背景

19年新建的vue项目,使用的是webpack3,随着项目的积累,组件的增多导致本地构建,线上打包等操作速度极慢,非常影响开发效率和部署效率,基于此问题,本次对webpack及相关插件进行了优化和升级。本博文分为2篇,第 1 篇 会直接附上可运行的代码(去除了一些业务代码配置),直接粘贴复制即可使用(注意是基于vue2.0项目原配置基础上的修改哦,在网上找了一堆都是升级过程的各种坑说明,不如直接粘贴复制运行来的爽丫~~~),第 2 篇也会对相关的修改和遇到的坑进行描述说明。

升级效果

1、本地构建

第一次构建 5分钟 缩短至 1.5分钟左右, 构建时间提升近 4 倍

更新构建 由 5-10s 缩短至 1-5s ,构建提升 2 倍

2、线上打包

执行npm run build 由10-15分钟 缩短至 3-5分钟,构建时间提升近4倍

升级过程

1. 更新webpack依赖
yarn upgrade webpack@5.37.0
yarn add webpack-dev-server webpack-cli -D

更新其他相关的组件,这里不需要一个个找了,可以使用npm-check-updates一键升级所需的组件,不再赘述怎么用的了,百度一下,你就知道,实在不会就一个个install吧~

2. package.json启动命令修改
  "scripts": {
"dev": "npx webpack serve --config build/webpack.dev.conf.js --color --progress",
"build": "node build/build.js",
"dll": "npx webpack --config build/webpack.dll.conf.js",
"start": "npm run dev"
}
3、webpack.base.conf.js配置修改
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const webpack = require('webpack')
const vueLoaderConfig = require('./vue-loader.conf')
const { VueLoaderPlugin } = require('vue-loader'); function resolve (dir) {
return path.join(__dirname, '..', dir)
} module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.ts'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
vue$: 'vue/dist/vue.esm.js',
'@': resolve('src'),
pages: resolve('src/pages')
}
},
module: {
rules: [
{
test: /\.vue$/,
use: {
loader: 'vue-loader'
}
},
{
test: /\.tsx?$/,
exclude: resolve('node_modules'),
use: [
{
loader: 'babel-loader'
},
{
loader: "ts-loader",
options: { appendTsxSuffixTo: [/\.vue$/], transpileOnly: true }
}
]
},
{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: resolve('node_modules'),
include: resolve('src')
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 10kb
}
},
generator: {
filename: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
},
node: {
global: false
},
plugins: [
new VueLoaderPlugin(),
new webpack.ProvidePlugin({
jQuery: 'jquery',
$: 'jquery'
}),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: path.resolve(__dirname, './vendors.manifest.json')
})
]
}
4、webpack.dev.conf.js配置修改
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const { merge } = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder') const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT) const devWebpackConfig = merge(baseWebpackConfig, {
mode: 'development',
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
devtool: config.dev.devtool,
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false,
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay ? { warnings: false, errors: true } : false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true,
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: 'body',
scriptLoading: 'blocking',
minify: {
removeComments: true
}
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
globOptions: {
dot: true,
gitignore: true,
ignore: ['.*'],
}
},
]
})
]
}) module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
process.env.PORT = port
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined
}))
resolve(devWebpackConfig)
}
})
})
5、webpack.prod.conf.js配置修改
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const env = require('../config/prod.env') const webpackConfig = merge(baseWebpackConfig, {
mode: "production",
module: {
rules: utils.styleLoaders({
sourceMap: false,
extract: true,
usePostCSS: true
})
},
devtool: config.build.devtool,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
clean: true
},
optimization: {
minimize: true,
minimizer: [
new TerserWebpackPlugin(),
new OptimizeCSSPlugin(),
],
runtimeChunk: { name: 'runtime' },
concatenateModules: true,
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all',
priority: -10
},
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 2,
chunks: 'async',
name: 'async-vendors'
}
},
},
moduleIds: 'deterministic'
},
plugins: [
new webpack.DefinePlugin({
'process.env': env
}),
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
chunkFilename: utils.assetsPath('css/[name].[contenthash].css')
}),
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
scriptLoading: 'blocking',
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'auto'
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
globOptions: {
dot: true,
gitignore: true,
ignore: ['.*'],
}
},
]
})
]
}) if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin');
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
filename: '[path][base].gz[query]',
algorithm: 'gzip',
test: /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: true
})
)
} if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
} module.exports = webpackConfig
6、utils.js配置修改
'use strict'
const path = require('path')
const config = require('../config')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const packageConfig = require('../package.json') exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory;
return path.posix.join(assetsSubDirectory, _path)
} exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
} const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
} // generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
} // Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return [
{
loader: MiniCssExtractPlugin.loader,
}
].concat(loaders)
} else {
return [
{
loader: 'style-loader'
}
].concat(loaders)
}
} // https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
// sass: generateLoaders('sass', { indentedSyntax: true }),
// scss: generateLoaders('sass'),
// stylus: generateLoaders('stylus'),
// styl: generateLoaders('stylus')
}
} // Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options) for (const extension in loaders) {
const loader = loaders[extension]; // console.log("css-loader", loader)
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
} return output
} exports.createNotifierCallback = () => {
const notifier = require('node-notifier') return (severity, errors) => {
if (severity !== 'error') return const error = errors[0]
const filename = error.file && error.file.split('!').pop() notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}

转载请说明来处 黑玛鱼的前端博客

老vue项目webpack3升级到webpack5全过程记录(一)的更多相关文章

  1. Eclipse 导入项目与 svn 插件关联全过程记录

    文章摘自:http://www.cnblogs.com/xmmcn/archive/2013/03/01/2938365.html 感谢博友分享! Eclipse 导入项目与 svn 插件关联全过程记 ...

  2. 在vue项目中的axios使用配置记录

    默认vue项目中已经安装axios,基于element-ui开发,主要记录配置的相关. axiosConfig.js import Vue from 'vue' import axios from ' ...

  3. vue项目node升级后,node-saas报错解决办法

    ERROR in ./node_modules/_extract-text-webpack-plugin@3.0.2@extract-text-webpack-plugin/dist/loader.j ...

  4. 如何快速把 Vue 项目升级到 webpack3

    由于 webpack3升级后,新增了 Scope Hositing(作用域提升) 功能,据说是对 js的性能提升很大.因此,我们做了一个测试对比,就是 webpack3和 webpack1/2 的性能 ...

  5. Vue项目搭建完整剖析全过程

    Vue项目搭建完整剖析全过程 项目源码地址:https://github.com/ballyalex 有帮助的话就加个星星呗~!  项目技术栈:vue+webpack+bower+sass+axios ...

  6. prettier包升级后vue项目运行报错

    今天用vue-cli新建vue项目的时候,发现项目怎么都跑不起来. 最后通过与以前项目作比较,发现prettier这个依赖的版本从原来的1.12.0升级成了1.13.1.我也不太清楚为什么升级后项目跑 ...

  7. 简单vue项目脚手架(vue+webpack2.0+vuex+vue-router)

    github地址 使用技术栈 webpack(^2.6.1) webpack-dev-server(^2.4.5) vue(^2.3.3) vuex(^2.3.1) vue-router(^2.5.3 ...

  8. 原有vue项目接入typescript

    原有vue项目接入typescript 为什么要接入typescript javascript由于自身的弱类型,使用起来非常灵活. 这也就为大型项目.多人协作开发埋下了很多隐患.如果是自己的私有业务倒 ...

  9. element-ui和npm、webpack、vue-cli搭建Vue项目

    一.element-ui的简单使用 1.安装 1. npm 安装 推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用. npm i element-ui -S 2. CDN ...

随机推荐

  1. 谜题(JAVA语言)

    package 第三章习题; /*  * 有一个5*5的网络,其中恰好有一个格子是空的,其他格子各有一个字母.  * 一个有4种指令:A, B, L, R, 分别表示把空格上.下.左.右的相邻字母移到 ...

  2. python3 虚拟环境 venv

    创建一个虚拟环境: python -m venv test            (test 为创建的虚拟环境目录) 激活虚拟环境: test\Scripts\activate            ...

  3. pgrep - 命令

    pgrep 命令格式:pgrep [选项] [模式] 选项 含义 -d <string> 指定输出分隔符 -l PID和进程名称 -a 列出PID和完整的命令行 -v 取反 -c 统计进程 ...

  4. PAT (Basic Level) Practice (中文)1055 集体照 (25 分) 凌宸1642

    PAT (Basic Level) Practice (中文)1055 集体照 (25 分) 凌宸1642 题目描述: 拍集体照时队形很重要,这里对给定的 N 个人 K 排的队形设计排队规则如下: 每 ...

  5. 更改当前目录--cd

    pwd   显示当前所在的目录路径 cd ../ 回到上一层目录 cd ../../     回到上上层目录 cd /          回到根目录 cd ~         回到当前用户的根目录 c ...

  6. JVMGC+Spring Boot生产部署和调参优化

    一.微服务开发完成,IDEA进行maven clean和package 出现BUILD SUCCESS说明打包成功 二.要求微服务启动时,配置JVM GC调优参数 p.p1 { margin: 0; ...

  7. 201871030122-牛建疆 实验三 结对项目——《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客链接 班级博客链接 作业要求链接 作业要求链接 我的课程学习目标 (1)体验软件项目开发中的两人合作,练习结对编程(Pair programming).(2)掌握Github协 ...

  8. 201871010109-胡欢欢-实验一-软件工程的准备(初识github及《现代软件工程-构建之法》)

    项目 内容 课程班级博客链接 2021年春软件工程课程班(2018级计算机科学与技术) 这个作业要求链接链接 实验一软件工程准备 我的课程学习目标 了解github的基本使用,学习markdown编辑 ...

  9. Leedcode算法专题训练(栈和队列)

    1. 用栈实现队列 232. Implement Queue using Stacks (Easy) Leetcode / 力扣 class MyQueue { Stack<Integer> ...

  10. 6.2set用法

    目录 1.set的定义 2.set容器内元素的访问 3.set常见使用的函数 set可以内部进行自动递增排序,且自动去除了重复元素 1.set的定义 set<typename> name; ...