In most cases, we use the webpack sheet to package applications, this time only need to configure an entry, a template file, but also is so, sometimes encounter many page of the project, and in my experience, the frequency of the problem is not low, such as project is bigger, to the assurance of global, Or if the project requires multiple iterations, it is suitable for multipage applications, which involves the packaging and configuration of webPack’s multipage files.


Manual configuration

The webPack configuration files for single-page applications and multi-page applications are mostly the same, but the multi-page configuration needs to take into account multiple pages in addition to the single-page configuration. Loader, output, and plugins basically do not need to be changed. If you’re using the extract-text-webpack-plugin and the autotemplate html-webpack-plugin, you’ll need to make additional changes to both of them. In most cases, we only need to make these three changes. Therefore, this article will only briefly talk about these three positions. If there are other places that need to be changed in the actual project, please refer to these three positions.

The example file directory is as follows:

entry

The entry configuration for a single-page application is typically as follows:

entry: resolve(__dirname, "src/home/index.js")
Copy the code

This configuration specifies that webpack starts with the/SRC /home/index.js file and starts with the package compilation process.

If it is a multi-page application, multiple entry files are required, such as:

entry: {
  home: resolve(__dirname, "src/home/index.js"),
  about: resolve(__dirname, "src/about/index.js")}Copy the code

In this way, the entire project has two entrances, home and About

extract-text-webpack-plugin

The extract-text-webpack-plugin is used to remove CSS styles and prevent them from loading incorrectly or causing javascript scripts to be too large. In a single-page application, the plugin is usually used as follows:

plugins: [
	new ExtractTextPlugin('style.[contenthash].css')]Copy the code

In a multi-page application, there are multiple entry files and corresponding pages, each page has its own CSS style, so you need to configure each page separately:

plugins: [
	new ExtractTextPlugin('home/[name].[contenthash].css'),
	new ExtractTextPlugin('about/[name].[contenthash].css')]Copy the code

It is also important to note that each page only needs its own CSS style. It is theoretically possible to package CSS files from other pages into your own page, but it is obviously not reasonable. It only adds redundant code and may lead to unpredictable style overwrites. Therefore, the following loader configuration needs to be modified:

