preface

In this article, we will further refine and optimize our template. The code for this article can be seen in vue3-WebPack5-TemplateTag1.0.0, so start now

Webpack is fully configured

Although we have added a lot of configuration, there are still a lot of features that are not used, so we are now adding them one by one

devtool

Devtoool controls whether and how sourcemap is generated. There are many values to choose from. In development, we can choose eval to speed up the build, and in production, we can choose source-map for higher quality sourcemap, but the packaging speed is reduced accordingly. You can make your own trade-offs between speed and mass. For Devtool and the rest of the configuration, we can centrally manage them in config.js

module.exports = {
    dev: {
        proxyTable: {},
        // Various Dev Server settings
        host: 'localhost'.// can be overwritten by process.env.HOST
        port: 8080.// can be overwritten by process.env.PORT, if port is in use, a free one will be determined
        autoOpenBrowser: true.errorOverlay: true.poll: false.// https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
        /** * Source Maps */
        // https://webpack.js.org/configuration/devtool/#development
        devtool: 'eval-cheap-module-source-map'.cssSourceMap: true
    },

    build: {
        productionSourceMap: true.// https://webpack.js.org/configuration/devtool/#production
        devtool: 'source-map'.// Gzip off by default as many popular static hosts such as
        // Surge or Netlify already gzip all static assets for you.
        // Before setting to `true`, make sure to:
        // yarn add --save-dev compression-webpack-plugin
        productionGzip: false.productionGzipExtensions: ['js'.'css'].// Run the build command with an extra argument to
        // View the bundle analyzer report after build finishes:
        // `yarn run build --report`
        // Set to `true` or `false` to always turn it on or off
        bundleAnalyzerReport: process.env.npm_config_report
    }
}


Copy the code

mode

Mode is a configuration option within Webpack that tells Webpack that built-in optimizations using the corresponding mode support the following string values:

options describe
development willDefinePlugin 中 process.env.NODE_ENVIs set todevelopment. Enable valid names for modules and chunks.
production willDefinePlugin 中 process.env.NODE_ENVIs set toproduction. Enable deterministic obfuscation names for modules and chunks,FlagDependencyUsagePlugin.FlagIncludedChunksPlugin.ModuleConcatenationPlugin.NoEmitOnErrorsPlugin 和 TerserPlugin 。
none Do not use any default optimization options

If not, Webpack sets the default value of mode to Production. We can set the corresponding mode value in the corresponding environment

stats

This is used to control how the bundle information is displayed. In dev environments, we use ‘errors-only ‘, otherwise we get a bunch of output on the command line that looks messy every time, whereas in prod environments we can set it to normal

performance

If the set size is exceeded, the corresponding prompt will be printed. This can only be configured in webpack.prod.conf.js

Complete configuration

Ok, now let’s take a look at the contents of the various files after adding these configuration items, starting with webpack.dev.conf.js

const merge = require('webpack-merge')
const webpack = require('webpack')
const config = require('./config')

const baseWebpackConfig = require('./webpack.base.conf')

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

const devWebpackConfig = merge(baseWebpackConfig, {
    mode: 'development'.module: {},
    stats: 'errors-only'.devtool: config.dev.devtool,
    devServer: {
        // http://[devserver. host]:[devserver. port]/[output.publicpath]/[output.filename]
        historyApiFallback: true.hot: true.client: {
            overlay: config.dev.errorOverlay ? { warnings: false.errors: true } : false.logging: 'none'.progress: true
        },
        compress: true.host: HOST || config.dev.host,
        port: PORT || config.dev.port,
        open: config.dev.autoOpenBrowser,
        proxy: config.dev.proxyTable
    },
    plugins: [new webpack.HotModuleReplacementPlugin()]
})

module.exports = devWebpackConfig

Copy the code

Then there is the webpack.prod.conf.js file

const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const { resolve } = require('./utils')
const config = require('./config')

const webpackConfig = merge(baseWebpackConfig, {
    mode: 'production'.devtool: config.build.productionSourceMap ? config.build.devtool : false.output: {
        path: resolve('dist'),
        filename: 'js/[name].[chunkhash].js'.publicPath: '/'.clean: true
    },
    stats: 'normal'.cache: {/ /... },
    performance: {
        maxEntrypointSize: 5 * 1024 * 1024.maxAssetSize: 3 * 1024 * 1024.hints: 'warning'
    },
    optimization: {/ /... },
    plugins: [/ /... ]
})


