很快地帮你把旧项目快速从webpack迁移至vite

4,358 阅读5分钟

为什么改用vite

可能是我闲着。

能不动就不动吧,折腾啊,你看看vite的issue数量那么多。

旧项目慢的话,不如换个新macbook pro吧,质的改变。不仅“webpack项目”启动变快,而且“vite项目”启动还会更快!

我的依赖

  • @vitejs/plugin-legacy。浏览器兼容性处理
  • @vitejs/plugin-react。集合插件,相当于react插件的preset
  • vite-plugin-inspect。调试用,可忽略
  • postcss-flexbugs-fixes
  • postcss-preset-env
  • autoprefixer

后面3个主要是处理css,

const loder_presetEnv = postcssPresetEnv({
  autoprefixer: {
    flexbox: 'no-2009',
  },
  stage: 3,
});
// vite配置
{
    css: {
    modules: {
      scopeBehaviour: 'local',
    },
    postcss: {
      plugins: [autoprefixer, postcssFlexbugsFixes, loder_presetEnv],
    },
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
      },
      scss: {},
    },
  },
}

问题汇总

当时是直接抄的别人配置,后来发觉@vitejs/plugin-react可以解决很多事情,比如第七个问题

1.xxx does not provide an export named 'xxx'

比较常见错误。ts导出报错,要把import {xxx} from '...'改成 import type {xxx} from '...',多一个关键字“type”。

因为还有其他分支开发业务,每次合并可能处理type会有冲突,同时,文件太多了。决定撸个解决这个问题的插件,叫vite-plugin-transform-ts-import

快就快在用这个插件,解决这个问题。该插件可以自动帮你做加“type”这个处理,省心省力。

详情:www.npmjs.com/package/vit…

2.process 未定义

配置文件追加,这个也是常见的环境变量获取方式改造。

define: {
    'process.env': process.env,
  },

同时 package.json 里面原本的环境变量,提到vite关键字之前

"script": {
    "vite": "MY_ENV=dev vite",
}

也可以考虑import.meta.env,终端参数是mode,详情翻阅官方文档

3. 'ReferenceError: require is not defined'

可以去找github.com/vitejs/awes…

  1. 关键字是“require”的插件。有对应的插件,
  2. 也可以试试“vite-plugin-commonjs”。

第一点我都没有生效,还会报奇怪的错。就直接改成import。

但是下面这个写法,还不知道好的办法代替,就把所有环境配置放进来,不多。

const config: Config = require(`./${env}`).default
4. Uncaught TypeError: require.context is not a function

同上。 这个主要是用了webpack的require.context特性,获取当前文件。 我是直接用vite提供import特性解决

const modules = import.meta.globEager('./*.ts')
5.react 多次定义
<!--配置追加-->
esbuild: {
    jsxFactory: '_jsx',
    jsxFragment: '_jsxFragment',
    jsxInject: `import { createElement as _jsx, Fragment as _jsxFragment } from 'react'`,
  },

可能会碰到吧,改了其他commonjs插件或官方的react插件,之后不复现,当时并没有在意和记录

6.dev 模块导入问题
 error: [plugin: vite:dep-pre-bundle] Failed to resolve entry for package "child_process".


error when starting dev server:
Error: Build failed with 1 error:
xxxPaths/dep-36bf480c.js:43807:10: error: [plugin: vite:dep-pre-bundle] Failed to resolve entry for package "child_process". The package may have incorrect main/module/exports specified in its package.json: Failed to resolve entry for package "child_process". The package may have incorrect main/module/exports specified in its package.json.

原本可运行,用yarn装的依赖,装了几个依赖和复制几个代码进来后报错。

搜出github有类似报错,不过是Pnpm。怀疑是依赖问题。

无法定位是哪个依赖造成的问题。回滚一次可以运行,逐个安装排查。

石锤socket.io-client的问题,但是node_modules里面确实没有child_process

  1. 方法一 翻了一下node_modules, socket.io-client的出口文件是build/index.js里面用的是“require”,需要支持用插件支持,增加一下配置代码
import { viteCommonjs } from '@originjs/vite-plugin-commonjs'


export default defineConfig({
  plugins: [
    ...
    viteCommonjs({
      include: ['socket.io-client']
    }),
    ]
})
  1. 方法二 但是重启vite后又不行了,最后解决办法,在issue里面翻到了,加配置
resolve: {
    alias: [
      {find: 'socket.io-client', replacement: 'socket.io-client/dist/socket.io.js',},
    ]
}

可以考虑用CDN链接注入script获取

7.构建时候相对路径报错
Could not resolve './typings' from xxx.tsx

好像这个rollup算是问题,使用了@rollup/plugin-node-resolve 尝试解决。

最后发现是“d.ts”后缀的文件,可以看浏览器的network,vite并不能请求到这种后缀的文件。批量改就行了。

build不通的文件,应该尝试跳到那个页面去看看。这里问题是有漏网的“d.ts”文件,改成“.ts”就行了

8. 无法解析class预发

最后这两个是插件碰到的问题。

[vite] Internal server error: This experimental syntax requires enabling the parser plugin: 'classProperties' 

这事解析出错,自定义插件的babel也要装babel插件。

自定义的插件里面也要补充

module.exports = {
  plugins: ['@babel/plugin-syntax-class-properties'],
}

9 node_moduels里面的模块无法导入
'getAugmentedNamespace' is not exported by commonjsHelpers.js, imported by /xxx/node_modules/rc-field-form/es/index.js?commonjs-proxy

应该是和其他插件有了冲突? 这些奇奇怪怪问题,给插件做了关键字过滤,传入对应文件名不作处理。

插件编写

vite-plugin-transform-ts-import:写的很粗糙,但也能用在这个文件众多的项目跑,毕竟改几百个 import 代码更加累,而且还要合并其他业务分支。

vite插件也如同rollup插件,不过多一些特定钩子。需要注意的是各个插件和各个钩子之间的顺序。可以看看别人的插件,可以比较简陋地解决一些问题。

原理

在bable的ast中,

import {RenderBtnProps} from 'src/typings'

这一句的ts声明导入,它的节点 importKind 是“value”,而esbuild 辨识的是 “type”。 所以插件原理是,通过babel分析src里当前使用的文件,存储所有ts的声明,如果import的变量名是存储空间中的ts,加个type进去。

所以,依赖包里面的ts声明要手动输入给插件记录,或者自己改成import type

包括自动处理这些情况

export {ShowProductIdListProps} from './productIdListTyping'

export default from './couponTypeing'

export {default as RenderProductIdsBySelect} from './renderProductIdsBySelectTyping'

官方调试插件

叫这个:vite-plugin-inspect,启动然后打开 https://xxxx/__inspect,

可以看到每个插件处理的结果,就相当于webpack的各个Loader,点进去方便查阅自己的插件编译结果,每个文件都可以看到转换的前后对比。

同时还会记录每个插件的耗时,显示我的插件顶多也是几百ms,不大影响vite的速度优势。

帮转小广告

珠海金山办公,诚招各岗位开发和产品,包餐、海景办公等福利,自己翻招聘软件咯。

内推极有机会绕过学历(重点大学本科or研究生之类)要求,联系方式:610038187@qq.com