共计 6473 个字符,预计需要花费 17 分钟才能阅读完成。
大家好!
文本是为了晋升开发效率及体验实际诞生的。
我的项目背景:
- 脚手架:vue-cli3,具体为
"@vue/cli-service": "^3.4.1"
- 库:vue2,具体为:
"vue": "2.6.12"
- 备注:没有 typescript , 非 ssr
痛点:随着工夫的推移、业务的一直迭代,依赖、性能、代码越来越多,我的项目本地启动比较慢、开发热更新比较慢。
改良指标:保留原来的 webpack, 反对 vite。并且尽可能的缩小改变,缩小保护老本。
思考:
- vite 生产环境用的是 rollup,rollup 更适宜打包库。
- vite 打包提效并没有进步太多。
- 保留原来的 webpack 形式,尽可能的保障生产的稳固与平安。
实际
次要是解决三方面:
- 配置文件需依据
vue.config.js
减少vite.config.js
- 入口文件
index.html
反对 vite 的形式 - 配置 vite 启动命令
-
可能须要
- 路由懒加载,vite 须要非凡解决
- 解决 commonjs 与 esModule 的引入与混用
减少 vite.config.js
在我的项目根目录创立一个 vite.config.js
装置所需依赖
npm i vite vite-plugin-vue2 -D
依据 vue.config.js
在 vite.config.js
中减少对应配置
// 若改了该文件逻辑,请对照着改一下 vue.config.js | |
import path from 'path' | |
import fs from 'fs' | |
import {defineConfig} from 'vite' | |
import config from './config' | |
import {createVuePlugin} from 'vite-plugin-vue2' | |
import {injectHtml} from 'vite-plugin-html' | |
const resolve = dir => path.join(__dirname, dir) | |
const alias = { | |
vue: 'vue/dist/vue.esm.js', | |
'@': resolve('src'), | |
} | |
const publicPath = '/' | |
const mode = 'development' | |
// https://vitejs.dev/config/ | |
export default defineConfig({ | |
base: publicPath, | |
plugins: [createVuePlugin(), | |
], | |
// 这些是注入我的项目中的变量,若有 process 结尾的,都须要在这儿注入,vite 默认不会注入 process 相干的变量及值 | |
define: {'process.env.NODE_ENV': JSON.stringify(mode), | |
'process.env.publicPath': JSON.stringify(publicPath), | |
}, | |
resolve: { | |
// 配置别名 | |
alias, | |
// 导入时想要省略的扩展名列表,必须退出.vue,因为 vite 默认不反对省略 .vue 后缀 | |
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] | |
}, | |
server: { | |
// 容许跨域 | |
cors: true, | |
proxy: {// 可间接拷贝 vue.config.js 中对应的 proxy} | |
} | |
}) |
sass 相干
配置非凡阐明:若我的项目中有用是 sass
预处理器, 且用到变量了。
须要装置 sass@1.32.13,不能装置比 1.32
更高的版本,跟高版本存在这个问题 Sass 报错: Using / for division is deprecated
npm i sass@1.32.13 -D
export default defineConfig({ | |
... | |
css: { | |
// 给 sass 传递选项 | |
preprocessorOptions: { | |
scss: { | |
charset: false, // 最新版 sass 才反对 | |
additionalData: `@import "src/sass/common/var.scss";`, | |
} | |
}, | |
}, | |
... | |
}) |
备注:如果生产环境用 vite 打包,采纳 sass@1.32.13
将会遇到这个问题 vite2 打包呈现正告,”@charset” must be the first,该如何打消呢?,然而 sass@1.32.13
不反对文档中的配置。所以这能够算是生产环境不必 vite 的一个起因。
还需全局替换 /deep/
为 ::v-deep
入口文件 index.html
反对 vite 的形式
因为 vite 的我的项目要求 index.html 文件在根目录,且有入口文件配置。
所以将 index.html 从 public 目录移到根目录。并退出
<% if (typeof isVite === 'boolean' && isVite) { %> | |
<script type="module" src="/src/main.js"></script> | |
<% } %> |
这样配置是为了能让 webpack、vite 形式都都反对,共用一个文件
而为了在 index.html 文件注入 isVite
变量,须要装置
npm i vite-plugin-html -D
须要在 vite.config.js
中配置
... | |
import {injectHtml} from 'vite-plugin-html' | |
export default defineConfig({ | |
... | |
plugins: [ | |
... | |
injectHtml({ | |
data: { | |
title: 'vite-plugin-html-example', | |
isVite: true | |
}, | |
}), | |
], | |
define: {'process.env.isVite': JSON.stringify(true) | |
}, | |
... | |
}) |
配置 vite 启动命令
最初在 package.json
中减少脚本
"scripts": {"vite-start": "vite"}
路由懒加载,vite 须要非凡解决
vue 实现路由懒加载的形式是这样的
const Home = import(/* webpackChunkName: "[home]" */ `@/page/home.vue`) | |
const routes = [ | |
{ | |
path: `/home`, | |
name: 'home', | |
component: Home | |
}, | |
] |
然而 vite 不反对,解决
const modules = import.meta.glob('@/page/*.vue') | |
const Home = modules['@/page/home.vue'] |
const modules = import.meta.glob('@/page/*.vue') | |
// vite 会生成代码 | |
const modules = {'@/page/home.vue': () => import('@/page/home.vue'), | |
'@/page/page1.vue': () => import('@/page/page1.vue'), | |
'@/page/page2.vue': () => import('@/page/page2.vue'), | |
... | |
} |
参考:vite-Glob 导入
所以可封装一下:
function loadPage (view) {if (process.env.isVite) {const modules = import.meta.glob('../pages/*.vue') | |
return modules[`../pages/${view}.vue`] | |
} | |
return () => import(/* webpackChunkName: "[request]" */ `@/pages/${view}`) | |
} | |
// 应用:const routes = [ | |
{ | |
path: `/home`, | |
name: 'home', | |
component: loadPage('home'), | |
}, | |
{ | |
path: `/404`, | |
name: '404', | |
component: loadPage('404'), | |
}, | |
] |
然而 webpack 不反对 import.meta,须要 loader 解决。解决:在本地建一个文件 webpack-import-meta-loader.js。
// 起源:https://github.com/KmjKoishi/webpack-import-meta-loader-fixed | |
// 是对 @open-wc/webpack-import-meta-loader 这个的修复 | |
// 次要是修复 当 this.rootContext 不存在的判断解决。构建生产环境时不存在 | |
/* eslint-disable */ | |
// @ts-nocheck | |
const path = require('path'); | |
function toBrowserPath(filePath, _path = path) {return filePath.replace(new RegExp(_path.sep === '\\' ? '\\\\' : _path.sep, 'g'), '/'); | |
}; | |
const regex = /import\.meta/g; | |
/** | |
* Webpack loader to rewrite `import.meta` in modules with url data to the source code file location. | |
* | |
* @example | |
* return import.meta; | |
* // becomes: return ({url: `${window.location.protocol}//${window.location.host}/relative/path/to/file.js` }); | |
* | |
* return import.meta.url; | |
* // becomes: return ({url: `${window.location.protocol}//${window.location.host}/relative/path/to/file.js` }).url; | |
*/ | |
module.exports = function (source) {const path = require('path'); | |
const relativePath = this.context.substring(this.context.indexOf(this.rootContext) + (this.rootContext && this.rootContext.length >= 0 ? (this.rootContext.length + 1) : 0), | |
this.resource.lastIndexOf(path.sep) + 1, | |
); | |
const browserPath = toBrowserPath(relativePath); | |
const fileName = this.resource.substring(this.resource.lastIndexOf(path.sep) + 1); | |
let found = false; | |
let rewrittenSource = source.replace(regex, () => { | |
found = true; | |
return `({url: getAbsoluteUrl('${browserPath}/${fileName}') })`; | |
}); | |
if (found) { | |
return ` | |
function getAbsoluteUrl(relativeUrl) { | |
const publicPath = __webpack_public_path__; | |
let url = ''; | |
if (!publicPath || publicPath.indexOf('://') < 0) {url += window.location.protocol + '//' + window.location.host;} | |
if (publicPath) {url += publicPath;} else {url += '/';} | |
return url + relativeUrl; | |
} | |
${rewrittenSource}`; | |
} else {return source;} | |
}; |
vue.config.js 批改配置:
const resolve = dir => require('path').join(__dirname, dir) | |
module.exports = { | |
... | |
configureWebpack: { | |
... | |
module: { | |
rules: { | |
... | |
{ | |
test: /index.js$/, | |
use: [resolve('webpack-import-meta-loader'), | |
'babel-loader' | |
], | |
include: [resolve('src/router')] | |
} | |
} | |
} | |
} | |
... | |
} |
解决 commonjs 与 esModule 的引入与混用
混用
webpack 形式下,若你的 src 我的项目源码中存在混用 commonjs 与 esModule。
计划一:不改源码,在 vite.config.js 中加配置,把 commonjs 转换为 esModule
装置 npm i cjs2esmodule -D
在 vite.config.js 中加配置
export default defineConfig({plugins: [cjs2esmVitePlugin()] | |
}) |
如果这个计划,能让你的我的项目运行失常。否则,可能须要采纳计划二。
计划二:把 src 代码中的 commonjs 语法本人手动改为 esModule
引入
如果你的我的项目在有一个 config.js, 被 vue.config.js 中应用。那么你可能须要解决。
vue.config.js 必须是 commonjs 语法的文件,能力被应用,否则会报错。
vite.config.js 既能够 esModule 语法,也能够 commonjs 语法。默认是 esModule 语法。
若下面混用,你是采纳计划二,而且 src 代码中也用了 config.js。那么你只能把 config.js 改成 esModule 的形式。此时 vue.config.js 不反对了,采纳的计划是依据 config.js 主动生成一个 config-cjs.js。
目标是缩小前期保护老本。
// transformConfig2cjs.js | |
// 运行我的项目的时候,会依据 config.js 主动生成文件:config-cjs.js, 以便让 vue-config.js 能间接应用 | |
const {transformAsync} = require('@babel/core'); | |
const plugin = require('@babel/plugin-transform-modules-commonjs') | |
const fs = require('fs') | |
const resolve = dir => require('path').join(__dirname, dir) | |
async function transfrom () {const inputPath = resolve('config.js') | |
const input = fs.readFileSync(inputPath, 'utf-8') | |
const {code} = await transformAsync(input, { | |
sourceType: 'module', | |
plugins: [plugin] | |
}); | |
fs.writeFileSync(resolve('./config-cjs.js'), code); | |
} | |
transfrom() |
而后在 vue.config.js 原来引入的 config.js 的中央改为 config-cjs.
最初在 package.json
中扭转下脚本,每次都从新生成一个最新的配置。
"scripts": { | |
"transformConfig2cjs": "node transformConfig2cjs.js", | |
"serve": "npm run transformConfig2cjs && vue-cli-service serve", | |
"build": "npm run transformConfig2cjs && vue-cli-service build", | |
} |
总结
遇到很多坑,都是语法相干的,最终都 11 解决了!
也尝试过一些其余计划,然而不能用,我的我的项目没有失效:
- wp2vite
反对了之后,开发是真的很高效!
心愿这篇文章对有须要的有所帮忙。