Not long ago, I wrote a Webpack multi-page boilerplate(Webpack 4-Boilerplate) from scratch, which is convenient for future work out of the box. We hereby record the key points in the development process.

Note: This article does not cover the basics of WebPack in detail, but if not at all, I recommend checking out the basics I wrote earlier

  • Build a simple VUE development environment based on WebPack from scratch
  • Build a simple WebPack-based React development environment from scratch

Reasons for multi-page packaging

Let’s start with a soul-searching question: Why multiple pages?

React: NPM run dev NPM run build

However, the reality is that in many scenarios, the single-page application development model does not work. For example, companies often develop activity pages: https://www.demo.com/activity/activity1.html https://www.demo.com/activity/activity2.html https://www.demo.com/activity/activity3.html

The above three pages are completely unrelated active pages, and there is no data shared between the pages. However, each page uses the React framework, and all three pages use a common popbox component. In this scenario, the WebPack multi-page packaging solution is needed:

  1. Keep the traditional single-page app development model: Use Vue, React and other front-end frameworks (jQuery is also available), support modular packaging, and you can treat each page as a single single-page app
  2. Standalone deployment: Each page is independent and can be deployed separately, decoupling the complexity of the project, and you can even choose different technology stacks on different pages

Therefore, we can think of multi-page apps as beggars’ version of front-end microservices.

Principle of multi-page packaging

First we agreed: SRC /pages directory, each folder is a separate page. Each page has at least two file configurations:

  • App.js: logical entry to the page

  • Index.html: HTML packaging template for a page

SRC/pages ├ ─ ─ page1 │ ├ ─ ─ app. Js │ ├ ─ ─ index. The HTML │ ├ ─ ─ index. The SCSS └ ─ ─ page2 ├ ─ ─ app. Js ├ ─ ─ index. The HTML └ ─ ─ index. The SCSSCopy the code

As we said earlier, each page can be viewed as a single page application.

How are single-page apps packaged? A single page application is configured by entry to the Webpack

module.exports = {
  entry: './src/main.js'.// The project entry file, webpack will start from main.js and load and pack all dependent JS files
  output: {
      path: path.resolve(__dirname, './dist'), // The package file path of the project
      filename: 'build.js' // The packaged file name}};Copy the code

Therefore, multi-page applications only need to configure multiple entries

module.exports = {
  entry: {
    'page1': './src/pages/page1/app.js'./ / page 1
    'page2': './src/pages/page2/app.js'./ / page 2
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'js/[name]/[name]-bundle.js'.// Filename cannot be written to death. You can only get the bundle name from [name]}}Copy the code

At the same time, multiple HTMLWebPackPlugins need to be configured because the index. HTML templates of multiple pages are different.

Note: HtmlWebpackPlugin must have chunks, otherwise the JS of all pages will be injected into the current HTML

module.exports = {
  plugins: [
    new HtmlWebpackPlugin(
    {
      template: './src/pages/page1/index.html'.chunks: ['page1'],}).new HtmlWebpackPlugin(
    {
      template: './src/pages/page2/index.html'.chunks: ['page2'],}),]}Copy the code

The principle of multi-page packaging is to configure multiple pagesentryAnd multipleHtmlWebpackPlugin

Details of multi-page packaging

The code segment

  1. Package third-party libraries (such as React,Fastclick) that are shared by multiple pages into a separate packagevendor.js
  2. Package logical code shared by multiple pages and global CSS (such as CSS-reset,icon font ICONS) separatelycommon.jsandcommon.css
  3. Separate out the runtime codemanifest.js
  4. Package each page with its own business codepage1.jsandpage1.css

The first three items are common files introduced by each page, and the fourth item is a separate file for each page.

The implementation is also very simple, configuration optimization can be:

module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        // Package common code in the business
        common: {
          name: "common".chunks: "initial".minSize: 1.priority: 0.minChunks: 2.// Use two references before packing
        },
        // Package third-party library files
        vendor: {
          name: "vendor".test: /[\\/]node_modules[\\/]/.chunks: "initial".priority: 10.minChunks: 2.// Use two references before packing}}},runtimeChunk: { name: 'manifest' } // Runtime code}}Copy the code

hash

Finally, we want to pack the file with a hash value so that we can make full use of the browser cache. Webpack has hash, chuckhash, Contenthash: In production environments, we usually use contenthash, whereas development environments do not specify hash.

// dev environment
module.exports = {
  output: {
    filename: 'js/[name]/[name]-bundle.js'.chunkFilename: 'js/[name]/[name]-bundle.js',}}// ProD production environment
module.exports = {
  output: {
    filename: 'js/[name]/[name]-bundle.[contenthash:8].js'.chunkFilename: 'js/[name]/[name]-bundle.[contenthash:8].js',}}Copy the code

The mock and proxy

Development environments typically require mock data, as well as proxy apis to the server. We can use devServer with mocker-API third-party library implementation.

const apiMocker = require('mocker-api');

// dev environment
module.exports = {
  devServer: {
    before(app) { // Local mock data
      apiMocker(app, path.resolve(__dirname, '.. /mock/index.js'))},proxy: { // Proxy interface
      '/api': {
        target: 'https://anata.me'.// the backend callback address
        changeOrigin: true.secure: false,},}},}Copy the code

Split the WebPack configuration

For general configuration, split the WebPack configuration file into three parts.

Build ├ ─ ─ webpack. Base. Js / / common part ├ ─ ─ webpack. Dev. Js / / dev └ ─ ─ webpack. Prod. Js / / productionCopy the code

The main differences between dev and PROd configurations:

  • devconfigurationdevServerTo facilitate local debugging and development
  • prodPackage compressed files, extract CSS separately (dev does not extract for CSS hot updates), and generate static resource listsmanifest.json

I’ll cover why a manifest.json is generated and how the packaged code is deployed in the next article.