如何使用webpack构建多页面应用,这是一个我一直在想和解决的问题。网上也给出了很多的例子,很多想法。猛一看,觉得有那么点儿意思,但仔细看也就那样。

使用webpack这个构建工具,可以使我们少考虑很多的问题。

我们常见的单页面应用只有一个页面,它考虑问题,解决问题围绕着中心化去解决,因此很多麻烦都迎刃而解。如果你使用过vue.js,那么想必你一定用过vue-router,vuex,它们就是典型的中心化管理模式,当然还有很多,这里不一一列举了。

而多页面应用,我们不能再按照中心化模式的路走了,因为行不通,这也是很多人认为多页面应用不好做,或者干脆认为webapck只能做单页面应用,而不能做多页面应用的原因。

所以,我要说明的第一点儿是:不要用做单页面应用的思维来做多页面应用。

单页面中的模块共享和多页面的模块共享的区别

  1. 单页面的模块共享,其实是代码块在同一个页面的不同位置的重复出现;而多页面应用的代码块儿共享需要实现的不仅是同一个页面的共享,还要做到跨页面的共享。

    所以,第一个要解决的问题是:不同页面的代码块共享如何实现?

  2. 单页面的路由管理,其实是根据用户的触发条件来实现不同的代码块的显隐;而多页面应用的路由管理则不然,它实现的是页面的跳转。

    所以,第二个要解决的问题是:所页面应用的导航该如何做?

  3. 单页面的状态管理,很受开发者喜好。单页面是一个页面,所以页面中的数据状态的管理操作起来还算得心应手,那么多页面应用的呢,显然依靠它自身很难实现。

所以,第三个要解决的问题是:多页面应用的状态管理如何做?

注:这个问题问的其实有点儿傻,如果你做的是dom操作的多页面儿应用,就不用做状态管理了。如果你还是使用想vue.js这样的库,你就需要考虑要不要再用做多页面的状态管理了,因为此法儿就是为单页面应用做的,多页面儿行不通。

多页面应用的探索

入口(entry):

webpack对入口不仅可以定义单个文件,也可以定义多个文件。

熟悉当页面应用开发的对于下面的代码应该不会陌生吧?


module.exports = {
entry: './src/index.js',
···
}

我第一次接触真正的单页面应用项目使用的就是angualrjs,使用的构建工具使webapck+gulp,其中的webpack.config.js 中的看到的入口文件代码就是它。

后来,接触到的是数组形式,代码如下:


module.exports = {
entry: ['./src/index.js', 'bootstrap']
···
}

这样,将bootstrap和入口文件一起引用,就可以在任何一个代码块中使用boostrap。

再后来,接触到的是对象形式,代码如下:


module.exports = {
main: './src/index.js'
···
}

这样做的目的是为了给输出的文件指定特定的名字。

再后来,就是做多页面应用,就需要用到如下的代码:


module.exports = {
entry: {
index: './src/index.js',
aboutUs: './src/aboutus.js',
contactUs: './src/contactus.js'
}
}

为了引入第三方库,我们可以像如下这样做:


module.exports = {
entry: {
index: ['./src/index.js', 'loadsh'],
aboutUs: './src/aboutus.js',
contactUs: ['./src/contactus.js', 'lodash']
}
}

webpack3.x的探索

但为了共享模块代码,我们需要像下面这这样做:


const CommonsChunkPlugin = require('webpack').optimization.CommonsChunkPlugin
module.exports = {
entry: {
index: ['./src/index.js', './src/utils/load.js', 'loadsh'],
aboutUs: ['./src/aboutus.js', 'loadsh'],
contactUs: ['./src/contactus.js','./src/utils/load.js', 'lodash']
},
plugins: [
new CommonsChunkPlugin({
name: "commons",
filename: "commons.js",
chunks: ["index", "aboutUs", "contactUs"]
})
]
}

这样型就会形成如下所示的项目目录结构:

├── src
│ ├── common // 公用的模块
│ │ ├── a.js
│ │ ├── b.js
│ │ ├── c.js
│ │ ├── d.js
│ ├── uttils // 工具
│ │ ├── load.js // 工具代码load.js
│ ├── index.js // 主模块index.js (包含a.js, b.js, c.js, d.js)
│ ├── aboutUs.js // 主模块aboutus.js (包含a.js, b.js)
│ ├── contactUs.js // 主模块contactus.js (包含a.js, c.js)
├── webpack.config.js // css js 和图片资源
├── package.json
├── yarn.lock

但是这个内置插件的局限性比较大。正如上面所使用的那样,它只会提取chunks选项所匹配的模块共有的代码块。就如同上面代码表示的那样,它只会提取pindex, aboutUs, contactUs共有的代码块loadsh,而不会提取index, contactUs共有的代码块load.js

