Soof Golan
Soof Golan

Reputation: 1520

How to configure Vite to allow JSX syntax in JS files?

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?

Upvotes: 30

Views: 57426

Answers (6)

Maksim Shamihulau
Maksim Shamihulau

Reputation: 1698

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',
      },
    },
  },
})

And don't forget to run npm i @vitejs/plugin-react.

Upvotes: 26

Rubel Hossain
Rubel Hossain

Reputation: 2723

simply just updated the vite.config.js file, added allow file types in react plugin.

export default defineConfig({ plugins: [react({ include: /\.(mdx|js|jsx|ts|tsx)$/ })], });

Upvotes: 0

Ravi Dubey
Ravi Dubey

Reputation: 11

Thanks to - @Maksim Shamihulau This answer worked for me for latest versions of Vite & React and used Tailwind Css also and it started working https://stackoverflow.com/a/76726872/23205457 :-

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',
      },
    },
  },
})

Upvotes: 1

Drikus Roor
Drikus Roor

Reputation: 1105

I had the same problem when migrating from CRA to Vite. Based on the example in this comment on Github I was able to treat all .js files as jsx:

vite.config.ts

export default defineConfig({

  // rest of configuration

  esbuild: {
    include: /\.js$/,
    exclude: [],
    loader: 'jsx',
  },
})

If you want to treat all combinations of .js, .jsx, .ts, and .tsx files as jsx, you might want to use the following include pattern:

esbuild: {
  include: /\.[jt]sx?$/,
  exclude: [],
  loader: 'jsx',
},

Upvotes: 10

Soof Golan
Soof Golan

Reputation: 1520

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.

Update November 2023

Vite 5.0 was released, this might not be relevant anymore, edits + corrections welcome.

Upvotes: 13

jdunning
jdunning

Reputation: 1716

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: [],
  },
});

Upvotes: 4

Related Questions