Webpack is widely used in single-page packaging, with numerous scaffoldings led by create-React-app. Single-page packaging usually packs business JS and CSS into the same HTML file. There is only one HTML file entry for the whole project, but many businesses require different entries for multiple pages. The Webpack-React-multi-Page architecture allows you to implement a multi-page architecture, ensuring that every page can be hot updated and packaged with a clear file hierarchy during project development.

Making the address

The project architecture

Technology USES

  • react16
  • webpack4
    • Html-webpack-plugin generates HTML files
    • Mini-css -extract- Plugin CSS separate package
    • Uglifyjs webpack - plugin js compressed
    • Optimize the CSS - assets - webpack - plugin CSS compression
  • es6
  • babel
  • node
    • Opn Opens the browser
    • Compression Enables Gzip compression
    • express
  • git

The directory structuregithub

| - webpack - react - multi - page / / project | | - dist / / compile production directory - index | -- index. CSS | -- index. Js | - about | -- about. CSS | - About. Js | | - images - index. HTML. | - about HTML | - node_modules / / the node package | - SRC/directory/development | - | - index/packaging/index page entry Images / | -- app. Js / / js | -- index. The index business SCSS | -- index. Js/js/index page entry | - about packaging / / the about page entry / | - | - images App. Js / / js | -- index. The about business SCSS | -- index. Js / / js entrance the about page | -- template. | - HTML / / HTML template style. The SCSS / / public SCSS | - WebpackConfig / / use in webpack | -- getEntry. Js / / to get entry | -- getFilepath. Js / / traverse folder | -- htmlconfig. Js / / | - each page HTML injection data Package. The json. | - gitignore | -- webpack. Config. Js / / webpack configuration file | - HTTP: / / www.js / / production start the programCopy the code

wiki

Webpack single-page packaging configuration

webpack.config.js

module.exports = (env, argv) => ({
    entry: ".src/index.js",
    output: {
        path: path.join(__dirname, "dist"),
        filename: "bundle.js"}, module: { rules: [ ... ] , }, plugins: [ new HtmlWebpackPlugin({ title:"Home page",
    	    filename:"index.html",
    	    favicon:"", 
    	    template: "./src/template.html",]}}));Copy the code

This will pack up a file like the one below in the dist folder

<! DOCTYPE html> <html lang="en"</title> <body> <div id="root"></div>
        <script type="text/javascript" src="bundle.js"></script>
    </body>
</html>

Copy the code

Webpack multi-page packaging configuration

Webpack entry supports two formats

Packaging a single file

module.exports = {
    entry: '.src/file.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'}};Copy the code

Bundle up a bundle.js under dist

Package out multiple files

module.exports = {
    entry: {
        index:"./src/index.js",
        about:"./src/about.js"
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'}};Copy the code

Above, two files, index.js and abou.js, corresponding to the entry attribute name, are packaged under dist

Mount each JS to the appropriate HTML file

We need to use the html-webpack-plugin webpack plugin to add a new HtmlWebpackPlugin({….) to the plugins every time a page is added })

const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = (env, argv) => ({
    entry: {
        index:"./src/index.js",
        about:"./src/about.js"
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'}... // Plugins: [new HtmlWebpackPlugin({filename:"index.html"// Generate index.html template:"./src/template.html"}) // chunks:["index"]
            }),
	new HtmlWebpackPlugin(
            {
                filename:"about.html"// Generate index.html template:"./src/template.html"}) // chunks:["about"]]}}))Copy the code

The html-webpack-plugin will generate an HTML file named filename from the template. HTML template and package it into the corresponding folder in output. Note that all packaged files are corresponding to the path directory in Output, including HTML. The chunks here are important to note that it determines which JS should be introduced in the HTML. If not, the default is to introduce all packaged JS, which is not what we want.

The above configuration will eventually package the following file structure under DIST

| - dist. | - index js | -- about. Js | -- index. Within HTML / / mount index, js | -- about. Within HTML / / mount the about, jsCopy the code

Through the above configuration, plus devServer, we can already achieve multi-page configuration development, but this is not smart, because every time you add a page, you have to configure it in Wepback, which will be very tedious, so let’s optimize, let’s just focus on the development of the page, the configuration to Webpack.

Webpack multi-page configuration optimization

Let’s look at the file structure under SRC

|-- src
    |-- index
        |-- app.js
        |-- index.scss
        |-- index.js
    |-- about
        |-- app.js
        |-- index.scss
        |-- index.js
Copy the code

Each folder below SRC corresponds to the JS business of an HTML page. If we directly find the corresponding entry JS of the folder and merge them to generate the corresponding entry, is there no need to write entry manually? Yes

  • getEntry.js
/* eslint-env node */ ** * @project: get entry * @author: leinov * @date: 2018-10-11 */ const fs = require("fs"); /** * @param {String} path * @returns {Object} Return entry {"about/aoubt":"./src/about/about.js". } */ module.exports =function getEnty(path){
    let entry = {};
    letexistpath = fs.existsSync(path); // Whether a directory existsif(existpath){
	letreaddirSync = fs.readdirSync(path); Readdirsync.map ((item)=>{let currentPath = `${path}/${item}`;
	    letisDirector = fs.statSync(currentPath).isDirectory(); // Check if it is a folderif(isDirector && item ! = ="component"/** * the following output format is {"about/about":".src/aobout/index.js"} * The purpose is to pack js into the corresponding folder */ entry['${item}/${item}`] = `${currentPath}/index.js`; }});returnentry; }};Copy the code

Use getEntry in webpack

const getEntry = require("./webpackConfig/getEntry");
const entry = getEntry();

module.exports = (env, argv) => ({
    entry: entry,
})

Copy the code

So we get the entry automatically

HTML – webpack – plugin configuration

Since each page needs to be configured with an HTML, we also use the fs module to get the directory under SRC and iterate through the HTML -webpack-plugin

  • getFilepath.js
/* eslint-env node */ ** * @project: /* @author: leinov * @date: 2018-10-11 */ const fs = require("fs"); ** @param {String} path path * @returns {Array} ["about"."index"]
 */
module.exports = function getFilePath(path){
    let arr = [];
    letexistpath = fs.existsSync(path); // Whether a directory existsif(existpath){
	letreaddirSync = fs.readdirSync(path); Readdirsync.map ((item)=>{let currentPath = path + "/" + item;
	    letisDirector = fs.statSync(currentPath).isDirectory(); // Check if it is a folderif(isDirector){ arr.push(item); }});returnarr; }};Copy the code
  • htmlconfig.js
/** * @author:leinov * @date: 2018-10-09 */ module.exports={index:{title:"Home page"// filename:"index.html",
	template: "./src/template.html",  
        chunks:["index/index"],
    },
    about:{
	title: "About page"// filename:"about.html",	
        template: "./src/template.html", 
	chunks:["about/about"]}};Copy the code

The final configuration of webpack through the above series of packages is as follows

const HtmlWebpackPlugin = require("html-webpack-plugin");
const getEntry = require("./webpackConfig/getEntry");
const getFilePath = require("./webpackConfig/getFilepath");
const htmlconfig =require("./webpackConfig/htmlconfig");

const entry = getEntry("./src"); const htmlarr=[]; // Inject the HTML template getFilePath("./src").map(pathname => {
	htmlarr.push(new HtmlWebpackPlugin(htmlconfig[pathname]));
});

module.exports = (env, argv) => ({
    entry: entry
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'}... DevServer: {port: 3100, open:true,
    },
    plugins: [
        ...htmlarr
    ]
})
Copy the code

This completes a complete multi-page architecture configuration, refer to the project code for the complete code