{ test: /\.css$/, loader: 'style! css! autoprefixer' }, { test: /\.scss$/, loaders: [ 'style', 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]', 'sass', 'autoprefixer' ] },Copy the code

The configuration above will pack all compiled CSS files into one file. What we need to do is to separate the CSS files so that each page has its own CSS style file:

// Define an ExtractTextPlugin for each page
const homeExtractCss = new ExtractTextPlugin('home/[name].[contenthash].css')
const aboutExtractCss = new ExtractTextPlugin('about/[name].[contenthash].css')
// ...
module: {
    rules: [
      // The ExtractTextPlugin for each page only handles the style file for that page
	  {
        test: /src(\\|\/)home(\\|\/)css(\\|\/).*\.(css|scss)$/.use: homePageExtractCss.extract({
          fallback: 'style-loader'.use: ['css-loader'.'postcss-loader'.'sass-loader']})}, {test: /src(\\|\/)about(\\|\/)css(\\|\/).*\.(css|scss)$/.use: salePersonalCenterExtractCss.extract({
          fallback: 'style-loader'.use: ['css-loader'.'postcss-loader'.'sass-loader']})}]}// ...
Each page has its own ExtractTextPlugin, so you need to declare them all
plugins: [
    homeExtractCss,
    aboutExtractCss
]
Copy the code

html-webpack-plugin

Does the use of htmL-Webpack-plugin make any difference in webPack configuration between a single-page application and a multi-page application

new HtmlWebpackPlugin({
   filename: 'home/home.html',
   template: 'src/home/html/index.html',
   inject: true,
   minify: {
       removeComments: true,
       collapseWhitespace: true
   }
 })
 new HtmlWebpackPlugin({
   filename: 'about/about.html',
   template: 'src/about/html/index.html',
   inject: true,
   minify: {
       removeComments: true,
       collapseWhitespace: true}})Copy the code

If you have several pages, do the above configuration for each page.


Automatic configuration

The above configuration code can meet the requirements of multi-page development, but there seems to be a pity, that is, every additional page, need to update the configuration of entry, extract-text-webpack-plugin, HtmlWebpackPlugin, although only a few lines of code problem. And basically is not difficult to copy and paste, but after all the code no matter how little also need to ask, and need to change more places, in a hurry may miss, if you can once and for all, write a code, no matter after the page does not need to ask.

A brief look at the directory shows that the directory structure is quite regular:

Each page is a folder in the SRC/directory. This folder has two subdirectories, one for the page’s template HTML, one for the style file CSS, and one for the entry file index.js

If every page is a directory under./ SRC and the directory is the same structure, then all the page names (e.g., home, About) can be obtained in a common way. An example of this generic method is as follows:

function getEntry () {
  let globPath = 'src/**/html/*.html'/ / (\ | \ \ \ \) this kind of writing is to compatible with Windows and MAC system directory path different writinglet pathDir = 'src(\/|\\\\)(.*?) (\/|\\\\)html'
  let files = glob.sync(globPath)
  let dirname, entries = []
  for (let i = 0; i < files.length; i++) {
    dirname = path.dirname(files[i])
    entries.push(dirname.replace(new RegExp(A '^' + pathDir), '$2'))}return entries
}
Copy the code

With the help of the glob library, you can walk through the subdirectories in the.src/ directory that have the pattern SRC /**/ HTML /*.html, and match the name of the subdirectory with the regular pattern

Now that you have all the page names, it’s easy to do.

entry

// entry: resolve(__dirname, "src/home/index.js")
/ / to
entry: addEntry()
/ /...
function addEntry () {
  let entryObj = {}
  getEntry().forEach(item= > {
    entryObj[item] = resolve(__dirname, 'src', item, 'index.js')})return entryObj
}
Copy the code

extract-text-webpack-plugin

// plugins: [
	// new ExtractTextPlugin('home/[name].[contenthash].css'),
	// new ExtractTextPlugin('about/[name].[contenthash].css')
/ /]
/ / to
const pageExtractCssArray = []
getEntry().forEach(item= > {
  pageExtractCssArray.push(new ExtractTextPlugin(item + '/[name].[contenthash].css'))})// ...
plugins: [...pageExtractCssArray]
Copy the code

The two loaders associated with the module.rules style are removed and dynamically added instead:

getEntry().forEach((item, i) => {
  webpackconfig.module.rules.push({
    test: new RegExp('src' + '(\ \ \ \ | \ /)' + item + '(\ \ \ \ | \ /)' + 'css' + '(\ \ \ \ | \ /)' + '.*\.(css|scss)$'),
    use: pageExtractCssArray[i].extract({
      fallback: 'style-loader',
      use: ['css-loader'.'postcss-loader'.'sass-loader']})}) //... module.exports = webpackconfigCopy the code

html-webpack-plugin

Instead of manually initiating the HTmL-webpack-plugin in your plugins, add it dynamically:

getEntry().forEach(pathname => {
  let conf = {
    filename: path.join(pathname, pathname) + '.html',
    template: path.join(__dirname, 'src', pathname, 'html'.'index.html')
  }
  webpackconfig.plugins.push(new HtmlWebpackPlugin(conf))
})
// ...
module.exports = webpackconfig
Copy the code

With these changes in place, you don’t need to manually modify the WebPack configuration to add or remove pages from your project, which may seem like a lot of code and a little bit more complex at first, but in the long run, it’s definitely a good idea.

In addition, if your project has a different directory structure than the one IN my example, you may need to make a few changes to the code based on your own directory structure, but the overall approach to the problem remains the same. For an easy to maintain project, the directory structure should be consistent.