当然,一般的第三方库,我们也不这样使用,而是像下面这样使用:


const CommonsChunkPlugin = require('webpack').optimization.CommonsChunkPlugin
module.exports = {
entry: {
index: ['./src/index.js', './src/utils/load.js'],
aboutUs: ['./src/aboutus.js'],
contactUs: ['./src/contactus.js','./src/utils/load.js'],
vendors: ['lodash']
},
externals: {
commonjs: "lodash",
root: "_"
},
plugins: [
new CommonsChunkPlugin({
name: "commons",
filename: "commons.js",
chunks: ["index", "aboutUs", "contactUs"]
})
]
}

对于web应用最终的目的是:匹配生成不同的html页面。

这里我们要使用的就是html-webpack-plugin

首先,需要安装html-webpack-plugin


yarn add --dev html-webpack-plugin

然后引入插件,并配置如下:


...
const HtmlWebapckPlugin = require('html-webpack-plugin');
...
plugins: [
...
new HtmlWebapckPlugin({
filename: 'index.html',
chunks: ['vendors', 'commons', 'index']
}),
new HtmlWebapckPlugin({
filename: 'aboutUs.html',
chunks: ['vendors', 'commons', 'aboutUs']
}),
new HtmlWebapckPlugin({
filename: 'contactUs.html',
chunks: ['commons', 'contactUs']
})
],
...

这样一个基于webpack3.x的多页面框架就有了基本的样子。

webpack4.x的探索

而使用webpack4.x则完全不同,它移除了内置的CommonsChunkPlugin插件,引入了SplitChunksPlugin插件,这个插件满足了我们的需要,弥补了CommonsChunkPlugin的不足。

如果你想要解决之前的不足,去提取index, contacUs共有的模块,操作起来会很简单。正如上面的所列举的那样,我们有三个入口点index, aboutUs, contactUsSplitChunksPlugin 插件会首先获取这三个入口点共有的代码块,然后建立一个文件,紧接着获取每两个入口点的共有代码块,然后将每个入口点独有的代码块单独形成一个文件。如果你使用了第三方库,就像上面我们使用的loadsh,它会将第三方入口代码块单独打包为一个文件。

配置文件webpack.config.js需要增加如下的代码:


···
optimization: {
splitChunks: {
chunks: 'all',
maxInitialRequests: 20,
maxAsyncRequests: 20,
minSize: 40
}
}
···

因为SplitChunksPlugin可以提取任意的入口点之间的共同代码,所以,我们就不需要使用vendors入口节点了。那么,为匹配生成不同的页面代码可以修改成如下:


const HtmlWebapckPlugin = require('html-webpack-plugin')
···
plugins: [
new HtmlWebapckPlugin({
filename: 'index.html',
chunks: ['index']
}),
new HtmlWebapckPlugin({
filename: 'aboutUs.html',
chunks: ['aboutUs']
}),
new HtmlWebapckPlugin({
filename: 'contactUs.html',
chunks: ['contactUs']
}),
]
···

可以发现结果越来越接近我们所想。但是这里还是存在一个问题,第三方库loadsh因为在入口点index, aboutUs中被分别引入,但是构建的结果却输出了两个第三方库文件,这不是我们想要的。这个问题怎么解决呢,因为html-webpack-plugin插件的chunks选项,支持多入口节点,所以,我们可以再单独创建一个第三方库的入口节点vendors。配置代码修改如下:


...
entry: {
index: ['./src/index.js', './src/utils/load.js'],
aboutUs: ['./src/aboutUs.js'],
contactUs: ['./src/contactUs.js','./src/utils/load.js'],
vendors: ['loadsh']
},
...
plugins: [
new HtmlWebapckPlugin({
filename: 'index.html',
chunks: ['index', 'vendors']
}),
new HtmlWebapckPlugin({
filename: 'aboutUs.html',
chunks: ['aboutUs', 'vendors']
}),
new HtmlWebapckPlugin({
filename: 'contactUs.html',
chunks: ['contactUs']
}),
],
...

注意:如果不同的入口点儿之间有依赖关系,如上面的indexvendors之间,因为index依赖于vendors,所以vendors要置于index之前。

这篇文章,说到这里基本上已经结束了。当然,webpack多页面应用的知识点还没有讲完,这些内容会放在后续的文章中详解。

源代码

webpack3.x multi-page

webpack4.x multi-page

来源:https://segmentfault.com/a/1190000017393930