module.exports = webpackConfig

Copy the code

add

Next, we refer to the functionality provided by VUe-CLI to further refine our configuration, first for the development environment

portfinder

If the configured port number is already used, it will automatically +1. This feature is used in PortFinder, which we will discuss in conjunction with the next plug-in

yarn add portfinder -D
Copy the code

FriendlyErrorsPlugin

Customize the message when the package is successful. Interested students can print a pikachu after each successful startup of dev-server

yarn add friendly-errors-webpack-plugin -D
Copy the code

Both plugins are used in webpack.dev.conf.js, and the code is as follows:

const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
// ...
constdevWebpackConfig = merge(baseWebpackConfig,{... })module.exports = new Promise((resolve, reject) = > {
    portfinder.basePort = process.env.PORT || config.dev.port
    portfinder.getPort((err, port) = > {
        if (err) {
            reject(err)
        } else {
            // publish the new Port, necessary for e2e tests
            process.env.PORT = port
            // add port to devServer config
            devWebpackConfig.devServer.port = port

            // Add FriendlyErrorsPlugin
            devWebpackConfig.plugins.push(
                new FriendlyErrorsPlugin({
                    compilationSuccessInfo: {
                        messages: [
                            `Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`].notes: []},clearConsole: true
                })
            )

            resolve(devWebpackConfig)
        }
    })
})
Copy the code

File copy

Copy the files from the public file to the dist file

yarn add copy-webpack-plugin -D
Copy the code

This feature is only used for packaging, so we add the following code to webpack.prod.conf.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const webpackConfig = merge(baseWebpackConfig, {
    / /...
    plugins: [
        new CopyWebpackPlugin({
            patterns: [{from: resolve('public'),
                    to: '/'.globOptions: {
                        dot: true.gitignore: true}}}])/ /...]})Copy the code

gzip/bundleAnalyzerReport

Whether a file is gzip compressed and whether a package report is generated is also used only when the package is added first

yarn add compression-webpack-plugin webpack-bundle-analyzer -D
Copy the code

We then add the following code to webpack.prod.conf.js

const config = require('./config')
const webpackConfig = merge(baseWebpackConfig,{/ /... })
if (config.build.productionGzip) {
    const CompressionWebpackPlugin = require('compression-webpack-plugin')

    webpackConfig.plugins.push(
        new CompressionWebpackPlugin({
            asset: '[path].gz[query]'.algorithm: 'gzip'.test: new RegExp('\ \. (' + config.build.productionGzipExtensions.join('|') + '$'),
            threshold: 10240.minRatio: 0.8}}))if (config.build.bundleAnalyzerReport) {
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
    webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig
Copy the code

Automatically introduce environment variables

In vue-CLI, we can specify environment variables by placing the following files in the project root directory

.env                Load in all environments
.env.local          # is loaded in all environments, but ignored by Git
.env.[mode]         Is loaded only in the specified mode
.env.[mode].local   # is only loaded in the specified mode, but is ignored by Git
Copy the code

This functionality is mainly implemented through the dotenv package, which we will add to the project as well

yarn add dotenv fs-extra -D
Copy the code

Add the loadEnvDefine method to the page

const fs = require('fs-extra')
const path = require('path')
exports.loadEnvDefine = (mode) => {
    const envDefine = {}
    if (fs.existsSync(`.env.${mode}`)) {
        require('dotenv').config({ path: `.env.${mode}` })
        const prefixRE = /^VUE_APP_/
        const envDefine = {}
        for (const key in process.env) {
            if (key == 'NODE_ENV' || key == 'BASE_URL' || prefixRE.test(key)) {
                envDefine[key] = JSON.stringify(process.env[key])
            }
        }
    }
    return envDefine
}
Copy the code

Introduce this method in the webpack.base.conf.js file and register it globally via DefinePlugin

const { loadEnvDefine } = require('./utils')
const webpack = require('webpack')
module.exports = {
    / /...
    plugins: [
        / /... .
        new webpack.DefinePlugin({
            'process.env': { ...loadEnvDefine(process.env.NODE_ENV) }
        })]
}
Copy the code

conclusion

Well, our project can be said to be built here, basically realized most of the functions provided by VUE-CLI, if you have any questions or suggestions, welcome to leave a message to exchange ~