npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

plugin-auto-script-jsx

v1.0.0-beta.2

Published

auto set script lang='jsx' when you use jsx

Readme

plugin-auto-script-jsx

概述

当你从别的构建工具 (vue-cli, webpack...) 等切换到 vite,并且你的项目中有使用到 jsx 时,你会发现这样的错误日志:

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

    script:E:/Desktop/todo/个人项目/xzq-vite-plugins/playground/auto-script-jsx/vue2/src/containJsxVue/test2.vue?id=0:5:6:
      5 │       <div>
        ╵       ^

  The esbuild loader for this file is currently set to "js" but it must be set to "jsx" to be able
  to parse JSX syntax. You can use "loader: { '.js': 'jsx' }" to do that.

这是因为:

Vite 出于编译性能考虑,不会和其他的构建工具一样,对每个处理的 .js 等文件进行完整的 AST 处理,以防万一它包含 JSX

它只会针对有对应的 .jsx 扩展名(如果是 .vue 文件, 只需要 <script lang="jsx"></script>)的文件进行完整的 AST 转换。

这样 Vite 就能避免无谓的编译期间的开销。

因为在大多数情况下,普通的 .js 文件不需要完整的 AST 转换才能在浏览器中工作。

具体原因可以参考:Cannot use jsx syntax in js file.

这时你就需要手动针对每个包含 jsx 的文件手动更改文件后缀名或者添加lang="jsx",当你的文件数量太多时,那可太麻烦了。

此时你可以尝试此插件。

优缺点

优点

  • 自动给包含 jsx代码的 .vue 文件添加 lang="jsx"
  • 兼容 Vue2Vue3

缺点

  • 只支持 Vite
  • 只能给 .vue 文件添加 lang="jsx"

安装

Vite

npm i plugin-auto-script-jsx -D

pnpm add plugin-auto-script-jsx -D

yarn add vue-lazyload -D

vite.config.js

import { defineConfig } from 'vite';
import autoScriptJsxPlugin from 'plugin-auto-script-jsx';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [autoScriptJsxPlugin()],
});

使用案例

以下测试包含了 options apicomposition api 两种风格

相同的 .vue 模板文件

composition api

<script>
export default {
  setup() {
    const dom = <h2 id="contain-jsx-test1">contain-jsx-test1</h2>;
    return () => {
      return <div>{dom}</div>;
    };
  },
};
</script>

options api

<script>
export default {
  render() {
    return (
      <div>
        <h2 id="contain-jsx-test2">contain-jsx-test2</h2>
      </div>
    );
  },
};
</script>

Vue 2(非 2.7)

import { defineConfig } from 'vite';
import { createVuePlugin as vue2 } from 'vite-plugin-vue2';
import autoScriptJsxPlugin from 'plugin-auto-script-jsx';

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
  return {
    plugins: [
      vue2({
        jsx: true,
        jsxOptions: {
          // https://github.com/vuejs/jsx-vue2/tree/dev/packages/babel-preset-jsx#vuebabel-preset-jsx
          // Cannot read properties of undefined (reading '$createElement')
          compositionAPI: true,
        },
      }),
      autoScriptJsxPlugin({
        runTime: false,
      }),
      inspect(),
    ],
    resolve: {
      // 默认不支持 .vue 扩展名
      // 并非 bug, 而是 vite 设计就是如此: https://github.com/vitejs/vite/issues/178#issuecomment-630138450
      // 配置参考: https://vitejs.bootcss.com/config/#resolve-extensions
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
    },
  };
});

runTime: false 的情况下,会在编译时自动给包含 jsx代码的 .vue文件中的 <script> 标签添加 lang = 'jsx'

Vue 2.7

import { defineConfig } from 'vite';
import vue2Dot7 from '@vitejs/plugin-vue2';
import vue2Dot7Jsx from '@vitejs/plugin-vue2-jsx';
import autoScriptJsxPlugin from 'plugin-auto-script-jsx';

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
  return {
    plugins: [
      vue2Dot7(),
      vue2Dot7Jsx(),
      autoScriptJsxPlugin({
        runTime: true,
      }),
    ],
    resolve: {
      // 默认不支持 .vue 扩展名
      // 并非 bug, 而是 vite 设计就是如此: https://github.com/vitejs/vite/issues/178#issuecomment-630138450
      // 配置参考: https://vitejs.bootcss.com/config/#resolve-extensions
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
    },
  };
});

runTime: true 的情况下,会在运行时自动给内存中的包含 jsx代码的 .vue文件中的 <script> 标签添加 lang = 'jsx',注意,此时并不会修改真实的存储在硬盘上的文件。

Vue3

import { defineConfig } from 'vite';
import vue3 from '@vitejs/plugin-vue';
import vue3Jsx from '@vitejs/plugin-vue-jsx';
import autoScriptJsxPlugin from 'plugin-auto-script-jsx';

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
  return {
    plugins: [
      vue3(),
      vue3Jsx(),
      autoScriptJsxPlugin({
        // 不打印日志
        logEnabled: false,
      }),
    ],
    resolve: {
      // 默认不支持 .vue 扩展名
      // 并非 bug, 而是 vite 设计就是如此: https://github.com/vitejs/vite/issues/178#issuecomment-630138450
      // 配置参考: https://vitejs.bootcss.com/config/#resolve-extensions
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
    },
  };
});

