情况
19年新创建的vue项目,应用的是webpack3,伴随着新项目的累积,部件的增加造成当地搭建,网上装包等操作速度超慢,十分危害开发设计高效率和布署高效率,根据此难题,此次对webpack及有关软件开展了提升和升級。本博闻分成2篇,第 1 篇 会立即另附可运作的编码(去除开一些业务流程编码配备),立即粘贴复制就可以应用(留意是根据vue2.0新项目原配备基本上的改动哦,在网络上找了一堆全是升級全过程的各种各样坑表明,比不上立即粘贴复制运作来的爽丫~~~),第 2 篇也会对有关的改动和碰到的坑开展叙述表明。
升級实际效果
1、当地搭建
第一次搭建 五分钟 减少至 1.五分钟上下, 搭建時间提高近 4 倍;
升级搭建 由 5-10s 减少至 1-5s ,搭建提高 2 倍;
2、网上装包
实行npm run build 由10-15分钟 减少至 3-五分钟,搭建時间提高近4倍;
升級全过程
1. 升级webpack依靠
yarn upgrade [email protected] 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') }) } }