1. I recently had a project to make a multi-page app for SEO purposes. In order to ensure the speed and efficiency of development, we decided to use Webpack to make a modular configuration scheme.
  2. The following are mainly for some important points to provide ideas, not in detail. Complete code, I will put on Github (project address) for your reference, if there is optimization, please point out in the comment area.

directory

| | - build webpack configuration | -- utils. Js processing webpack configuration of public methods | | -- webpack. Base. Conf., js common configuration | | -- webpack. Dev. Conf., js development environment configuration . | | - webapck prod. Conf. Js production environment configuration | | -- webpack. Rules. Conf. | js file handling rules - dist where mutated files | -- - | | - SRC the source file | | - assets | | - pages | | | - the index page | | | | -- index. HTML page template | | | | -- index. | js page entry documents htmlarrary. Js page configuration fileCopy the code

Multiple page

Multi-page, the first and most important is to handle multiple HTML templates and corresponding multiple entry files.

HTML template

Create a htmlarry.js file in the project root directory to store the page configuration:

// htmlarlary.js module.exports = [{_html: 'index', title: 'home ', chunks: ['index', 'manifest', 'vendors'] // Vendor modules used by the page}, {_html: 'login', title: 'login', vendors: ['login']}]Copy the code

Then create the getHtmlArray method at /build/utils.js to automatically generate multiple template configurations:

// /build/utils.js const HtmlWebpackPlugin = require('html-webpack-plugin') const htmlArray = require('.. /htmlarray.js') exports.gethtmlarray = function (moduleExportsPlugins) {// Generate the required configuration of HtmlWebpackPlugin const getHtmlConfig = function (name, chunks, title) { return { template: `./src/pages/${name}/index.html`, filename: `./${name}.html`, favicon: './src/assets/images/public/favicon.ico', title, inject: true, hash: Minify: process.env.node_env === 'development'? CollapseWhitespace: true // CollapseAttributequotes: True, // Remove attribute references},}; }; Htmlarray.foreach ((element) => {const {_html, chunks, title } = element moduleExportsPlugins.push(new HtmlWebpackPlugin(getHtmlConfig(_html, chunks, title))) }) }Copy the code

Add multi-page engine configuration via getHtmlArray in webpack.base.conf.js:

const { getHtmlArray } = require('./utils.js') module.exports = { // ... } getHtmlArray(module.exports.plugins)Copy the code

Entrance to the file

Create the getEntry method at /build/utils.js to automatically generate the configuration of the entry file:

// /build/utils.js const glob = require('glob') exports.getentry = function () {const entry = { glob.sync('./src/pages/*/*.js').forEach((name) => { const start = name.indexOf('src/') + 4; const end = name.length - 3; const eArr = []; const n = name.slice(start, end).split('/')[1]; eArr.push(name); eArr.push('@babel/polyfill'); // This is introduced to use async await, some properties not supported by IE can be supported, compatible with IE browser entry[n] = eArr; }) return entry; }Copy the code

Add multi-entry configuration via getEntry in webpack.base.conf.js:

// webpack.base.conf.js

const { getEntry } = require('./utils.js')

module.exports = {
  entry: getEntry(),
}Copy the code

JS

JS, we generally have the following requirements:

  1. Eslint error alerts;
  2. Ts-loader parses typescript syntax;
  3. Babel-loader parses ES6 syntax.

For the above requirements, let’s configure the rules and make an extension:

// webpack.rules.conf.js module.exports = [ { test: /\.(js|ts)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: { presets: [ ['@babel/preset-env', { useBuiltIns: 'usage', targets: { chrome: '58', ie: '8' }, corejs: 2 }] ] } }, { loader: 'ts-loader' }, { loader: 'eslint-loader', options: { cache: True // Optimize packing speed}}]}]Copy the code

In production, we need to compress the JS files and remove the common code, so we need to optimize the webpack.prod.conf.js as follows:

// webpack.prod.conf.js cconst merge = require('webpack-merge') const UglifyJsPlugin = require('uglifyjs-webpack-plugin') const baseConfig = require('./webpack.base.conf.js') const prodConfig = { New UglifyJsPlugin({uglifyOptions: ({compress: false }) }), new OptimizeCSSAssetsPlugin({}) ], splitChunks: { chunks: 'all', cacheGroups: { vendors: {// Remove third-party plugins test: /[\\/]node_modules[\\/]/, // Specify third-party packages under node_modules name: 'vendors', priority: -10 // Extract priority}, utilCommon: {// extract custom name: 'common', minSize: 0, // Separate reference module into new code file minChunks: 2, // indicates the number of times to separate and generate new chunk priority by referencing modules such as different files: - 20}}}, / / optimization runtimeChunk is tell webpack whether to put this part of the pack out alone, to optimize the cache problem runtimeChunk: {name: 'manifest' } } } module.exports = merge(baseConfig, prodConfig)Copy the code

CSS

For CSS, we generally have the following requirements:

  1. Postcss-loader Installs the autoprefixer plug-in for automatic compatibility processing.
  2. Sass-loader parses sASS syntax;
  3. MiniCssExtractPlugin Uses CSS compression.

For the above requirements, let’s configure the rules and make an extension:

// webpack.rules.conf.js const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = [ { test: / \. SCSS $/ I use: [Object. The assign (/ / production environment compress CSS needs to use MiniCssExtractPlugin. Instead of style - loader loader {loader: process.env.NODE_ENV === 'production' ? MiniCssExtractPlugin.loader : Process.env.node_env === 'production'? {options: {publicPath: '../'}} : {} ), 'css-loader', 'sass-loader', 'postcss-loader' ] } ]Copy the code

In production, we need to compress the CSS file, so we need to optimize it in webpack.prod.conf.js like this:

// webpack.prod.conf.js

cconst merge = require('webpack-merge')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const baseConfig = require('./webpack.base.conf.js')

const prodConfig = {
  optimization: {
    minimizer: [
      new OptimizeCSSAssetsPlugin({})
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
      chunkFileName: '[id].[contenthash:8].css'
    }),
  ]
}

module.exports = merge(baseConfig, prodConfig)Copy the code

images

In terms of images, we generally have the following requirements:

  1. Images in CSS and JS can be parsed;
  2. Images of the IMG tag in HTML can be parsed.

For the above requirements, let’s configure the rules and make an extension:

// webpack.rules.conf.js const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = [ { test: XxxHTMLLINKxxx0. {loader: 'html-loader',}]}, {test: /\.(png|jpg|gif|ico)$/, use: [ { loader: 'url-loader', options: { name: '[name].[hash:8].[ext]', limit: 30000, outputPath: './images' } } ] } ]Copy the code

other

Devserver and hot updates

// webpack.dev.conf.js const devConfig = {devServer: {open: true, host: '0.0.0.0', port: 2000, useLocalIp: true, hot: true }, plugins: [ new webpack.HotModuleReplacementPlugin() ] }Copy the code

This intelligently starts CSS hot update. If you need JS hot update, you need to add a piece of code, please find it yourself
Official document.

An error

  1. If the SRC of the img tag is empty, an error is reported.
  2. If an error is reported:TS2688: Cannot find type definition file for 'unist'.Dependencies need to be installed@types/unist, other similar error, this is[email protected]An error is reported due to changing the support mode of types.
  3. After compiling CSS image path error, according to whether the production environment to dynamically addpublicPath.Click here to.