背景
随着公司vue2构建的项目越来越大,导致编译和启动速度超级慢,而且项目一跑起来node直接占2.5G以上的内存,如果不设置电脑node内存占用上限的话,会导致栈溢出。这对应我只有8G运行内存的电脑来说,负担特别大。随着每一次编译时间的加长以及动不动就内存溢出导致项目直接停止运行问题的出现,终于,我忍不住了。决定把老项目改成webpack5来进行编译和打包,至少编译速度上面应该会好很多。
!!!注意,我这里使用的vue是2.6.12版本的,是带build文件夹的,而不是那种webpack配置只有vue.config.js可以配置的版本
在升级之前,我先处理下内存溢出的问题。如果你出现下面问题,有可能就是跟我一样的原因。
"scripts": {
"start": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"dev": "npm run start --max_old_space_size=8192",
"build": "node build/build.js --no-clean && node ./scripts/versionScript.js",
"fix-memory-limit": "cross-env LIMIT=2048 increase-memory-limit"
},
公司代码之前就在启动项上面设置了--max_old_space_size=8192,但是我电脑上面没有生效(mac)。于是我使用cross-env(可以运行在不同操作系统上),看配置
"scripts": {
"start": "npx webpack serve --config ./build/webpack.dev.conf.js",
"dev:memory": "cross-env NODE_OPTIONS=--max_old_space_size=3072 webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"build": "node build/build.js --no-clean && node ./scripts/versionScript.js",
"fix-memory-limit": "cross-env LIMIT=2048 increase-memory-limit"
},
配置开始(先设置下node版本,我这里用的是node16.0.0)
安装webpack,webpack-cli
大家安装的版本尽量与我的一致,不然很容易因为版本不匹配到时候报错。
"webpack": "^5.96.1",
"webpack-cli": "^5.1.4"
设置package.json中的scripts,因为vue2里面的一些写法在webpack5中不适用了
"start": "npx webpack serve --config ./build/webpack.dev.conf.js",
"dev": "npm run start --max_old_space_size=8192",
设置完成之后,npm run dev遇到第一个报错 TypeError: webpack.NamedModulesPlugin is not a constructor 这个报错是因为webpack5已经不支持这种写法了,直接删掉就行
安装webpack-dev-server
"webpack-dev-server": "^4.15.2"
然后npm run dev 报下面错误。这是因为vue2(webpack3)中有一个node配置项(这些选项可以配置是否 polyfill 或 mock 某些 Node.js 全局变量),然后里面有一些填充了fs模块啥的在 webpack 5 下的 Node.js 中填充 fs需要在resolve.fallback里面去使用。这一步我们先删掉node配置。
Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.devtool should match pattern "^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map(-debugids)?$".
BREAKING CHANGE since webpack 5: The devtool option is more strict.
Please strictly follow the order of the keywords in the pattern.
- configuration.node should be one of these:
false | object { __dirname?, __filename?, global? }
-> Include polyfills or mocks for various node stuff.
然后继续会发现以下报错,看报错信息是我们devtool使用错误,这里我们把devtool的值改为eval-cheap-source-map(每个 module 会通过 eval() 来执行,并且生成一个 DataUrl 形式的 SourceMap) 开启devtool是为了我们开发的时候进行调试,而不同的devtool有不同的效果。
[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.devtool should match pattern "^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map(-debugids)?$".
BREAKING CHANGE since webpack 5: The devtool option is more strict.
Please strictly follow the order of the keywords in the pattern.
安装html-webpack-plugin@5.5.0
然后npm run dev会报一系列devServer文件
Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options has an unknown property 'watchOptions'. These properties are valid:
object { allowedHosts?, bonjour?, client?, compress?, devMiddleware?, headers?, historyApiFallback?, host?, hot?, http2?, https?, ipc?, liveReload?, magicHtml?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, port?, proxy?, server?, setupExitSignals?, setupMiddlewares?, static?, watchFiles?, webSocketServer? }
大家可以按照我这个来配置
devServer: {
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
// contentBase: false, // since we use CopyWebpackPlugin.
static: {
directory: path.join(__dirname, "/")
},
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
proxy: config.dev.proxyTable,
client: {
overlay: true,
}
}
然后npm run dev,这时候应该就会报js和vue相关的错误了。 如下
Module build failed (from ./node_modules/vue-loader/index.js):
TypeError: Cannot read property 'vue' of undefined
安装vue-loader,vue-template-compiler,vue-style-loader
安装"vue-loader": "^14.2.4"
安装"vue-template-compiler": "^2.6.12"(用作Vue2模版编译为渲染函数的,最好和你的vue版本一样,不然可能会出现版本匹配问题)
"vue-style-loader": "^3.1.2"
继续npm run dev这个时候会报一些关于之前删除node配置项的错误,我们只需要根据提示配置一下就行了。
Field 'browser' doesn't contain a valid alias configuration
/Users/luhuaji/node_modules/fs doesn't exist
Field 'browser' doesn't contain a valid alias configuration
/Users/luhuaji/Desktop/vue2-webpack5/node_modules/fs doesn't exist
这里因为每个人项目都不一样,所以这里的配置可能也不一样。只需要根据错误提示,然后网上找下解决方法,基本上都有。下面是我的配置项(build/webpack.base.conf.js)resolve里面加下面代码
fallback: {
path: require.resolve('path-browserify'),
os: require.resolve("os-browserify/browser"),
https: require.resolve("https-browserify"),
fs: false,
util: require.resolve("util/"),
crypto: require.resolve("crypto-browserify"),
buffer: require.resolve("buffer/"),
vm: require.resolve("vm-browserify"),
stream: require.resolve("stream-browserify")
}
"path-browserify": "^1.0.1"
"os-browserify": "^0.3.0" 注意,这里不是下载"os-browserify/browser"
"https-browserify": "^1.0.0"
"util": "^0.12.5"
"crypto-browserify": "^3.12.1"
"buffer": "^6.0.3"
"vm-browserify": "^1.1.2"
"stream-browserify": "^3.0.0"
同时还由于我们使用了webpack5,所以需要指定下当前运行的环境,否则会有提示
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
安装babel-loader,@babel/core,@babel/preset-env,@babel/plugin-transform-runtime
这几个配置都是十分重要的,且需要版本匹配,不然会有意想不到的问题
"babel-loader": "^8.3.0"
"@babel/core": "^7.23.9"
"@babel/preset-env": "^7.26.0"
"@babel/plugin-transform-runtime": "^7.25.9"
我们需要配置.babelrc文件,当然babel还有其他很多配置,可以根据你项目来配置。比如项目中使用到了jsx,这个我一直没有配置成功,暂时还没找到原因。
{
"presets": [
["@babel/preset-env"]
],
// 下面这个选项是引用插件来处理代码的转换,transform-runtime用来处理全局函数和优化babel编译
"plugins": ["@babel/plugin-transform-runtime"]
}
综上基本上运行npm run dev可以正常运行了,但是每个人项目不一样,可能还会存在其他报错。跟着报错提示一个一个解决基本上没啥问题
配置assets资源模块
然后就是在webpack5中我们可以使用资源模块来帮助我们打包其他资源类型,比如字体,图表,图片等文件。所以我们可以把原先webpack3里面的一些字体,图片loader替换成assets模块。不然图片什么的到时候不显示。
在build/webpack.base.conf.js中module下的rules中配置
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: "asset", // 一般会转换为 "asset/resource"
generator: {
filename: utils.assetsPath('img/[name].[hash:7].[ext]'), // 独立的配置
},
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: "asset", // 一般会转换为 "asset/resource"
generator: {
filename: utils.assetsPath('media/[name].[hash:7].[ext]'), // 独立的配置
},
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
type: "asset", // 一般会转换为 "asset/resource"
generator: {
filename: utils.assetsPath('fonts/[name].[hash:7].[ext]'), // 独立的配置
},
}
美化下编译时候的样式
当你按照上面一步步来执行,如果项目比较大。你会发现会停留在这种状态几十秒不懂,不知道的还以为编译失败卡住了。实际上等了一小段时间时候才会显示编译成功。
这时候我们就会想起来,用脚手架搭建的时候会显示编译进度。我们接下来就美化下编译进度。
废话不多说,开始美化
"webpackbar": "^5.0.2"(试过最新版本发现会报错,所以就使用了这个版本)
在build/webpack.dev.conf.js下面
const WebpackBar = require('webpackbar');
plugin: [
new WebpackBar({
name: '武功盖世',
color: 'black',
basic: false
})
]
如果不想要下面的webpack-dev-server等其他信息,我们可以在webpack中配置。在build/webpack.dev.conf.js中配置stats: 'errors-only'。这个配置的意思是只在发生错误时输出。
至于webpack-dev-server的消息输出,目前还没找到隐藏的方法
这是最后的效果
最后
目前来说应该是实现了vue2改为webpack5编译,编译速度确实快了不少,尤其是修改文件之后保存编译,而且打包后的文件也小了一点。不错不错,webpack5值得信赖呀!不过目前还没用作生产,不知道后续会不会出现其他问题。应该问题不大,出现报错,根据报错查找资料解决。当然如果直接改公司的项目还是不推荐,改完最好自己先用用,毕竟我改完也没直接用。而且最好是有webpack基础,不然出了问题就准备提桶跑路吧。而且到这里还没结束,还有打包的修改,下一篇文章继续更新。