Support Vite bundler better
Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
I'm attempting to use this package with Vite to bundle a React Native Web project. On doing so, it's been quite a challenge to use the .js files with .jsx syntax, as Vite likes the throw the following errors:
vite v4.0.4 building for production...
✓ 152 modules transformed.
[commonjs--resolver] Unexpected token (91:8) in C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/react-native-vector-icons/lib/create-icon-set.js
file: C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/react-native-vector-icons/lib/create-icon-set.js:91:8
89:
90: return (
91: <Text selectable={false} {...props}>
^
92: {glyph}
93: {children}
error during build:
SyntaxError: Unexpected token (91:8) in C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/react-native-vector-icons/lib/create-icon-set.js
at Object.pp$4.raise (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:20310:13)
at Object.pp$9.unexpected (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:17611:8)
at Object.pp$5.parseExprAtom (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19694:10)
at Object.pp$5.parseExprSubscripts (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19486:19)
at Object.pp$5.parseMaybeUnary (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19452:17)
at Object.pp$5.parseExprOps (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19379:19)
at Object.pp$5.parseMaybeConditional (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19362:19)
at Object.pp$5.parseMaybeAssign (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19329:19)
at Object.pp$5.parseParenAndDistinguishExpression (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19790:28)
at Object.pp$5.parseExprAtom (file:///C:/Users/crutchcorn/git/Etc/react-native-monorepo-example/apps/vite-react-app/node_modules/rollup/dist/es/shared/rollup.js:19653:41)
Describe the solution you'd like A clear and concise description of what you want to happen.
While there might be a way to migrate around this, I've spent some time with it and haven't made much headway. The official Vite team themselves suggests moving .js files to .jsx to side-step detection frustrations in doing this.
Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.
I could use patch-package, and likely may do this in the interim, but this wouldn't be much help in the long run.
Additional context Add any other context or screenshots about the feature request here.
I'm happy to make a PR renaming files to .jsx and fixing any related packaging errors that might arise from this.
Actually I figure it out without need to change the file extension. This happens because react-native-vector-icons contains jsx code (e.g. <Text>) inside .js file.
First, I need to add files with .web to the extensions (the order of the item in the array actually matters):
const extensions = [
'.mjs',
'.web.tsx',
'.tsx',
'.web.ts',
'.ts',
'.web.jsx',
'.jsx',
'.web.js',
'.js',
'.css',
'.json',
];
Add these extensions to resolve:
export default defineConfig({
...
resolve: {
extensions,
...
Then inside defineConfig, I added to optimizeDeps to resolve js files using jsx loader:
optimizeDeps: {
esbuildOptions: {
resolveExtensions: extensions,
jsx: "automatic",
loader: { ".js": "jsx" },
},
},
When I serve up the web app, I will get this error message:
MaterialCommunityIcon.tsx:49 Error: Dynamic require of "react-native-vector-icons/MaterialCommunityIcons" is not supported
So my web app's index.html, I need to add:
<style type="text/css">
@font-face {
font-family: 'MaterialCommunityIcons';
src: url('/MaterialCommunityIcons.ttf') format('truetype');
}
</style>
Now the serve command is working. However, the build command still does not work with the same error.
I created a rollup plugin:
const rollupPlugin = (matchers: RegExp[]) => ({
name: 'js-in-jsx',
load(id: string) {
if (
matchers.some((matcher) => matcher.test(id)) &&
id.endsWith('.js')
) {
const file = readFileSync(id, { encoding: 'utf-8' });
return esbuild.transformSync(file, { loader: 'jsx', jsx: 'automatic' });
}
},
});
Then add this plugin to the vite config:
build: {
rollupOptions: {
plugins: [rollupPlugin([/react-native-vector-icons/])],
},
},
Now build command should work.
Another issue I notice: In the web browser, I got this error:
NavigationContainer.tsx:29 Uncaught ReferenceError: global is not defined
In vite.config.ts, add:
define: {
global: "window",
},
The final vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import * as esbuild from 'esbuild';
import { readFileSync } from 'fs';
const extensions = [
'.mjs',
'.web.tsx',
'.tsx',
'.web.ts',
'.ts',
'.web.jsx',
'.jsx',
'.web.js',
'.js',
'.css',
'.json',
];
const rollupPlugin = (matchers: RegExp[]) => ({
name: 'js-in-jsx',
load(id: string) {
if (matchers.some((matcher) => matcher.test(id)) && id.endsWith('.js')) {
const file = readFileSync(id, { encoding: 'utf-8' });
return esbuild.transformSync(file, { loader: 'jsx', jsx: 'automatic' });
}
},
});
export default defineConfig({
cacheDir: '../../node_modules/.vite/techy-jokes-web',
define: {
global: 'window',
},
resolve: {
extensions,
alias: {
'react-native': 'react-native-web',
},
},
build: {
rollupOptions: {
plugins: [rollupPlugin([/react-native-vector-icons/])],
},
},
server: {
port: 4200,
host: 'localhost',
},
preview: {
port: 4300,
host: 'localhost',
},
optimizeDeps: {
esbuildOptions: {
resolveExtensions: extensions,
jsx: 'automatic',
loader: { '.js': 'jsx' },
},
},
plugins: [react()],
test: {
globals: true,
cache: { dir: '../../node_modules/.vitest' },
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
Dude I love you! thanks for this!
I'm not familiar with vite, is there anything we could do in our library to make this more seamless? Would simply renaming js to hsx solve the issue?
Indeed @johnf - I could even test any alpha releases against our production Vite setup and would be happy to make a PR to do so
Thanks a ton for the config, this was super helpful!
If anyone faces this same issue with expo vector icons (which is built on top of react-native-vector-icons), you can get the above config working with minimal changes:
- Update build to use the rollupPlugin for the expo package as well, and transform mixed ES modules (to fix a 'require is not defined' error that occurs post build).
build: {
commonjsOptions: { transformMixedEsModules: true },
rollupOptions: {
plugins: [
rollupPlugin([/react-native-vector-icons/, /@expo\/vector-icons/]),
],
},
},