配置项

以下显示配置的默认值:

autoScriptJsxPlugin({
  // 会打印出当前环境的 Vue 版本, 和对应的文件是否
  // containJsx: 该文件是否包含 jsx; scriptTagContainJsxLang: 该 .vue 文件是否在 script 标签上有 lang = 'jsx'
  logEnabled: true,
  // 默认采用的是在编译时修改文件的策略
  // 如果为 true, 那么就是在运行时对内存中的文件进行修改, 相比于编译时修改, runTime: true, 对用户的真实存储在硬盘中的文件不会有修改
  // 但是它的缺点是: 它需要先关闭依赖预构建, 不然在依赖预构建的扫描依赖的过程中 esbuild 就会因为 loader 配置错误而报错, 根本就走不到插件调用这里来
  runTime: false,
});

log info

> vite

[vite:vue-auto-script-jsx]   {
  VUE_VERSION: '2.7.8',
  isVue2: false,
  isVue2Dot7: true,
  isVue3: false
}
[vite:vue-auto-script-jsx]   parseSFC-Func:  [Function: parse]
[vite:vue-auto-script-jsx]   { containJsx: false, scriptTagContainJsxLang: false }
[vite:vue-auto-script-jsx]   { containJsx: true, scriptTagContainJsxLang: false }
[vite:vue-auto-script-jsx]   target:  E:/Desktop/todo/个人项目/xzq-vite-plugins/playground/auto-script-jsx/vue2.7/src/containJsxVue/test1.vue
[vite:vue-auto-script-jsx]   { containJsx: true, scriptTagContainJsxLang: false }
[vite:vue-auto-script-jsx]   target:  E:/Desktop/todo/个人项目/xzq-vite-plugins/playground/auto-script-jsx/vue2.7/src/containJsxVue/test2.vue
[vite:vue-auto-script-jsx]   { containJsx: false, scriptTagContainJsxLang: false }

警告

runTime: false 时,该插件会对硬盘上存储的真实文件进行修改,因此建议先通过 git 提交一下,保持工作区和暂存区的纯净,然后再运行此插件。

这样方便追踪此插件修改的文件。

runTime: true 时,它需要先关闭依赖预构建, 不然在依赖预构建的扫描依赖的过程中 esbuild 就会因为 loader 配置错误而报错, 根本就走不到插件调用这里来。

关闭依赖预构建带来的影响就是开发时速度变慢,而且还有可能出现不同的模块风格带来的兼容性问题。

参考: vite 依赖与构建。

bin

不建议使用,有风险,这是兜底方案,最好还是通过 git 查看记录进行还原。

当你选择 runTime: false 时, 会对硬盘上的实际文件进行修改,其实这个操作是有些危险的,这里我们提供的一个还原命令:

npx vue-auto-script-jsx --reset

原理是我们会将对文件进行修改的操作记录缓存起来,然后当你输入这个命令时,它会该插件将修改过的文件进行还原。

缓存文件

缓存文件的路径为:${projectRoot}/node_modules/.vue-auto-script-jsx/cache.json

存储的内容:

{ 文件路径: 文件修改的历史记录 }

这里可以发现,文件修改历史记录是一个数组,那么第一个就是原始文件内容。

{
  "xxx/test1.vue": [
    "<script>\nexport default {\n  setup() {\n    const dom = <h2 id=\"contain-jsx-test1\">contain-jsx-test1</h2>;\n    return () => {\n      return <div>{dom}</div>;\n    };\n  },\n};\n</script>\n",
    "<script lang=\"jsx\">\nexport default {\n  setup() {\n    const dom = <h2 id=\"contain-jsx-test1\">contain-jsx-test1</h2>;\n    return () => {\n      return <div>{dom}</div>;\n    };\n  },\n};\n</script>\n",
    "<script>\nexport default {\n  setup() {\n    const dom = <h2 id=\"contain-jsx-test1\">contain-jsx-test1</h2>;\n    return () => {\n      return <div>{dom}</div>;\n    };\n  },\n};\n</script>\n"
  ],
  "xxx/test2.vue": [
    "<script>\nexport default {\n  render() {\n    return (\n      <div>\n        <h2 id=\"contain-jsx-test2\">contain-jsx-test2</h2>\n      </div>\n    );\n  },\n};\n</script>\n",
    "<script lang=\"jsx\">\nexport default {\n  render() {\n    return (\n      <div>\n        <h2 id=\"contain-jsx-test2\">contain-jsx-test2</h2>\n      </div>\n    );\n  },\n};\n</script>\n",
    "<script>\nexport default {\n  render() {\n    return (\n      <div>\n        <h2 id=\"contain-jsx-test2\">contain-jsx-test2</h2>\n      </div>\n    );\n  },\n};\n</script>\n"
  ]
}

License

MIT License © 2022-PRESENT Mr-xzq