3

webpack一般是配合单页面应用使用,但并不是所有的web应用都是单页的,有多个页面的情况还是很多的,当然你可以用其它的构建工具来打包,但对于习惯了webpack的你来说,要是能直接在webpack上做少许配置就可以支持多页面的打包构建,岂不乐哉!

准备工作

  • webpack已安装
  • webpack-dev-server已配置
  • js、css、图片、字体等的loader都已配置完毕

多页HTML处理

既然是多页面,也就是说有多个HTML页面需要处理,而且得根据对应的HTML页面,打包对应页面的业务逻辑代码。比如我们最后想要的打包目录结构是这样的:
image

我们有三个页面,login.html、index.html、crop.html,我们分别打包出对应的css文件login.css、index.css、crop.css,且js也是如此的打包,可以看一下最后输出的index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>index-page</title>
    <link href="/css/index.css" rel="stylesheet">
</head>
<body>
    <header><nav></nav></header>
    <div class="container-fluid index-page">
       <div class="ocr-wrapper">
          <div class="jumbotron">
              <h1>Hello World!</h1>
              <p>这是一个多页面的webpack配置demo</p>
          </div>
      </div>
   </div>
   <footer class="footer"></footer>
   <script type="text/javascript" src="/js/vendors.min.js"></script><script type="text/javascript" src="/js/index.min.js"></script>
</body>
</html>

index.html自动插入对应的index.css、index.min.js和公共库代码vendors.min.js。

为了实现这个目的,我们把我们的src目录作如下组织:
image

template文件夹中放置html的模板页面,这里配合html-withimg-loader还可以实现模板的拆分:

<!DOCTYPE html>
<html>
<head>
    #include("./layout/meta.html")
    <title>crop-page</title>
</head>
<body>
#include("./layout/header.html")
<div class="container-fluid">
    <div class="ocr-wrapper">
        <div class="jumbotron">
            <img src="../imgs/picture.jpg" alt="Picture" draggable="false">
        </div>
    </div>
</div>
#include("./layout/footer.html")
</body>
</html>

view文件夹则放置每个页面的入口文件,在入口文件里加载一些必要的资源:

import $ from 'jquery';
import 'bootstrap';

import 'bootstrap/dist/css/bootstrap.min.css';
import '../css/index.css';

$(function () {
    console.log('index page');
});

根据我们的目录结构,我们需要一个方法来得到entry和文件的对应关系,我们引入模块blob,实现如下方法:

// 获取指定路径下的入口文件
function getEntries(globPath) {
    var files = glob.sync(globPath),
        entries = {};

    files.forEach(function(filepath) {
        // 取倒数第二层(view下面的文件夹)做包名
        if(filepath.match(/\.js$/)){
            var split = filepath.split('/');
            var fileName = split[split.length - 1];
            var name = fileName.substring(0, fileName.length - 3);
            entries[name] = './' + filepath;
        }
    });

    return entries;
}

然后dev模式下,我们需要在entry里设置dev-server和hot-reload,所以我们配置里的entry应该是一个数组,同时,我们还得为每一个html页面都插入对应的资源:

var entries = getEntries('src/view/**');

webpackConfig.entry.push('webpack-dev-server/client?http://0.0.0.0:8090');
webpackConfig.entry.push('webpack/hot/only-dev-server');

Object.keys(entries).forEach(function(name) {
    // 每个页面生成一个entry,如果需要HotUpdate,在这里修改entry
    webpackConfig.entry.push(entries[name]);

    // 每个页面生成一个html
    var plugin = new HtmlWebpackPlugin({
        // 生成出来的html文件名
        filename: name + '.html',
        // 每个html的模版,这里多个页面使用同一个模版
        template: './src/template/'+ name +'.html',
        // 自动将引用插入html
        inject: true
    });
    webpackConfig.plugins.push(plugin);
});

prod模式下,我们的entry应该是一个对象,并为每个入口添加注入对应的资源,由此我们得作如下配置:

var entries = getEntries('src/view/**');

Object.keys(entries).forEach(function(name) {
    webpackConfig.entry[name] = entries[name];

    // 每个页面生成一个html
    var plugin = new HtmlWebpackPlugin({
        // 生成出来的html文件名
        filename: name + '.html',
        // 每个html的模版,这里多个页面使用同一个模版
        template: './src/template/'+ name +'.html',
        // 自动将引用插入html
        inject: true,
        // 每个html引用的js模块,也可以在这里加上vendor等公用模块
        chunks: ['vendors', name]
    });
    webpackConfig.plugins.push(plugin);
});

webpackConfig.entry['vendors'] = ['jquery', 'bootstrap'];

这样,我们的多页面配置就搞定了,只需在单页的基础上,对entry做一些处理即可,改动并不算太多吧!


默凡
1.3k 声望239 粉丝

知行合一,天道酬勤