Vue-cli4 project packaging 💕
How to operate webpack
For vli3 and vli4 versions, we need to modify the webpack configuration. We need to create the vue.config.js file in the project root directory
First, configure the cross domain problem of the interface
module.exports = { devServer: { open: false, // Auto launch browser host: '0.0.0.0', // localhost port: 6060, // Port number, can not be configured hotOnly: false, // Hot update, can not be configured overlay: { // Displays a full screen overlay in the browser when a compiler error or warning occurs warnings: false, errors: true }, proxy: { // 2. Configure cross domain '/api': { target: 'http://120.53.31.103:84/xxx/xxx ', / / domain names that allow cross domain interfaces // ws: true, / / whether to enable websockets changOrigin: true, // Open the agent and create a virtual server locally pathRewrite: { '^/api': '/' } } } } }
After configuring the cross domain, we can put the '/ api' in the requested address and use it directly
Configure alias alias
Using Vue cli to develop projects, the biggest feature is componentization. Components frequently refer to other components or plug-ins. We can define some common paths as short names. It is convenient for use in development. It can be configured after the project is created, which is convenient for later use
//Load path module const path = require('path') //Define the resolve method to convert a relative path into an absolute path const resolve = dir => path.join(__dirname, dir) ``module.exports = { chainWebpack: config => { // add alias config.resolve.alias .set('@', resolve('src')) // vue's own alias .set('assets', resolve('src/assets')) .set('api', resolve('src/api')) .set('views', resolve('src/views')) .set('components', resolve('src/components')) } }
After configuration, it will be more convenient for us to use later. The alias can be used directly for the path
Packaging and optimized configuration of webpack after project development
Purpose:
- Increase packing speed
- Reduce the project volume and improve the loading speed of the first screen
- Improve user experience (skeleton screen)
Steps:
First, we need to modify the path of the static resource file
module.exports = { publicPath: './', // ###1. Static resource path (default /, which must be changed before packaging, otherwise the screen will be blank after packaging) assetsDir: 'assets', lintOnSave: true, }
Here we optimize the packaged project:
- Remove production environment sourceMap
After the vue project is packaged, some map files will be automatically generated in the js folder, which takes up a considerable part of the space. The sourceMap resource mapping file stores the code locations before and after packaging, which is convenient for development and use. This takes up a considerable part of the space.
The function of the map file is: after the project is packaged, the code is compressed and encrypted. If an error is reported during operation, the output error information cannot accurately know where the code reports an error. With a map, you can accurately output which line and column has an error like unencrypted code.
sourceMap is not required for the production environment. We can configure the following attributes:
module.exports = { //Remove the productionSourceMap from the production environment productionSourceMap: false, }
After removing sourceMap, it can reduce about 3-4MB
- Remove console.log printing and comments
Download plug-ins:
cnpm install uglifyjs-webpack-plugin --save-dev
// 4. Remove conlose.log const UglifyJsPlugin = require('uglifyjs-webpack-plugin') configureWebpack: config => { const plugins = []; if (isProduction) { plugins.push( new UglifyJsPlugin({ uglifyOptions: { output: { comments: false, // Remove comments }, warnings: false, compress: { drop_console: true, drop_debugger: false, pure_funcs: ['console.log']//Remove console } } }) ) } },
After removing printing and comments, packaging will reduce about 20-30kb, because congsol. Log () and comments will not take up too much volume
- Accelerate optimization with CDN
cdn optimization refers to the introduction of third-party libraries such as vue, vue router and axios into the project through cdn, which will significantly reduce the number of vendors.js and greatly improve the loading speed of the front page of the project. The following are the specific operations:
const isProduction = process.env.NODE_ENV === 'production'; // externals const externals = { vue: 'Vue', 'vue-router': 'VueRouter', vuex: 'Vuex', vant: 'vant', axios: 'axios' } // The CDN external chain will be inserted into index.html const cdn = { // development environment dev: { css: [], js: [] }, // production environment build: { css: ['https://cdn.jsdelivr.net/npm/vant@2.12/lib/index.css'], js: [ 'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js', 'https://cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js', 'https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js', 'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js', 'https://cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js' ] } } module.exports = { configureWebpack: config => { // Modify configuration for production environment if (isProduction) { // externals config.externals = externals } }, chainWebpack: config => { /** * Add the CDN parameter to the htmlWebpackPlugin configuration */ config.plugin('html').tap(args => { if (isProduction) { args[0].cdn = cdn.build } else { args[0].cdn = cdn.dev } return args }) } }
Add in public/index.html:
<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <title><%= htmlWebpackPlugin.options.title %></title> <!-- use CDN of CSS file --> <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" /> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" /> <% } %> <!-- use CDN Accelerated JS File, configuration in vue.config.js lower --> <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %> <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script> <% } %> </head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
- Compress resource files
Download plug-ins
cnpm i compression-webpack-plugin -D
vue.config.js is configured as follows:
const CompressionWebpackPlugin = require('compression-webpack-plugin') module.exports = { // Change here according to your actual situation publicPath, assetsDir: 'assets', lintOnSave: true, configureWebpack: { plugins:[ new CompressionWebpackPlugin({ filename: '[path].gz[query]', algorithm: 'gzip', // test: /\.js$|\.html$|\.json$|\.css/, test: /\.js$|\.json$|\.css/, threshold: 10240, // Only resources with a size greater than this value will be processed minRatio: 0.8, // Only resources with a compression ratio less than this value will be processed // deleteOriginalAssets: true / / delete the original file }) ], }, }
After compression, some space will be saved. The single back end needs to modify nginx to cooperate with the front end
location ~ .*\.(js|json|css)$ { gzip on; gzip_static on; # gzip_static is the processing module of nginx for static files. This module can read pre compressed gz files, which can reduce the CPU resource consumption of gzip compression each time. gzip_min_length 1k; gzip_http_version 1.1; gzip_comp_level 9; gzip_types text/css application/javascript application/json; root /dist; }
- Compression of picture resources
Download plug-ins
npm install image-webpack-loader --save-dev
This plug-in is easy to fail to download. If it fails, you can install it several times. If it has been downloaded before, uninstall it first and then download it
//npm installed npm removed npm npm uninstall image-webpack-loader //If yarn is installed, remove yarn yarn remove image-webpack-loader
Using cnpm means installing cnpm and then setting the global registry to the image of Ali. Domestic Ali is faster
npm install cnpm -g --registry=https://registry.npm.taobao.org
Using cnpm to install image webpack loader, you will find that it will be installed soon
cnpm install --save-dev image-webpack-loader
Configure vue.config.js
module.exports = { // Change here according to your actual situation publicPath, assetsDir: 'assets', lintOnSave: true, // image compression is defined in chainWebpack chainWebpack: config => { config.module .rule('images') .use('image-webpack-loader') .loader('image-webpack-loader') .options({ bypassOnDebug: true }) .end()} }
- Common code extraction
Starting from webpack4, the commonchunk plug-in was officially removed and the optimization attribute was used for more flexible configuration, which should also be the most complex part of the code modification process of upgrading from V3 to V4
splitChunks: { chunks: "async",//The default value is all/initial/async/function(chunk). When the value is function, the first parameter is the chunk module when traversing all entry chunks, chunk_ Modules are all dependent modules of chunk. They can be freely configured through the name of chunk and the resource s of all dependent modules. All public modules that meet the conditions of chunk and all dependent modules of the module, including css, will be extracted minSize: 30000, //Indicates the minimum module size before compression. The default value is 30kb minChunks: 1, // Indicates the number of references. The default value is 1; maxAsyncRequests: 5, //All asynchronous requests must not exceed 5 maxInitialRequests: 3, //The number of initial parallel requests shall not exceed 3 automaticNameDelimiter:'~',//Name separator, default is~ name: true, //The packed names are chunk s by default, and the names are separated by separators (the default is ~) cacheGroups: { //Set the cache group to extract chunk s that meet different rules. Take generating common as an example common: { name: 'common', //The name of the extracted chunk chunks(chunk) { //It is the same as the parameter configuration of the outer layer, covering the chunks of the outer layer, and extracting with the chunk as the dimension }, test(module, chunks) { //You can extract strings, regular expressions, and functions in the dimension of module. Any module that meets the conditions will be extracted into the chunk of the common. When it is a function, the first parameter is each module traversed, and the second parameter is each chunk array referenced to the module. In the process of trying, I found that css could not be extracted, which needs further verification. }, priority: 10, //Priority. A chunk is likely to satisfy multiple cache groups and will be extracted into the cache group with high priority minChunks: 2, //Referenced by at least a few chunk s reuseExistingChunk: true,// If the extracted chunk is referenced in the chunk, the chunk will be referenced directly and the packaged code will not be repeated enforce: true // If minSize is not set in the cacheGroup, judge whether to use the upper minSize. true: use 0, false: use the upper minSize } } }
- Third party module extraction
// Common code extraction configureWebpack: config => { //.... //Optimize Item Configuration config.optimization = { splitChunks: { // Split code block cacheGroups: { vendor: {//Third party library withdrawal chunks: 'all', test: /node_modules/, name: 'vendor', minChunks: 1,//The minimum number of times this code block should be referenced before splitting maxInitialRequests: 5, minSize: 0,//Greater than 0 bytes priority: 100//weight }, common: { //Common module extraction chunks: 'all', test: /[\\/]src[\\/]js[\\/]/, name: 'common', minChunks: 2,The minimum number of times this code block should be referenced before splitting maxInitialRequests: 5, minSize: 0,//Greater than 0 bytes priority: 60 }, styles: { //Style extraction name: 'styles', test: /\.(sa|sc|c)ss$/, chunks: 'all', enforce: true }, runtimeChunk: { name: 'manifest' } } } } }
After configuring these attributes, they can be compressed to 1MB. If you want to optimize them, you can continue to configure them:
Complete packaging
Complete packaging
//Load path module const path = require('path') //Define the resolve method to convert a relative path into an absolute path const resolve = dir => path.join(__dirname, dir) // 4. Remove conlose.log const UglifyJsPlugin = require('uglifyjs-webpack-plugin') const isProduction = process.env.NODE_ENV === 'production'; // 5. CDN accelerated optimization // externals exclusion const externals = { vue: 'Vue', 'vue-router': 'VueRouter', vuex: 'Vuex', vant: 'vant', axios: 'axios' } // The CDN external chain will be inserted into index.html const cdn = { // development environment dev: { css: [], js: [] }, // production environment build: { css: ['https://cdn.jsdelivr.net/npm/vant@2.12/lib/index.css'], js: [ 'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js', 'https://cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js', 'https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js', 'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js', 'https://cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js' ] } } module.exports = { publicPath: './', // ###1. Static resource path (default /, white screen after packaging) assetsDir: 'assets', lintOnSave: true, productionSourceMap: false,//Remove production environment sourceMap devServer: { open: false, // Auto launch browser host: '0.0.0.0', // localhost port: 6060, // Port number hotOnly: false, // Hot renewal overlay: { // Displays a full screen overlay in the browser when a compiler error or warning occurs warnings: false, errors: true }, proxy: { // 2. Configure cross domain '/api': { target: 'http://120.53.31.103:84/api/app ', / / domain name of the interface // ws: true, / / whether to enable websockets changOrigin: true, // Open the agent and create a virtual server locally pathRewrite: { '^/api': '/' } } } }, chainWebpack: config => { // 3 add alias config.resolve.alias .set('@', resolve('src')) .set('assets', resolve('src/assets')) .set('api', resolve('src/api')) .set('v', resolve('src/views')) .set('components', resolve('src/components')) // 4. Add the CDN parameter to the htmlWebpackPlugin configuration config.plugin('html').tap(args => { if (isProduction) { args[0].cdn = cdn.build } else { args[0].cdn = cdn.dev } return args }) // 5. Picture compression config.module .rule('images') .use('image-webpack-loader') .loader('image-webpack-loader') .options({ bypassOnDebug: true }) .end() }, configureWebpack: config => {// 4. Remove conlose.log const plugins = []; if (isProduction) { // 4. External exclusions config.externals = externals plugins.push( new UglifyJsPlugin({ uglifyOptions: { output: { comments: false, // Remove comments }, warnings: false, compress: { drop_console: true, drop_debugger: false, pure_funcs: ['console.log']//Remove console } } }) ) } // 6. Optimize Item Configuration config.optimization = { splitChunks: { // Split code block cacheGroups: { vendor: {//Third party library withdrawal chunks: 'all', test: /node_modules/, name: 'vendor', minChunks: 1,//The minimum number of times this code block should be referenced before splitting maxInitialRequests: 5, minSize: 0,//Greater than 0 bytes priority: 100//weight }, common: { //Common module extraction chunks: 'all', test: /[\\/]src[\\/]js[\\/]/, name: 'common', minChunks: 2,//The minimum number of times this code block should be referenced before splitting maxInitialRequests: 5, minSize: 0,//Greater than 0 bytes priority: 60 }, styles: { //Style extraction name: 'styles', test: /\.(sa|sc|c)ss$/, chunks: 'all', enforce: true }, runtimeChunk: { name: 'manifest' } } } } }, }