Skip to main content

Migrating from Helium 2.x to 3.0

This guide provides detailed step-by-step instructions for migrating your Helium application from version 2.x to 3.0.

Overview

Helium 3.0 represents a significant modernization of the framework, primarily focused on updating the build tooling and SSR framework from vite-plugin-ssr to vike, along with dependency updates for security and performance.

What Changed and Why

1. vite-plugin-ssr → Vike Migration

  • What: The SSR framework was renamed from vite-plugin-ssr to vike
  • Why: Official rebrand by the maintainer, improved API, better documentation
  • Impact: Import statements and some configuration patterns changed

2. Vite 3 → Vite 5

  • What: Build tool upgraded from Vite 3.x to Vite 5.x
  • Why: Performance improvements, security fixes, future compatibility
  • Impact: Faster builds, improved developer experience

3. Dependency Updates

  • Storybook: v7 → v8.6.14 (component development)
  • i18next: v21 → v23.16.8 (internationalization)
  • react-i18next: v11 → v13.5.0 (React i18n bindings)
  • GraphQL: 16.6.0 → 16.11.0 (security fixes)
  • Why: Security vulnerabilities, deprecated APIs, performance improvements

4. Enhanced Configuration Management

  • What: Vite configuration expanded and improved in helium-server package
  • Why: Added critical build settings (manifest, ssr.noExternal, resolve.dedupe) and factory function pattern
  • Impact: More comprehensive base config, prevents misconfiguration

Prerequisites

Before starting the migration:

  • Backup your project: Create a git branch or backup
  • Node.js 18.20.7: REQUIRED - Helium 3.0 requires Node.js 18.20.7 (check with node -v)
  • npm 8.19.2+: npm 8.19.2 or higher (check with npm -v)
  • Clean git state: Commit or stash any pending changes
  • Working 2.x app: Ensure your current app builds and runs successfully

⚠️ Important: Node.js 18.20.7 is required for Helium 3.0 (Vike and Vite 5 both require Node 18+). Helium 2.7 and earlier required Node.js 16.18.1 or higher. You must upgrade to Node 18.20.7 before migrating to 3.0.

Migration Steps

Step 1: Update Dependencies

1.1 Update package.json

Update your package.json dependencies to use 3.x versions:

{
"dependencies": {
// Core Helium packages - update to 3.x
"@thoughtindustries/helium-server": "^3.0.0",

// Component packages - update to 2.x (if using)
"@thoughtindustries/catalog": "^2.0.0",
"@thoughtindustries/content": "^2.0.0",
"@thoughtindustries/user": "^2.0.0",
"@thoughtindustries/cart": "^2.0.0",
"@thoughtindustries/featured-content": "^2.0.0",
"@thoughtindustries/dashboard-stats": "^2.0.0",

// Build tools
"vike": "0.4.195", // Changed from vite-plugin-ssr
"vite": "^5.4.11", // Upgraded from 3.x/4.x

// Updated dependencies
"i18next": "^23.16.8",
"react-i18next": "^13.5.0",
"graphql": "^16.11.0"
},
"devDependencies": {
"@mdx-js/rollup": "^2.1.3",
"tsup": "^8.5.0"
}
}

1.2 Remove old dependencies

Remove vite-plugin-ssr if it's explicitly listed:

npm uninstall vite-plugin-ssr

1.3 Install new dependencies

# Clean install to avoid conflicts
rm -rf node_modules package-lock.json
npm install

Step 2: Add Required Build Scripts

Helium 3.0 requires additional build scripts for manifest generation. These scripts ensure proper deployment to Cloudflare Workers.

2.1 Download the scripts from the template package

# Download the template package
npm pack @thoughtindustries/helium-template@latest

# Extract the scripts folder
tar -xzf thoughtindustries-helium-template-*.tgz package/scripts

# Move scripts to your project root
mv package/scripts ./scripts

# Clean up
rm -rf package thoughtindustries-helium-template-*.tgz

2.2 Update your build:vite script

In your package.json, update the build:vite script to include manifest generation:

Before:

"build:vite": "vite build",

After:

"build:vite": "vite build && node scripts/generate-manifest.js && node scripts/generate-asset-tags.js",

2.3 Verify the scripts folder

Your project should now have:

your-project/
├── scripts/
│ ├── generate-manifest.js
│ └── generate-asset-tags.js
├── package.json
└── ...

Why is this needed?

  • generate-manifest.js creates dist/client/manifest.json required by the deployment process
  • generate-asset-tags.js creates dist/asset-tags.json for asset loading
  • Without these, deployment will fail with missing manifest errors

Step 3: Update Import Statements

3.1 Update vite-plugin-ssr imports to vike

Find and replace all occurrences in your codebase:

In renderer/_default.page.server.tsx:

