vue2+vite+vue-cli5 实现vite开发webpack打包

20221008补充一条,如果需要兼容IE,需要修改.browserslistrc为

> 1%
last 2 versions
IE 11
IE 10

去除自带的not dead,

1. 为何要用vite开发,但是webpack打包

主要是因为即想要得到vite的高效开发模式(免编译)但是最后又想要兼容到IE9(ps,vite自带插件最多IE11而且打包出两份代码)

2. 实现流程

主要通过利用vue-cli5构建vue2项目(vue3不兼容IE),然后用vite-plugin-vue2实现vite开发(不需要使用它打包)

2.1 vue-cli5

推荐升级使用vue-cli5,可以避免很多问题,
例如vue-cli5默认会出现vue.config.js,
vue-cli4.3 生成的typescript 的vue项目中typescript版本过低导致报错
vue-cli4.3 很多vue.config.js的配置无效,例如 runtimeCompiler:true

npm install -g @vue-cli

2.2 创建vue项目

Use class-style component syntax 这儿先选择n,如果你希望项目依然可以兼容原来的非class写法的话,这个先选n,后面手动在package.json的dependencies加上

    "vue-class-component": "^7.2.3",
    "vue-property-decorator": "^9.1.2",

最后记得选择In dedicated config files 为Y,
typescript可选可不选

2.3 兼容vite

这部分我参考了这篇文章,但是对其中部分操作进行了修正webpack项目中使用vite加速的兼容模式详解

2.3.1 index.html处理

vite需要index.html在根目录,那就把index.html拷贝到根目录,这儿需要删除里面原有的htmlWebpackPlugin相关的代码,否则vite会报错,
另外还需要注入main函数给index.html

接下来在根目录下添加command文件夹,并在其中新建htm.js和vite.js(node启动用)
html.js 主要作用是在webpack打包前把index.html拷贝一份到public目录下

// ./command/html.js
const path = require('path')
const fs = require('fs')
// 把 index.html 拷贝到 public 下
fs.copyFileSync(path.resolve('./index.html'), path.resolve('./public/index.html'))

为何不保留public下的index.html呢,这就是一个坑,本人已经踩过了,
当public下存在index.html时,vite启动后无法正常给index.html注入main函数
因此需要vite.js

const path = require('path')
const fs = require('fs')
// vite启动时,需要删除public 下的index.html
if(fs.existsSync(path.resolve('./public/index.html'))){
    fs.unlinkSync(path.resolve('./public/index.html'));
}

然后就是新建vite.config.js
在里面配置vite-plugin-html实现main函数注入,具体可以参考之前提到的那篇文章

然后就是设置vite-plugin-vue2等插件到vite.config.js

2.3.2 启动项目配置

package.json中script部分

    "vite": "node ./command/vite.js && vite",
    "serve": "node ./command/html.js && npm run transformJs && vue-cli-service serve",
    "build": "node ./command/html.js && npm run transformJs && vue-cli-service build",
    "transformJs": "babel --plugins @babel/plugin-transform-modules-commonjs --presets=@vue/cli-plugin-babel/preset ./config -d ./config_cm"

我这提示需要babel7.0以上,卸了原来的6.x,重装7.0

npm uninstall babel-cli
npm uninstall babel-core
npm install @babel-cli
npm uninstall @babel-core

然后安装 @babel/plugin-transform-modules-commonjs 和 @vue/cli-plugin-babel 即可
npm run vite 表示vite启动

2.3.3 vite和webpack公用一个调试devServer

本来其实可以不用的,但是有些情况下,需要即时的看下webpack下的IE兼容情况,而不是每次都需要打包部署后查看
文章中提供了实现,就是上一节中的babel的作用,但是实际测试发现vue-cli5会检测devServer配置字段,
在根目录下新建config文件夹,然后新建config/index.js
20230118补漏,根目录下还要再建一个config_cm/index.js
因为vue.config.js中无法使用export语法导出的js需要把config/index.js 通过babel转换为config_cm/index.js后,在vue.config.js中引入

export default function (webpackFlag) {
    let config = {
        host: '0.0.0.0',
        port: 12003,
        https: false,
        proxy: {
            "/_api": {
                //target: "http://172.27.148.96:8871",
                //target: "http://32.142.240.253:8871",  //写地址
                target: "http://localhost:8090",
                ws: true,  // 允许跨域
                changeOrigin: true,  //允许跨域
                /*改动一下,由于vite.config和vue.config path重写不同*/
                //pathRewrite: {
                //    "^/_api": ""
                //},
                timeout: 60000
            }
        }
    }
    if (webpackFlag === true) {
    /*改动一下,由于vite.config和vue.config path重写不同*/
    	config.proxy["/_api"].pathRewrite ={
            "^/_api": ""
        }
        return config;
    }
    else {
        config = Object.assign(config, {
            hotOnly: true,
            disableHostCheck: true
        })
        /*改动一下,由于vite.config和vue.config path重写不同*/
        config.proxy["/_api"].rewrite=(path) => path.replace(/^\/_api/,'');
        return config;
    }
}

