- 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.
- 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:
// htmlarrary.js
module.exports = [
{
_html: 'index'.title: 'home'.chunks: ['index'.'manifest'.'vendors'] // The vendor module used by the page
},
{
_html: 'login'.title: 'login'.chunks: ['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 configuration required by HtmlWebpackPlugin according to the template configuration
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: true./ / open the hash
chunks, // The package to import from the page
minify: process.env.NODE_ENV === 'development' ? false : {
removeComments: true.// Remove comments from HTML
collapseWhitespace: true.// Folding white space is the same as compressing code
removeAttributeQuotes: true.// Remove attribute references}}; };// Loop to create template configurations
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 = {
/ /... The related configuration
}
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 = {}
// Read all page entries in the SRC directory
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
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:
- Eslint error alerts;
- Ts-loader parses typescript syntax;
- 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 packaging 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 = {
optimization: {
minimizer: [
// This will cause sourcemap to disappear
new UglifyJsPlugin({
uglifyOptions: ({
compress: false})}),new OptimizeCSSAssetsPlugin({})
],
splitChunks: {
chunks: 'all'.cacheGroups: {
vendors: { // Remove third-party plugins
test: /[\\/]node_modules[\\/]/.// specify a third-party package under node_modules
name: 'vendors'.priority: - 10 // Extract the priority
},
utilCommon: { // Remove custom
name: 'common'.minSize: 0.// The minimum size to separate reference modules into new code files
minChunks: 2.// Indicates how many times to reference modules such as different files before separating and generating new chunks
priority: - 20}}},/ / optimization. RuntimeChunk is tell webpack if we need to separate packaging, this part 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:
- Postcss-loader Installs the autoprefixer plug-in for automatic compatibility processing.
- Sass-loader parses sASS syntax;
- 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.assign(
/ / production environment compress CSS needs to use MiniCssExtractPlugin. Replace style - loader loader
{ loader: process.env.NODE_ENV === 'production' ? MiniCssExtractPlugin.loader : 'style-loader' },
// Solve the problem that CSS images cannot be displayed properly after compiling
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:
- Images in CSS and JS can be parsed;
- 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: /\.html$/.use: [
// If the SRC of the img tag is empty, an error is reported.
{
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 code, please find the official website documentation.
An error
- If the SRC of the img tag is empty, an error is reported.
- 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. - After compiling CSS image path error, according to whether the production environment to dynamically add
publicPath
.Click here to.