要实现多页面应用 web 我们需要注意几点,首先我们要明白多页应用:

  • 多入口 entry
  • 多页面 html
  • 每个页面不同的 chunk
  • 每个页面不同的参数

实现多页面有两种方式

  • 多配置(webpack3.1.0)
    • parallel-webpack
  • 单配置

多配置

  • 优点
    • 可以使用 parallel-webpack 来提高打包速度
    • 配置更加独立,灵活
  • 缺点
    • 不能多页面之间共享代码(不能提取公用代码)

单配置

  • 优点
    • 共享各个 entry 之间的公用代码
  • 缺点
    • 打包速度比较慢
    • 输出的内容比较复杂

多页面多配置

// parallel-webpack并行处理

parallel-webpack
parallel-webpack --watch
parallel-webpack --config

以下面项目结构为例

├── src
│   ├── components
│   │   └── module.js
│   ├── css
│   │   ├── a.css
│   │   ├── b.css
│   │   └── c.css
│   ├── pages
│   │   ├── a.js
│   │   ├── b.js
│   │   └── c.js
│   └── index.html
├── webpack.config.js
├── package.json
└── README.md

基本配置

同时每个页面都引入了 react 公共模块

// webpack.config.js

const merge = require('webpack-merge')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpack = require('clean-webpack-plugin')
const path = require('path')

const baseConfig = {
  entry: {
    react: 'react'
  },

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[chunkhash].js'
  },

  plugins: [
    new CleanWebpack(path.resolve(__dirname, 'dist')),

    new webpack.optimize.CommonsChunkPlugin({
      name : 'react',
      minChunks: Infinity
    })
  ]
}

我们把多页面配置抽离出来封装

// webpack.config.js

const generatePage = function ({
  title = '',
  entry = '',
  template = './src/index.html',
  name = '',
  chunks = []
} = {}){
  return {
    entry,
    plugins: [
      new HtmlWebpackPlugin({
        chunks,
        template,
        filename: name + '.html'
      })
    ]
  }
}

const pages = [
  generatePage({
    title: 'page a',
    entry: {
      a: './src/pages/a'
    },
    name: 'a',
    chunks: ['react', 'a']
  }),

  generatePage({
    title: 'page b',
    entry: {
      b: './src/pages/b'
    },
    name: 'b',
    chunks: ['react', 'b']
  }),

  generatePage({
    title: 'page c',
    entry: {
      c: './src/pages/c'
    },
    name: 'c',
    chunks: ['react', 'c']
  })
]

module.exports = pages.map(page => merge(baseConfig, page))

同时再抽离 css 模块

// webpack.config.js

const ExtractTextWebpack = require('extract-text-webpack-plugin')

{
  module: {
    rules: [
      {
        text: /\.css$/,
        use: ExtractTextWebpack.extract({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      }
    ]
  },

  plugins: [
    new ExtractTextWebpack({
      filename: 'css/[name].[hash].css'
    })
  ]
}

打包之后可以看到 dist 目录下,css,js,html 都已经划分好,但是会发现 react 模块被生成多次


这里可以使用 parallel-webpack 并行打包提升打包速度。如果是在全局安装的,可以直接调用 parallel-webpack 进行打包,如果是局部安装,我们需要在 node_modules 里找到 parallel-webpack 调用

node_modules/parallel-webpack/bin/run.js

多页面单配置

我们只需要在多配置基础上稍作修改

// webpack.config.js

module.exports = pages.map(page => merge(baseConfig, page))

// 改为

module.exports = merge([baseConfig].concat(pages))

这样我们就把所有配置都 merge 到一个配置里做打包


从打包结果可以很清晰的看到,react 模块只打了一个包,但是在 html 中我们发现 title 属性并没有  传过去。HtmlWebpackPlugin 默认使用 ejs 模板语法传参,我们修改下 html

// inex.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>

</body>
</html>

这样参数就可以传过去了。以上就是 webpack 多页应用的配置