Webpack to Vite,项目实战踩坑记录

随着公司各个项目体积的增大,开发环境项目的构建常常能达到一分钟甚至更长,使用vite能快速帮助我们提升项目的构建速度,于是最近开始对公司的项目进行改造,同时为了节省时间成本,生产的环境的构建打算沿用原本webpack的那套配置,仅仅将开发环境由webpack转为vite。

一、安装vite相关依赖

"vite": "^2.7.13",
"vite-plugin-html": "^2.1.2",
"vite-plugin-vue2": "^1.9.3",

二、修改index.html的位置

将index.html移至根目录下,而非public中,并且在html中引入入口js文件

<script type="module" src="/src/main.ts"></script>

三、修改ts的配置文件

// tsconfig.json
{
  "compilerOptions": {
  	...
  	"types": [
      ...
      "vite/client"
    ],
  },
  ...
}

四、修改启动命令

使用npm run serve启动项目

"scripts": {
    "start": "npm run serve",
    "serve": "vite --port 8764",
    "build": "vue-cli-service build",
    "test:unit": "vue-cli-service test:unit",
    "lint": "vue-cli-service lint"
},

五、开发环境改为vite的报错修复

1. 别名@需要在vite.config.js重新配置
export default defineConfig({
  ...  
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  ...
})
2. ts装饰器在vite启动时报错vite error: Unexpected "@" @Component

原因:EcmaScript 还没有正式支持 JS 装饰器,导致没有明确地将它们的

解决方法:将 <script> 替换为 <script lang="ts">

3. require('script-loader!file-saver');报错

原因:ESBuild不支持commonjs,,vite中所有所以的commonjs语法必须转化成ESM

解决方法:将 require('script-loader!xlsx/dist/xlsx.core.min');替换为 new URL('script-loader!xlsx/dist/xlsx.core.min', import.meta.url).href;

类似var CryptoJS = require('crypto-js');这种也需要转成import CryptoJS from 'crypto-js';

4. less语法报错variable @primaryColor is undefined

原因:未在vite.config.js中注入less全局变量

解决方法:新增配置

export default defineConfig({
  ...  
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
        additionalData: `@import ${getLessVariables(
          resolve('src/assets/less/variable.less'),
        )}`,
      },
    },
  },
  ...
})
5. require.context报错

require.context改为import.meta.globEager

glob表达式的语法有不懂的可以在github上查找相关文档

// const _modules = require.context('./modules', true, /\.ts$/);
const _modules = import.meta.globEager('./modules/*.ts');
  • import.meta.glob: 通过动态导入默认懒加载,通过遍历加 then 方法可拿到对应的模块文件详情信息
  • import.meta.globEager: 直接引入所有的模块, 即静态 import
6. 在index.html中支持ejs语法

首先在vite.config.js中配置变量ENV

import { minifyHtml, injectHtml } from 'vite-plugin-html';

export default defineConfig({
    ...
    plugins: [
        createVuePlugin(),
        minifyHtml(),
        injectHtml({
            data: {
                ENV: 'develop',
            },
        }),
    ],
    ...
})

在html中文件使用变量做判断

<% if (ENV === 'develop') { %>
<script type="module" src="/src/main.ts"></script>
<% } %>

六、生产环境构建报错修复

在使用vite命令本地构建项目无误之后,尝试在本地使用npm run build构建生产环境的文件的时候出现了一些问题

1、与vite支持的语法冲突

解决方法:webpack引入相应loader,babel引入相应的plugins兼容vite语法

安装这两个依赖

// package.json
"@open-wc/webpack-import-meta-loader": "^0.4.7",
"babel-preset-vite": "^1.0.4",

分别在babel.config.js和vue.config.js中配置

// babel.config.js
module.exports = {
  presets: ['babel-preset-vite', ['@vue/app', { useBuiltIns: 'entry' }]],
};
// vue.config.js
module.exports = {
    ...
    chainWebpack: config => {
        const jsRule = config.module.rule('js');
        const tsRule = config.module.rule('ts');

        jsRule.uses.clear();
        tsRule.uses.clear();

        /**
         * @open-wc/webpack-import-meta-loader
         * Webpack loader for supporting `import.meta` in webpack.
         *
         * 在babel配置文件中使用babel-preset-vite兼容import.meta.globEager语法
         */
        jsRule
            .use(require.resolve('@open-wc/webpack-import-meta-loader'))
            .loader(require.resolve('@open-wc/webpack-import-meta-loader'))
            .end()
            .use('happypack/loader?id=babel')
            .loader('happypack/loader?id=babel')
            .end();

        // 处理ts文件
        tsRule
            .use(require.resolve('@open-wc/webpack-import-meta-loader'))
            .loader(require.resolve('@open-wc/webpack-import-meta-loader'))
            .end()
            .use('cache-loader')
            .loader('cache-loader')
            .options({
            cacheDirectory: resolve('node_modules/.cache/ts-loader'),
        })
            .end()
            .use('babel-loader')
            .loader('babel-loader')
            .end()
            .use('ts-loader')
            .loader('ts-loader')
            .options({
            transpileOnly: true, // 关闭类型检查,即只进行转译(类型检查交给webpack插件(fork-ts-checker-webpack-plugin)在另一个进程中进行,这就是所谓的多进程方案,如果设置transpileOnly为false, 则编译和类型检查全部由ts-loader来做, 这就是单进程方案.显然多进程方案速度更快)
            appendTsSuffixTo: ['\\.vue$'],
            happyPackMode: false,
        })
            .end();

        // 使用webpack 插件进行typescript 的类型检查 fork-ts-checker-webpack-plugin
        config.plugin('fork-ts-checker').use(ForkTsCheckerWebpackPlugin, [
            {
                vue: true,
                tslint: false,
                formatter: 'codeframe',
                checkSyntacticErrors: false,
                // 因为fork-ts-checker-webpack-plugin是在单独的进程跑的,所以它的错误或警告信息是异步回传给到webpack进程的, 这时编译报错信息只在终端显示,不会在预览的浏览器界面显示报错信息。
                // 将async设置为false后,就要求webpack等待fork-ts-checker-webpack-plugin进程返回信息, 这样会在页面显示编译报错信息。不过这样做也可能会拖慢整个webpack的转译等待时间。
                // async: false
            },
        ]);

        config.resolve
            .set('symlinks', false)
            .extensions.merge(['.js', '.json', '.vue', '.ts'])
            .end();
    },
    ...
}

但是在npm上看到babel-preset-vite的说明有这样一句话

The functionality within these transformations should not be relied upon in production.

也就是说不建议放在将babel-preset-vite配置在生产环境。。但是他没有说为什么不能用在生产环境,也没有给出生产环境的替代方案,所以暂时只能这样发到测试环境,目前还没有发现什么问题,如果有解决方案的小伙伴可以告知我,一起学习一下~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值