-
Notifications
You must be signed in to change notification settings - Fork 164
Migrate your Remix app to Vite
To improve and extend Remix's bundling capabilities, Vite has been added to Remix as an alternative bundler. In the future, Vite will become the default bundler for Remix.
Beginning in late February 2024, Shopify CLI uses Vite in its Remix app template, and all new apps now use Vite by default.
If you have a Remix app and want to migrate to Vite, then you can follow the instructions in this page.
Your app was created before February 21, 2024.
Any new apps created after that date already use Vite.
To use Vite in your app, you need to add some additional dependencies, and update some Remix dependencies.
-
Run one of the following commands to install the dependencies for Vite:
npm
npm add --save-dev vite npm add vite-tsconfig-paths
yarn
yarn add --dev vite yarn add vite-tsconfig-paths
pnpm
pnpm add --save-dev vite pnpm add vite-tsconfig-paths
-
Make sure that all of your
@remix-run
dependencies are at least2.7.0
, and set thetype
setting tomodule
so it works with"moduleResolution": "Bundler"
:/package.json
"dependencies": { - "@remix-run/dev": "^2.0.0", - "@remix-run/node": "^2.0.0", - "@remix-run/react": "^2.0.0", - "@remix-run/serve": "^2.0.0", + "@remix-run/dev": "^2.7.0", + "@remix-run/node": "^2.7.0", + "@remix-run/react": "^2.7.0", + "@remix-run/serve": "^2.7.0", }, "devDependencies": { - "@remix-run/eslint-config": "^2.0.0", + "@remix-run/eslint-config": "^2.7.0", },
Because the app now runs on Vite scripts, you need to update the scripts that are used to run or build your app.
-
Update your script aliases in
package.json
:"scripts": { - "build": "tsc && remix build", - "start": "remix-serve build/index.js", + "build": "vite build && vite build --ssr", + "start": "remix-serve ./build/server/index.js", },
-
Shopify CLI runs the
dev
script, so you need to update it inshopify.web.toml
:[commands] - dev = "npx prisma generate && npx prisma migrate deploy && npm exec remix dev" + dev = "npx prisma generate && npx prisma migrate deploy && npm exec remix vite:dev" - [hmr_server] - http_paths = ["/ping"]
When using Vite, the way you can set Remix configurations differs slightly.
-
Remix no longer uses its own configuration file, so you need to delete
remix.config.js
, and add a newvite.config.[ts|js]
file.This file will use the Vite plugin for Remix, and set your server up so that Hot Module Replacement (HMR) will work when running the app using Shopify CLI.
TypeScript (
/vite.config.ts
)import { vitePlugin as remix } from "@remix-run/dev"; import { defineConfig, type UserConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; if ( process.env.HOST && (!process.env.SHOPIFY_APP_URL || process.env.SHOPIFY_APP_URL === process.env.HOST) ) { process.env.SHOPIFY_APP_URL = process.env.HOST; delete process.env.HOST; } const host = new URL(process.env.SHOPIFY_APP_URL || "http://localhost") .hostname; let hmrConfig; if (host === "localhost") { hmrConfig = { protocol: "ws", host: "localhost", port: 64999, clientPort: 64999, }; } else { hmrConfig = { protocol: "wss", host: host, port: parseInt(process.env.FRONTEND_PORT!) || 8002, clientPort: 443, }; } export default defineConfig({ server: { port: Number(process.env.PORT || 3000), hmr: hmrConfig, fs: { // See https://vitejs.dev/config/server-options.html#server-fs-allow for more information allow: ["app", "node_modules"], }, }, plugins: [ remix({ ignoredRouteFiles: ["**/.*"], }), tsconfigPaths(), ], build: { assetsInlineLimit: 0, }, }) satisfies UserConfig;
JavaScript (
/vite.config.js
)import { vitePlugin as remix } from "@remix-run/dev"; import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; if ( process.env.HOST && (!process.env.SHOPIFY_APP_URL || process.env.SHOPIFY_APP_URL === process.env.HOST) ) { process.env.SHOPIFY_APP_URL = process.env.HOST; delete process.env.HOST; } const host = new URL(process.env.SHOPIFY_APP_URL || "http://localhost") .hostname; let hmrConfig; if (host === "localhost") { hmrConfig = { protocol: "ws", host: "localhost", port: 64999, clientPort: 64999, }; } else { hmrConfig = { protocol: "wss", host: host, port: parseInt(process.env.FRONTEND_PORT!) || 8002, clientPort: 443, }; } export default defineConfig({ server: { port: Number(process.env.PORT || 3000), hmr: hmrConfig, fs: { // See https://vitejs.dev/config/server-options.html#server-fs-allow for more information allow: ["app", "node_modules"], }, }, plugins: [ remix({ ignoredRouteFiles: ["**/.*"], }), tsconfigPaths(), ], build: { assetsInlineLimit: 0, }, });
Tip
If you're not using TypeScript, you can skip steps 2 and 3.
-
Configure the appropriate TypeScript types. To do that, create a new file called
env.d.ts
, with the following contents:/// <reference types="vite/client" /> /// <reference types="@remix-run/node" />
-
Update your
tsconfig.json
file to include the correct libraries and module settings:- "include": ["**/*.[ts|js]", "**/*.[tsx|jsx]"], + "include": ["env.d.ts", "**/*.ts", "**/*.tsx"], "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2019"], - "module": "Node16", - "moduleResolution": "Node16", - "target": "ES2019", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "module": "ESNext", + "moduleResolution": "Bundler", + "target": "ES2022", }
After your app is fully configured, you can start updating your routes.
The main changes are that the <LiveReload />
component is no longer required, and you can import CSS files directly as modules, instead of using the links
export.
-
Remove
<LiveReload />
from/app/root.[tsx|jsx]
:import { - LiveReload, Scripts, } from "@remix-run/react"; export default function App() { return ( <html> <body> - <LiveReload /> <Scripts /> </body> </html> ); }
-
Only use the
links
export in your routes when you're importing global CSS, and add the?url
flag when usinglinks
. Use CSS module imports for app-specific CSS files.The following exports were included in previous versions of the template. You might need to remove exports from other routes in your app.
/app/routes/_index/route.[tsx|jsx]
:- import indexStyles from "./style.css"; + import "./styles.css"; - export const links = () => [{ rel: "stylesheet", href: indexStyles }];
/app/routes/app.[tsx|jsx]
:- import polarisStyles from "@shopify/polaris/build/esm/styles.css"; + import polarisStyles from "@shopify/polaris/build/esm/styles.css?url"; export const links = () => [{ rel: "stylesheet", href: polarisStyles }];
/app/routes/auth.login/route.[tsx|jsx]
:- import polarisStyles from "@shopify/polaris/build/esm/styles.css"; + import polarisStyles from "@shopify/polaris/build/esm/styles.css?url"; export const links = () => [{ rel: "stylesheet", href: polarisStyles }];
-
Because the app is using the
Bundler
moduleResolution
value, you can no longer userequire()
statements. Because of this, you need to update the import for Polaris translations in/app/routes/auth.login/route.[tsx|jsx]
.+ import polarisTranslations from "@shopify/polaris/locales/en.json"; export const loader = async ({ request }: LoaderFunctionArgs) => { - return json({ - errors, - polarisTranslations: require(`@shopify/polaris/locales/en.json`), - }); + return json({ errors, polarisTranslations }); };
This tutorial covers the steps required to migrate an app that has not been modified from the original Remix template to Vite. Depending on your app's features and functionality, you might need to make additional changes to complete the migration. Review the Remix migration instructions to understand whether there are other changes that you need to make.
After making all of the changes, you should be able to run or build your app as before.