webpack 构建多页面应用的更多相关文章

  1. webpack构建多页面react项目(webpack+typescript+react)

    目录介绍 src:里面的每个文件夹就是一个页面,页面开发相关的组件.图片和样式文件就存放在对应的文件夹下. tpl:里面放置模板文件,当webpack打包时为html-webpack-plugin插件 ...

  2. 使用Webpack构建多页面程序

    使用webpack搭建单页面程序十分常见,但在实际开发中我们可能还会有开发多页面程序的需求,因此我研究了一下如何使用webpack搭建多页面程序. 原理 将每个页面所在的文件夹都看作是一个单独的单页面 ...

  3. gulp + webpack 构建多页面前端项目

    修改增加了demo地址 gulp-webpack-demo 之前在使用gulp和webpack对项目进行构建的时候遇到了一些问题,最终算是搭建了一套比较完整的解决方案,接下来这篇文章以一个实际项目为例 ...

  4. Vue2+VueRouter2+webpack 构建项目实战(三):配置路由,运行页面

    制作.vue模板文件 通过前面的两篇博文的学习,我们已经建立好了一个项目.问题是,我们还没有开始制作页面.下面,我们要来做页面了. 我们还是利用 http://cnodejs.org/api 这里公开 ...

  5. webpack搭建多页面系统(一):对webpack 构建工具的理解

    为什么使用webpack构建工具? 1.开发效率方面: 在一般的开发过程中,分发好任务后,每个人完成自己单独的页面,如果有的人开发完成之后,接手别人的任务,就有可能造成开发时候的冲突. 如果利用模块化 ...

  6. 使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&引用jquery来实现alert

    使用webstorm+webpack构建简单入门级"HelloWorld"的应用&&构建使用jquery来实现 1.首先你自己把webstorm安装完成. 请参考这 ...

  7. webpack构建vue项目(配置篇)

    最近公司要求用vue重构项目,还涉及到模块化开发,于是乎,我专门花了几天的时间研究了一下webpack这个目前来看比较热门的模块加载兼打包工具,发现上手并不是很容易,现将总结的一些有关配置的心得分享出 ...

  8. webpack构建具备版本管理能力的项目

    webpack是时下十分流行的编译和打包工具,它提供一种可扩展的loader的方式,简单的配置,便可以编译打包各类型的文件,包括js.css.image.font.html,以及各种预编译语言都不在话 ...

  9. 使用vue-cli构建多页面应用+vux(二)

    当我们安装好vue-cli完整的项目以后,我们开始对它进行改造,此处参考了简书某个作者的,附上原文链接 http://www.jianshu.com/p/43697bdee974以及此文例子地址htt ...

随机推荐

  1. [SCOI2003]字符串折叠 (区间DP)

    题目描述 折叠的定义如下: 一个字符串可以看成它自身的折叠.记作S = S X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) = SSSS…S(X个S). 如果A = A’, B = ...

  2. java面试题之hashcode相等两个类一定相等吗?equals呢?相反呢?

    答:hashcode相等,两个类不一定相等,equals也不一定相等: 反过来,equals相等,hashcode一定相等

  3. 2017NOIP初赛游记

    前天晚上,玩三国杀,玩到了昨天凌晨2点40多分吧,我觉得初赛要爆炸了, 不得不吐槽一下,三国杀的武将太少了. 昨天是初赛的日子,上午8点多来了后看了看阅读程序和程序填空,复习了以下理论知识和wsj 然 ...

  4. NAND FLASH 物理结构分析

    转自:http://blog.51cto.com/hardywang/2053915 NAND Flash是一种非易失性随机访问存储介质,基于浮栅(Floating Gate)晶体管设计,通过浮栅来锁 ...

  5. cf550D Regular Bridge

    Regular Bridge An undirected graph is called k-regular, if the degrees of all its vertices are equal ...

  6. *AtCoder Regular Contest 094 F - Normalization

    $n \leq 200000$的abc字符串,现能进行如下变换零次或若干次:选一个$i<n$且$s_i \neq s_{i+1}$,把$s_i$和$s_{i+1}$替换成abc三个字母中除了这两 ...

  7. android本地存储SharedPreferences

    SharedPreferences是Android中最容易理解的数据存储技术,实际上SharedPreferences处理的就是一个key-value(键值对)SharedPreferences常用来 ...

  8. noip2015提高组day2解题报告

    1.跳石头 题目描述 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石( ...

  9. HBASE的安装过程及运行HBASE程序的需要配置的内容

    HBase安装配置 ①下载压缩包(选择与自己安装的Hadoop版本的兼容版本,见后面附录) 官网下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/hba ...

  10. BUPT复试专题—旋转图像(2014)

    题目描述 将一幅只含有01像素点的图片进行顺时针旋转,旋转的角度仅包含0°,90°,180°,270° 输入 第一行一个整数T(<50)表示输入的组数 每组测试数据第一行是两个整数N和M(< ...