相比原文章直接导出固定的config会导致vue-cli5启动时检测到不合法的字段而失败,我这儿导出了函数,并支持传入flag得到不同的config。
相应的vue.config.js中devServer要这么写

const path = require('path')
function resolve(dir) {
    return path.join(__dirname, dir)
}
const { defineConfig } = require('@vue/cli-service')
const getDevServer = require(resolve('config_cm')).default  //此处vue.config.js中使用了经过babel转换后的config_cm
module.exports = defineConfig({
  transpileDependencies: true,
  devServer:getDevServer(true)
})

vite.config.js中这么写

import getDevServer from './config/index.js'   //vite中就不需要使用babel转换的代码
...
{
server:getDevServer(),
}
...

3. 主要配置代码(用了ts)

vue.config.js 其他配置自己加

const path = require('path')
function resolve(dir) {
    return path.join(__dirname, dir)
}
const { defineConfig } = require('@vue/cli-service')
const getDevServer = require(resolve('config_cm')).default
module.exports = defineConfig({
  transpileDependencies: true,
  devServer:getDevServer(true)
})

vite.config.js 参考webpack项目中使用vite加速的兼容模式详解 并修改所得

// vite.config.js
import getDevServer from './config/index.js'
import { defineConfig, loadEnv } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'
import path from 'path'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { createVuePlugin } from "vite-plugin-vue2";
// import requireTransform from 'vite-plugin-require-transform';

export default defineConfig(({ mode }) => {
    const envPrefix = ['VUE']
    const env = loadEnv(mode, process.cwd(), envPrefix)
    const define = {
        'process.env.NODE_ENV': '"development"',
        'process.env.BASE_URL': '"/"',
        'process.env.VITE': true
    }
    for (const [key, value] of Object.entries(env)) {
        define[`process.env.${key}`] = `"${value}"`
    }
    // 加载环境变量,因为 vite 中不会加载以 VUE 开头的,我们得自己指定下
    return {
        build: {
            // 设置vite打包大小控制
            chunkSizeWarningLimit: 10000,
        },
        resolve: {
            extensions: [".vue", ".mjs", ".js", ".ts", ".jsx", ".tsx", ".json"],
            alias:{
                '@': path.resolve(__dirname, './src/')
            },
            // alias: [
            //     // 针对以 ~@/[包名称]开头的,替换为 node_modules/@[包名称]
            //     { find: /^(~@)(?!\/)(.+)/, replacement: path.join('node_modules/@$2') },
            //     // 针对以 ~@/ 开头,替换为 src/
            //     { find: /^~@\//, replacement: path.join(__dirname, 'src/') },
            //     // 针对以 @/ 开头的,替换为 src/
            //     { find: /^@\//, replacement: path.join(__dirname, './src', '/') }
            // ],
        },
        server:getDevServer(),
        define,
        plugins: [
            // requireTransform({
            //     fileRegex: /.js$|.vue$|.ts$/
            // }),
            createSvgIconsPlugin({
                // 指定要缓存的文件夹
                iconDirs: [path.resolve(process.cwd(), 'src/assets/svgs')],
                // 指定symbolId格式
                symbolId: '[name]'
            }),
            createVuePlugin(),
            createHtmlPlugin({
                minify: true,
                template: './index.html',
                entry: '/src/main.ts', // 这个会帮我们注入入口 js 文件
                inject: {
                    data: {
                        // 这是我们 index.html 用到的环境变量
                        ...env
                    }
                }
            })
        ]
    }
})

package.json部分
需要class组件写法的加上
“vue-class-component”: “^7.2.3”,
“vue-property-decorator”: “^9.1.2”,
可以实现class组件写法和原来的非class写法在typescript下兼容
需要注意的是下面的transformJs在使用vue-cli serve或者build时,需要把/config/index.js转换为/config_cm/index.js供vue.config.js使用

{
  "scripts": {
    "vite": "node ./command/vite.js && vite",
    "serve": "node ./command/html.js && npm run transformJs && vue-cli-service serve",
    "build": "node ./command/html.js && npm run transformJs && vue-cli-service build",
    "transformJs": "babel --plugins @babel/plugin-transform-modules-commonjs --presets=@vue/cli-plugin-babel/preset ./config -d ./config_cm"
  },
  "dependencies": {
    "@babel/plugin-transform-modules-commonjs": "^7.18.6",
    "core-js": "^3.8.3",
    "vite": "^3.1.3",
    "vite-plugin-html": "^3.2.0",
    "vite-plugin-svg-icons": "^2.0.1",
    "vite-plugin-vue2": "^2.0.2",
    "vue": "^2.6.14",
    "vue-class-component": "^7.2.3",
    "vue-property-decorator": "^9.1.2",
    "vue-router": "^3.5.1"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^5.0.8",
    "@vue/cli-plugin-router": "~5.0.0",
    "@vue/cli-plugin-typescript": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "less": "^4.0.0",
    "less-loader": "^8.0.0",
    "typescript": "~4.5.5",
    "vue-template-compiler": "^2.6.14"
  }
}

顺便把tsconfig.json也提供下吧

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "noImplicitAny":false,
	  "skipLibCheck": true,
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
      "webpack-env"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

你可能感兴趣的:(vue,typescript,vue.js,webpack)