8

Vite does not allow usage of JSX syntax within .js files by default.

I have already renamed my files to .jsx (or .tsx), but I have external dependencies that I cannot rename.

Example error from Vite:

✘ [ERROR] The JSX syntax extension is not currently enabled

    node_modules/somelib/src/someFile.js:122:11:
      122 │     return <div/>

How can I configure Vite to support JSX expressions in all .js files?

Soof Golan
  • 1,090
  • 2
  • 9
  • 13

3 Answers3

7

You can change esbuild configuration to treat all js files as jsx with the loader option:

// vite.config.ts
import {defineConfig} from 'vite'

// https://vitejs.dev/config/
export default defineConfig(() => ({
  esbuild: {
    loader: "tsx", // OR "jsx"
    include: [
      // Add this for business-as-usual behaviour for .jsx and .tsx files
      "src/**/*.jsx",
      "src/**/*.tsx",
      "node_modules/**/*.jsx",
      "node_modules/**/*.tsx",

      // Add the specific files you want to allow JSX syntax in
      "src/LocalJsxInJsComponent.js",
      "node_modules/bad-jsx-in-js-component/index.js",
      "node_modules/bad-jsx-in-js-component/js/BadJSXinJS.js",
      "node_modules/bad-jsx-in-js-component/ts/index.ts",
      "node_modules/bad-jsx-in-js-component/ts/BadTSXinTS.ts",

      // --- OR ---

      // Add these lines to allow all .js files to contain JSX
      "src/**/*.js",
      "node_modules/**/*.js",

      // Add these lines to allow all .ts files to contain JSX
      "src/**/*.ts",
      "node_modules/**/*.ts",
    ],
  },
}));

Note: there is a performance penalty for loading .js files with the .jsx loader.

Answer taken from this discussion in Vite's GitHub, Which marks the incorrect (and older) answer as the "correct" one.

Update March 2023

The original answer did not work correctly for vite build, only for vite dev. The current version works for both with vite@^4.0.0

Here is an example repo you can clone and test the solution.

Soof Golan
  • 1,090
  • 2
  • 9
  • 13
3

The vite.config.js below makes Vite/Vitest treat *.js files as JSX to avoid errors like:

Error: Failed to parse source for import analysis because the content contains invalid JS syntax. If you are using JSX, make sure to name the file with the .jsx or .tsx extension.

vite.config.js

import { defineConfig, transformWithEsbuild } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    {
      name: 'treat-js-files-as-jsx',
      async transform(code, id) {
        if (!id.match(/src\/.*\.js$/))  return null

        // Use the exposed transform from vite, instead of directly
        // transforming with esbuild
        return transformWithEsbuild(code, id, {
          loader: 'jsx',
          jsx: 'automatic',
        })
      },
    },
    react(),
  ],

  optimizeDeps: {
    force: true,
    esbuildOptions: {
      loader: {
        '.js': 'jsx',
      },
    },
  },
})
Maksim Shamihulau
  • 1,219
  • 1
  • 15
  • 17
  • 1
    The accepted answer = https://stackoverflow.com/a/74620428/4200446 didn't work for me. However this solution worked. In my case, I needed to use "tsx", not "jsx". – Cristian Jul 25 '23 at 08:31
2

I wasn't able to get the config in this answer to work as-is. I needed to add include and exclude keys to the esbuild config for some reason.

Building on this comment on the Vite discussion board, I was able to get this config file working for both vite serve and vite build. (Well, "working" as in not complaining about JSX in .js files anymore. Vite is still complaining about some CJS modules...)

// vite.config.js
import fs from "node:fs";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import * as esbuild from "esbuild";

const sourceJSPattern = /\/src\/.*\.js$/;
const rollupPlugin = (matchers) => ({
  name: "js-in-jsx",
  load(id) {
    if (matchers.some(matcher => matcher.test(id))) {
      const file = fs.readFileSync(id, { encoding: "utf-8" });
      return esbuild.transformSync(file, { loader: "jsx" });
    }
  }
});

export default defineConfig({
  plugins: [
    react()
  ],
  build: {
    rollupOptions: {
      plugins: [
        rollupPlugin([sourceJSPattern])
      ],
    },
    commonjsOptions: {
      transformMixedEsModules: true,
    },
  },
  optimizeDeps: {
    esbuildOptions: {
      loader: {
        ".js": "jsx",
      },
    },
  },
  esbuild: {
    loader: "jsx",
    include: [sourceJSPattern],
    exclude: [],
  },
});
jdunning
  • 1,356
  • 1
  • 14
  • 26