文档全文请查看 根目录的文档说明。javascript
若是能够,请给本项目加【Star】和【Fork】持续关注。css
有疑义请点击这里,发【Issues】。html
实战项目示例目录前端
安装:java
npm install
复制代码
运行(注,这里不像以前用的 test ,而是改用了 build):jquery
npm run build
复制代码
基本需求:webpack
jQuery
是每一个前端开发者都理应会 jQuery);less
做为 css
预处理器;打包要求:git
url-loader
不能转换 base64字符串 的文件,被这个处理(主要用于设置打包后图片路径,以及CDN等);html-webpack-plugin
:用于将已有 html 文件做为模板,生成打包后的 html 文件;clean-webpack-plugin
:用于每次打包前清理dist文件夹CommonsChunkPlugin
:提取 chunks 之间共享的通用模块多页模式是一个难点。es6
且不考虑共同模块(这里主要指的是html模板,而不是js的模块),光是单独每一个入口 js 文件须要搭配一个相对应的 html 文件,就已是一件很麻烦的事情了。github
对于这个问题,须要借助使用 html-webpack-plugin
来实现。
因为以前木有 html-webpack-plugin
的相关内容,这里只讲思路和代码。
第一:多入口则多个html文件
也是核心内容,html-webpack-plugin
只负责生成一个 html 文件。
而多入口显然须要生成多个 html 文件,所以 有多少个入口,就须要在 webpack 的 plugins 里添加多少个 html-webpack-plugin
的实例。
同时,咱们还要更改 webpack 的 entry 入口,entry 的值应该是根据入口数量自动生成的对象。
第二:chunks特性实现按需加载
经过配置 html-webpack-plugin
的 options.chunks
,可让咱们实现让 login.html
只加载 login/index.js
,而 userInfo.html
只加载 userInfo/index.js
(注:因为以 entry 的 key 做为寻找出口文件的根据,所以打包后带 hash 的文件名不影响匹配);
注意,这个实现的机制,是经过 options.chunk
的值,去匹配 webpack.config.js
的 entry
对象的 key
。
由于一个入口文件对应一个出口文件,因此这里会去拿入口文件对应的出口文件,将其加到 html 文件里。
第三:template自定义做为模板的 html 文件
options.template
能够自定义该实例以哪一个 html 文件做为模板。
第四:filename
options.filename
能够自定义生成的 html 文件输出为何样的文件名。
第五:管理多入口
已知:
一个 html-webpack-plugin
实例具备如下功能:
咱们经过webpack打包后,一个入口 js 文件会对应一个出口 js 文件;
而每一个入口 js 文件,都对应一个 html 模板文件;
所以每一个 html 模板文件,都知道本身对应哪一个出口 js 文件;
因此以上是实现多入口的原理。
代码:
多入口管理文件:
config/entry.json
[
{
"url": "login",
"title": "登陆"
},
{
"url": "userInfo",
"title": "用户详细信息"
}
]
复制代码
webpack配置文件:
webpack.config.js:
首先,配置 entry
:
const entryJSON = require('../config/entry.json');
// 入口管理
let entry = {}
entryJSON.map(page => {
entry[page.url] = path.resolve(__dirname, `../src/page/${page.url}/index.js`)
})
复制代码
其次,配置 plugins
:
// 在上面已经引用了 entryJSON
const path = require('path')
// 由于多入口,因此要多个HtmlWebpackPlugin,每一个只能管一个入口
let plugins = entryJSON.map(page => {
return new HtmlWebpackPlugin({
filename: path.resolve(__dirname, `../dist/${page.url}.html`),
template: path.resolve(__dirname, `../src/page/${page.url}/index.html`),
chunks: [page.url], // 实现多入口的核心,决定本身加载哪一个js文件,这里的 page.url 指的是 entry 对象的 key 所对应的入口打包出来的js文件
hash: true, // 为静态资源生成hash值
minify: false, // 压缩,若是启用这个的话,须要使用html-minifier,否则会直接报错
xhtml: true, // 自闭标签
})
})
复制代码
最后,webpack 自己的配置:
module.exports = {
// 入口文件
entry: entry,
// 出口文件
output: {
path: __dirname + '/../dist',
// 文件名,将打包好的导出为bundle.js
filename: '[name].[hash:8].js'
},
// 省略中间的配置
// 将插件添加到webpack中
plugins: plugins
}
复制代码
文件目录(已省略无关文件):
├─build
│ └─webpack.config.js
├─dist
└─src
└─page
├─login
│ ├─index.js
│ ├─index.html
│ └─login.less
└─userInfo
├─index.js
└─index.html
复制代码
如何将页面整齐的分类,也是很重要的。不合理的规划,会增长项目的维护难度。
项目目录以下分类:
├─build webpack 的配置文件,例如 webpack.config.js
├─config 跟 webpack 有关的配置文件,例如 postcss-loader 的配置文件,以及多入口管理文件
├─dist 打包的目标文件夹,存放 html 文件
│ └─img 打包后的图片文件夹
└─src 资源文件夹
├─common 全局配置,或者公共方法,放在此文件夹,例如 less-loader 的全局变量
├─img 图片资源文件夹,这些是共用的图片
├─less less 文件夹,共用的less文件
├─page 每一个页面,在page里会有一个文件夹,里面放置入口 js 文件,源 html 文件,以及不会被复用的 html template文件。
├─template html 模板文件夹(经过js引入模板,这里的可能被复用)
└─static 静态资源文件夹,这里放使用静态路径的资源
复制代码
虽然还不够精细,但应对小型项目是足够了的。
别名的优点不少,好比:
一、css/less 代码,能够和图片分离:
只要 webpack 配置和图片的位置不变。
那么使用别名,就能够随意移动 less 文件。
没必要担忧由于移动 less 文件,而形成的 less 文件与 图片 文件的相对路径改变,致使找不到图片而出错。
二、方便总体移动图片
假如本来图片放在src/img
文件夹下,如今你忽然想把图片放在src/image
文件夹下。
若是不使用别名,你须要一个一个去修改图片的路径;
而使用别名,只须要改一下别名的路径就好了。
css-loader
支持独立于 webpack 的别名的设置,教程参照:css-loader
这里基于【3.2】的文件分类管理,附上关于别名的控制代码:
{
loader: 'css-loader',
options: {
root: path.resolve(__dirname, '../src/static'), // url里,以 / 开头的路径,去找src/static文件夹
minimize: true, // 压缩css代码
// sourceMap: true, // sourceMap,默认关闭
alias: {
'@': path.resolve(__dirname, '../src/img') // '~@/logo.png' 这种写法,会去找src/img/logo.png这个文件
}
}
},
复制代码
其他代码已省略,若是有须要,请查看 DEMO 中的 build/webpack.config.js
文件。
方案:
因为npm上并无最新的 jQuery,目前来讲, 1.7.4
是最新的版本。
因此能够从下面这个CDN直接下载 jQuery 来使用,版本是 1.12.4
https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js
而后在js文件的开始位置,经过require引入(注意,不能经过 import
引入)
const $ = require('../../common/jquery.min')
复制代码
webpack会帮你作剩下的事情,你只须要愉快的使用 jQuery 就行了。
在 3.4 中,咱们引入了 jQeury,方法简单易行,但又一个缺点,那就是会致使代码重复打包的问题。
即 jQuery 会被打包进每个引入他的入口 js 文件中,每一个页面都须要重复下载一份将jQuery代码打包到其中的 js 文件(极可能两个 js 文件只有 20kb 是本身的代码,却有 90kb 是 jQuery 代码)。
咱们指望:
方案改进:
为了实现这个目标,毫无疑问,咱们须要将 jQuery.js 文件单独打包,或者说,每个在多个模块中共享的模块,都会被单独打包。
有几种作法,但实测后都很差用,鉴于 jQuery 会在每一个页面都适用,所以综合考虑后,我采用如下方案来初步实现个人目标。
最后我采用了 webpack 自带的插件:webpack.optimize.CommonsChunkPlugin
来实现,他能够将在多个文件中引入的 模块,单独打包。
关于这个插件能够先参考官方文档:CommonsChunkPlugin: 提取 chunks 之间共享的通用模块。
为了实现咱们的目的,咱们须要作两件事:
一、使用这个插件,以下配置:
const webpack = require('webpack')
new webpack.optimize.CommonsChunkPlugin({
name: "foo", // 这个对应的是 entry 的 key
minChunks: 2
})
复制代码
这个的效果是将至少有 2 个 chunk 引入的公共代码,打包到 foo 这个 chunk 中。
二、咱们须要引入这个打包后的 chunk ,方法是经过 html-webpack-plugin
这个插件引入。
// 无关配置已经省略
new HtmlWebpackPlugin({
chunks: [page.url, 'foo'], // 这里的foo,就是经过CommonsChunkPlugin生成的chunk
})
复制代码
无需修改源代码,此时咱们能够执行npm run build
查看打包后的效果:
foo.d78e8f4193f50cc42a49.js // 199 KB(这里包含jQuery以及公共代码)
login.d2819f642c5927565e7b.js // 15 KB
userInfo.1610748fb3346bcd0c47.js // 4 KB
0.fe5c2c427675e10b0d3a.js // 2 KB
复制代码
注:
若是页面不少的话,那么极可能某些公共组建被大量chunk所共享,而某些chunk又被少许chunk所共享。
所以可能须要特殊配置 minChunks
这个属性,具体请查看官方文档。
须要借助 clean-webpack-plugin
这个插件。
使用这个插件后,能够在每次打包前清理掉整个文件夹。
基于本项目来讲,清除的时候配置的时候须要这样配置:
new CleanWebpackPlugin(path.resolve(__dirname, '../dist'), {
root: path.resolve(__dirname, '../'), // 设置root
verbose: true
})
复制代码
缘由在于,这个插件会认为webpack.config.js
所在的目录为项目的根目录。
只使用第一个参数的话,会报错移除目标的目录位置不对:
clean-webpack-plugin: (略)【实战5】打包一个具备常见功能的多页项目\dist is outside of the project root. Skipping...
复制代码
而添加了第二个参数的设置后,就能够正常使用了。
注:
他的效果是直接删除文件夹,所以千万别写错目录了,若是删除了你正常的文件夹,那么……就只能哭啦。
因为咱们极可能在 html 中使用 <img>
标签,
而 html-webpack-plugin
这个插件,只能用于将某个 html 文件做为打包后的源 html 文件,
不会将其 <img>
标签中的 src
属性转为打包后的图片路径,同时也不会将引入的图片进行打包。
所以咱们须要将 html 内容单独拆出来,page
文件夹里的源文件只负责做为 html 模板而已。
为了使用 html 模板,咱们须要专门引入一个插件:
html-withimg-loader
:用于解析 html 文件。
使用方法很简单:
loader
(参照 webpack.config.js
);import
导入 html 模板文件(例如 login.html
);导入的时候,是一个字符串,而且图片的 url 已经被解析了。而后咱们将其引入源 html 文件中(好比page/login.html
),再写各类逻辑就好了。
注:
务必记得先把 html 模板插入页面中,再写他的相关逻辑。
使用插件 UglifyjsWebpackPlugin
,文档参照 (UglifyjsWebpackPlugin)[https://doc.webpack-china.org/plugins/uglifyjs-webpack-plugin]
压缩前:
0.fe5c2c427675e10b0d3a.js // 2 KB
foo.a5e497953a435f418876.js // 199 KB
login.9698d39e5b8f6c381649.js // 15 KB
userInfo.f5a705ffcb43780bb3d6.js // 4 KB
复制代码
丑化压缩后:
0.fe5c2c427675e10b0d3a.js // 1 KB
foo.a5e497953a435f418876.js // 120 KB
login.9698d39e5b8f6c381649.js // 10 KB
userInfo.f5a705ffcb43780bb3d6.js // 2 KB
复制代码
从新列出全部需求:
基本需求:
jQuery
是每一个前端开发者都理应会 jQuery);less
做为 css
预处理器;打包要求:
需求的实现:
基本需求:
需求的实现过程 | |
需求 | 实现方法 |
引入jQuery | 1. 经过 require() 引入,并经过 CommonsChunkPlugin 实现单独打包; |
使用 less 做为 css 预处理器 | 1. 使用 less-loader 来处理 .less 文件; |
标准模块化开发 | 1. 使用 import 和 require 语法来进行模块化开发; |
有异步加载的模块 | 1. 经过 require([], callback) 来实现模块的异步加载 |
使用 es六、es7 语法 | 1. 使用 babel 来转义 |
写一个登陆页面做为DEMO,再写一个登陆后的示例页面做为跳转后页面 | 1. 登陆页:page/login 2. 跳转后页面:page/userInfo |
可适用于多页项目 | 1. config/entry.json 用于配置多页入口; 2. html-withimg-loader 来生成多页模板; 3. 最后在webpack.config.js里配置 entry 和 plugins |
css 文件与 图片 文件脱离(即更改 css 文件路径不影响其对图片的引用) | 经过 css-loader 的别名实现 |
打包需求:
需求的实现过程 | |
需求 | 实现方法 |
启用 hash 命名,以应对缓存问题 | 配置 output 的 filename 属性,加 [chunkhash] 便可 |
css 自动添加兼容性前缀 | 使用 post-loader 的 autoprefixer |
将图片统一放到同一个文件夹下,方便管理 | 配置 url-loader (实质是 file-loader )的 outputPath |
将共同引入的模块单独打包出来,用于缓存,减小每次重复加载的代码量 | 使用插件 CommonsChunkPlugin 来实现 |
代码进行丑化压缩 | 使用插件 UglifyjsWebpackPlugin 来实现 |