- import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr/server';
+ import { escapeInject, dangerouslySkipEscape } from 'vike/server';

In vite.config.ts (if you have custom config):

- import ssr from 'vite-plugin-ssr/plugin';
+ import vike from 'vike/plugin';

- plugins: [react(), ssr()]
+ plugins: [react(), vike()]

Step 4: Update Vite Configuration

4.1 Simplify vite.config.ts

Old 2.x approach:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import ssr from 'vite-plugin-ssr/plugin';

export default defineConfig({
plugins: [react(), ssr()],
build: {
manifest: true
},
optimizeDeps: {
include: ['dayjs', 'universal-cookie']
},
envPrefix: 'HELIUM_PUBLIC_',
ssr: {
noExternal: ['@apollo/client', 'graphql', 'use-debounce']
},
resolve: {
dedupe: ['@apollo/client']
}
});

New 3.x approach:

import { createVikeConfig } from '@thoughtindustries/helium-server';
import { defineConfig } from 'vite';

export default defineConfig(async () => {
// Get base config with all critical settings included
const config = await createVikeConfig();

// Add any custom configuration here if needed
// For example, custom aliases, additional plugins, etc.

return config;
});

Key Benefits:

  • ✅ Critical settings (manifest, envPrefix, ssr.noExternal, resolve.dedupe) are now centralized
  • ✅ Can't accidentally break production deployment settings
  • ✅ Much simpler configuration - just call the factory function
  • ✅ ESM/CJS compatibility handled automatically
  • ✅ All necessary plugins already included (React, Vike, MDX support)

Step 5: Update Environment Variables

The envPrefix is now centralized in helium-server. Ensure your environment variables use the HELIUM_PUBLIC_ prefix:

Environment variables that should be exposed to the browser:

HELIUM_PUBLIC_API_KEY=your-key
HELIUM_PUBLIC_FEATURE_FLAG=true

Variables without the prefix are server-only:

HELIUM_ENDPOINT=https://your-instance.thoughtindustries.com/helium/api/graphql

Step 6: Update passToClient (Optional New Fields)

Two new optional fields have been added to passToClient in 3.0:

In renderer/_default.page.server.tsx:

export const passToClient = [
'pageProps',
'urlParsed', // REQUIRED for Server Routing
'urlPathname', // REQUIRED for Server Routing
'apolloInitialState',
'heliumEndpoint',
'appearance',
'documentProps',
'currentUser',
'isProduction',
'queryParams',
'authToken',
'routeParams', // NEW: For dynamic routes like @courseSlug
'assetUrls' // NEW: For asset references
];

Note:

  • urlParsed and urlPathname were already in 2.x templates - no changes needed
  • Only add routeParams if you use dynamic routes (e.g., @courseSlug.page.tsx)
  • Only add assetUrls if you're using the latest template-base structure
  • If you started from template-base, these are likely already present

Step 7: Client Routing Configuration (if applicable)

If you're using Client Routing (can be enabled by uncommenting the export below), the passToClient array remains the same as for Server Routing. The only difference is that urlParsed and urlPathname are optional in Client Routing (these values are automatically available), but you can still include them in the array without issues.

To enable Client Routing in renderer/_default.page.client.tsx:

// Uncomment this line to enable Client Routing:
export const clientRouting = true;

// To use Server Routing (default), keep it commented out:
// export const clientRouting = true;

Note: Most applications use Server Routing (the default). Only enable Client Routing if you want instant page transitions without full page reloads.

Step 8: Clean Build and Test

8.1 Clean previous builds

rm -rf dist node_modules package-lock.json
npm install

8.2 Test local development

npm run dev

Visit http://localhost:3000 and verify:

  • Pages load correctly
  • Navigation works
  • GraphQL queries return data
  • No console errors
  • Translations load properly

8.3 Test production build

npm run build

Verify the build completes without errors and check:

  • dist/client/ folder exists with assets
  • dist/server/ folder exists with SSR code
  • dist/client/manifest.json exists
  • dist/asset-tags.json exists

Step 9: Deploy and Test

9.1 Deploy to a sandbox/staging environment first

npm run deploy sandbox

9.2 Verify deployment

  • Deployment completes without errors
  • Visit your staging instance
  • Test all custom pages
  • Test navigation between pages
  • Check browser console for errors
  • Verify GraphQL queries work

9.3 Deploy to production (when ready)

npm run deploy production

Common Migration Issues

Issue 1: Import errors for vite-plugin-ssr

Error:

Cannot find module 'vite-plugin-ssr/server'

Solution: Replace all vite-plugin-ssr imports with vike:

# Find all occurrences
grep -r "vite-plugin-ssr" . --exclude-dir=node_modules

# Replace (use your editor's find/replace)
vite-plugin-ssr → vike

Issue 2: Build fails with "vike not found"

Error:

Failed to load vike plugin

Solution:

npm install [email protected]

Issue 3: TypeScript errors

Error:

Cannot find type definitions for 'vike'

Solution: Vike includes its own TypeScript definitions. Ensure you're using vike 0.4.195 or higher.

Issue 4: ESM/CJS compatibility errors

Error:

ERR_REQUIRE_ESM: require() of ES Module not supported

Solution: This should be automatically handled by the new createVikeConfig() function. If you still see this:

  1. Ensure you're using createVikeConfig() in your vite.config.ts
  2. Rebuild helium-server: cd node_modules/@thoughtindustries/helium-server && npm run build
  3. Or reinstall: rm -rf node_modules && npm install

Issue 5: Deployment fails

Error: Deployment logs show errors or deployment completes but pages don't load

Solution:

  1. Ensure you're using helium-server 3.0.0 or higher:
npm install @thoughtindustries/helium-server@latest
  1. Verify your build completed successfully
  2. Check deployment logs for specific error messages
  3. Contact TI support with deployment logs if issues persist

Issue 6: Pages show /not-found after deployment

Possible Causes:

  1. Manifest not generated correctly
  2. Build artifacts missing
  3. Deployment error occurred

Solutions:

  1. Verify build output includes dist/client/manifest.json and dist/asset-tags.json
  2. Check the deployment logs for any errors
  3. Ensure your build completed successfully before deploying
  4. Try rebuilding and redeploying

Issue 7: Missing manifest.json or deployment fails

Error:

Missing dist/client/manifest.json

or deployment logs show manifest-related errors.

Cause: The scripts/ folder is missing from your project, or the build:vite command isn't calling the manifest generation scripts.

Solution: Follow Step 2: Add Required Build Scripts to add the scripts folder and update your build command:

# Add scripts folder
npm pack @thoughtindustries/helium-template@latest
tar -xzf thoughtindustries-helium-template-*.tgz package/scripts
mv package/scripts ./scripts
rm -rf package thoughtindustries-helium-template-*.tgz

Then update package.json:

"build:vite": "vite build && node scripts/generate-manifest.js && node scripts/generate-asset-tags.js"

Breaking Changes Summary

Required Changes

  1. Update imports: vite-plugin-ssrvike
  2. Add build scripts: Copy scripts/ folder and update build:vite command
  3. Update vite.config.ts: Use createVikeConfig() from helium-server
  4. Update dependencies: Install vike, update Vite to 5.x
  1. passToClient: Ensure urlParsed and urlPathname are present for Server Routing (Should already be present in default 2.x applications)
  2. Environment variables: Use HELIUM_PUBLIC_ prefix for client-exposed vars
  3. Clean install: Remove node_modules and package-lock.json before installing

Non-Breaking (Automatic)

  1. Apollo Client: Automatic cleanup implemented (prevents memory leaks)
  2. Performance optimization: Improved caching and resource management
  3. Configuration: Enhanced base settings automatically applied from helium-server

Verification Checklist

After migration, verify these items:

  • All imports updated from vite-plugin-ssr to vike
  • scripts/ folder added with generate-manifest.js and generate-asset-tags.js
  • build:vite script updated to call manifest generation scripts
  • vite.config.ts uses createVikeConfig()
  • Dependencies updated in package.json
  • Clean npm install completed
  • Local dev server runs (npm run dev)
  • Production build succeeds (npm run build)
  • dist/client/manifest.json generated after build
  • dist/asset-tags.json generated after build
  • Deployment to staging succeeds
  • All pages load correctly in staging
  • Navigation works (both hard navigation and client-side)
  • GraphQL queries return data
  • No console errors in browser
  • Performance is acceptable
  • Deployment to production succeeds
  • Production instance works correctly

Rollback Plan

If you encounter critical issues during migration:

Quick Rollback

git checkout main  # or your previous stable branch
npm install
npm run build
npm run deploy [nickname]

Partial Rollback

If some features work but others don't, you can:

  1. Keep using 2.x temporarily
  2. Report issues to TI support
  3. Wait for hotfix releases

Getting Help

If you encounter issues during migration:

  1. Check the error message: Most errors include helpful diagnostics
  2. Review this guide: Ensure all steps were followed
  3. Check deployment logs: Review any errors from the deployment process
  4. Contact TI Support: Provide error messages and deployment logs
  5. GitHub Issues: Check Helium issues for known problems

Additional Resources

Timeline Recommendation

For a typical Helium application:

  • Small projects (1-3 custom pages): 1-2 hours
  • Medium projects (5-10 custom pages): 2-4 hours
  • Large projects (custom components, complex routing): 4-8 hours

Plan accordingly and test thoroughly in staging before deploying to production.


Last updated: January 2026 Helium version: 3.0.0