前言
在学习 Webpack 之前,我们需要了解一个概念:模块。
何为模块?
如果你曾学过 Java , C# 之类的语言,一定会知道 Java 中的 import 或 C# 中的 using 吧? 比如:我想在 C# 中进行数据库操作,我只需要在代码头部加上 下面这两段代码即可。
1 | using System.Data; |
在前端中 模块又该如何定义呢? 按照我个人的理解:
- 在 HTML 中 模块 便是一个组件
1
2
3
4
5
6<div class="layer">
<div><%= name %></div>
<% for(var i = 0; i < People.length;++i) { %>
<%= People[i] %>
<% } %>
</div> 在 CSS 中 模块 便是一个局部样式
1
2
3
4
5
6header{
display:block;
}
header h1{
font-size: 60px;
}在 Javascript 中 模块 便是一个封装着方法或数据的脚本文件
1
2let People = { name: "Simon" } ;
module.exports = People;
而我们又该怎样实现 在前端中加载模块呢? 下面是两个很常见的例子:
在 Less 中
1 | @import "header"; |
在 Javascript
1 | // CommonJS |
如果你直接运行以上代码,浏览器并不会解析,这个时候,就要依靠 Webpack 了!
Webpack 是什么
Webpack 是一款目前非常流行的前端模块打包工具,可以将项目中所加载的模块进行打包,以及将 一些浏览器不支持的语言进行转换。
Webpack 的打包原理是 先找到入口文件,递归探索出所有依赖的模块,最后 利用 Loader 进行不同文件类型的处理,打包成一个 Javascript 文件。
其中,Webpack 的两个最核心原理分别是:
- 一切皆模块
- 按需加载
当然 Webpack 的作用不止加载模块这么简单,前端的常用需求通常都可以实现:利用 Loader 转换 es6 、 Less 、 Typescript ,还可利用插件 开发多页面应用,等等诸多强大功能。
正文
下面,我将讲解 Webpack 的具体使用和配置。
安装
我一般在项目中使用 Webpack,都是先执行下面这四条命令进行 Webpack 的安装
- npm install -g webpack 在全局安装 Webpack,第一次使用时 执行
- npm install --save-dev webpack 将 Webpack 安装到你的项目
- npm init npm 初始化,会询问你的项目信息,可以回车跳过
- npm install --save-dev webpack-dev-server 在当前项目,安装 Webpack 服务器
安装完成后,便是建立配置文件了。
基本配置
在项目根目录下新建名为 webpack.config.js 的文件, 基本上 一个配置文件的大体结构就是下面这样:
1 | modules.export={ |
入口
entry 代表是入口文件,Webpack 工作的开始。 Webpack 会递归的探索出 入口文件中所依赖的模块,并按照顺序 利用 Loader 进行处理。 官网给出了其 3 种数据类型:
- 字符串
1
entry: "app.js";
- 数组 数组中的每一项都会被打包,形成互不依赖的文件
1
entry: ["app.js","main.js"];
- 对象 对象中的每一个属性都会被打包,形成互不依赖的文件一般入口文件中多是 import 或者 require 等模块导入命令。
1
2
3
4entry:{
app: "./src/js/app.js",
main: "./src/js/main-792ee436ad.js"
}
出口
output 顾名思义,Webpack 打包后文件的具体配置 常用的属性有 4 个
- path:
${__dirname }/dist
打包后文件所在路径 - filename: “js/[name].js” 打包后文件的名字,这里有 4 种常用的写法
- 自定义
- [name].js 代表的便是入口的文件名
- [hash].js 此次打包后的 hash 值
- [chunkhash] 该块打包后的 hash 值
- publicPath:
"http://cdn.com/"
上线时的公共路径,主要应用于线上 - chunkFilename: ‘js/[name].js’ 按需加载模块时输出的文件名称
Loader
Loader 是 Webpack 中最振奋人心的东西了! 将一切浏览器不支持的语言,处理成 浏览器可以支持。 针对各个文件类型,都有各种的 Loader 等你去挖掘。
Loader 的工作方式 是从右向左执行,链式地按照顺序进行编译。 loader 链中的第一个返回值给下一个 loader,在最后一个 loader,返回所预期的结果。
loader 可以是同步或异步函数,也可使用 options 对象去接受配置参数。
基础结构
1 | module:{ |
可以很清楚的看到,Loader 利用 test 的正则 找到各个类型文件,然后使用 loader 进行处理,便可转换成浏览器支持的文件。
其中我知道的 loader 的写法有两种:
- 每一个 loader 都是一个对象
1
2
3
4
5loaders:[
{loader:"style-loader"},
{ loader: "css-loader?modules", options: { importLoaders: 1 } },
{loader: "less-loader"}
] - 使用 ! 号拼接的写法下面介绍三个 前端必备的 Loader 方式
1
loader: "style-loader!css-loader?importLoaders=1!less-loader"
css
- style-loader 通过注入
style
标签将 CSS 添加到 DOM1
npm install style-loader --save-dev
- css-loader css-loader 像 import / require()一样解释@import 和 url()并解析它们。
1
npm install css-loader --save-dev
- postcss-loader 补充 不兼容的 css 属性 的浏览器前缀
1
npm install post-loader --save-dev
- less-loader 将 Less 转换成 CSS
1
2npm install less --save-dev
npm install less-loader --save-dev
javascript
babel 主要用于将 es6 转换成 es2015
1 | npm install --save-dev babel-core babel-loader babel-preset-es2015 |
图片 & 字体
- file-loader 用于压缩文件
1
npm install --save-dev file-loader
- url-loader 如果文件下于 规定限制,将会转换成 二进制编码
1
npm install --save-dev url-loader
ejs
另外 我想介绍一下 自己常用的 ejs-loader 配置
1
npm install --save-dev ejs-loader
1
test:/\.ejs$/ , loader:"ejs-loader",
使用
1 | <div class="layer"> |
1 | //入口文件 |
运行 生成后的页面 ,便会发现 ejs 组件已经被加进去了, 想象一下,我们在平时工作中是否可以把 一个轮播图,或者 排行榜 、评论 当成一个组件呢?
插件
plugins 在日常工作中,我们使用 Loader 处理不同类型的文件,当有某种其他方面的需求时,比如 抽离 CSS 、生成多页面 HTML ,plugins 便派上了用场。
插件的使用,一般都要先 require 出来,然后在 plugins 属性中 进行初始化
1 | const htmlWebpackPlugin = require("html-webpack-plugin"); |
下面将介绍 一些工作中常用的插件
- clean-webpack-plugin 主要用于 打包之前 先清空 打包目录下的文件,防止文件混乱。
1
npm install --save-dev clean-webpack-plugin
- html-webpack-plugin 主要用于生成 HTML,可以规定 模板 HTML,也可以为 模板传入参数,压缩文件等这个插件可谓是 前端必备的,它的配置有很多
1
npm install --save-dev html-webpack-plugin
那么问题来了,我们在模板文件中 又该怎样使用参数呢? 直接按照 ejs 的语法写入 html 文件即可!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45new htmlWebpackPlugin({
//打包后的文件名
filename: "index.html",
//模板
template: "index.html",
//为 true 自动生成 script 标签添加到 html 中
//或者写 body/head 标签名
inject: false,//js 的注入标签
//通过<%= htmlWebpackPlugin.options.title %>引用
title: "参数 title",
//通过<%= htmlWebpackPlugin.options.date %> 引用
date: new Date()
//网站的图标
favicon: 'path/to/yourfile.ico'
//生成此次打包的 hash
//如果文件名中有哈希,便代表有 合理的缓冲
hash: true,
//排除的块
excludeChunks: [''],
//选中的块 与入口文件相关
chunks: ['app','people'],
//压缩
minify:{
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
}),生成后的模板文件1
2
3
4
<html lang="en">
<%= htmlWebpackPlugin.options.date %>
</html>另外,如果想生成 多页面应用,只需 将上面的配置,多复制几遍即可。1
2
3
4
<html lang="en">
Thu Dec 07 2017 10:01:58 GMT+0800 (中国标准时间)
</html>1
2
3new htmlWebpackPlugin({ filename: "index1.html", }
new htmlWebpackPlugin({ filename: "index2.html", }
new htmlWebpackPlugin({ filename: "index3.html", } - UglifyJsPlugin 主要用于压缩 Javascript 文件
1
npm i -D uglifyjs-webpack-plugin
- webpack.ProvidePlugin 自动加载模块,全局使用变量,下面借助 官网的 DEMO
1
2
3
4
5
6
7
8new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
// in a module
$('#item'); // <= 起作用
jQuery('#item'); // <= 起作用
// $ 自动被设置为 "jquery" 输出的内容 - open-browser-webpack-plugin 打开服务器后 会自动打开浏览器端口,用起来 很方便
- HotModuleReplacementPlugin 热更新插件
常用命令
webpack 最基本的启动 webpack 命令。找到根目录下的 webpack.config.js 文件中的 entry 属性,递归出所有项目中依赖的模块。
webpack -w 监控代码变化,实时进行打包更新
- webpack -p 对打包后的文件进行压缩,利用线上发布
- webpack -d 提供 SourceMaps,方便调试代码
- webpack –colors 输出结果带彩色,可以更详细的查看信息
- webpack –profile 输出性能数据,可以看到每一步的耗时
前两个命令使用频率会较大
devtool
不知道你现在时候有没有一个想法? webpack 打包后的文件就一定正确无误吗? 如果发生错误的话,该怎么办呢?
devtool 属性 便提供了生成 sourcemap 的功能,具体有下面这些选项。
- source-map 此选项具有最完备的 source map,但会减慢打包的速度;
- cheap-module-source-map 生成一个不带列映射的 map
- eval-source-map 使用 eval 打包源文件模块,生成一个完整的 source map。
- cheap-module-eval-source-map 这是最快生成 source map 的方法,生成后的 Source Map 会和打包后的 JavaScript 文件同行显示,但没有列映射,所以慎用
devServer
- contentBase: “./dist”, 本地服务器所加载的页面所在的目录
- historyApiFallback: true, 再找不到文件的时候默认指向 index.html
- inline: true, 当源文件改变时会自动刷新页面
- hot: true, 热加载开启
- port:8080 设置默认监听端口
resolve
extensions: [“.js”, “.html”, “.css”, “.txt”,”less”,”ejs”,”json”], 自动扩展文件后缀名,意味着我们 require 模块可以省略不写后缀名
alias: { Temp: path.resolve(__dirname, “src/templates/“) } 模块别名定义,直接 require(‘AppStore’) 即可,方便后续直接引用别名
其他功能
path
常用于字符串拼接路径。
1 | const path = require("path"); |
- path.resolve() 将相对路径转换成绝对路径
1
2const aPath = path.resolve("__dirname","js","main.js");
// aPath = 当前目录下的 js 文件夹的 main.js 文件的路径 - path.join() 对路径进行拼接
1
2const rPath = path.join("source","js","main.js");
// aPath = //source/js/main-792ee436ad.js - __dirname Node.js 中的全局变量,代表的是 项目的当前路径。常与 path 结合使用。
热更新
上面我们已经提过了 webpack -w
命令,它可以实时的监控 代码的改变,从而自动进行打包,但是 有个缺点 在于它不能及时的刷新界面。 在我们 开启服务器后,是无法使用 此命令的,这个时候,如果你还想进行 自动打包,又想自动刷新界面,热更新 便是不二之选,另外 Webpack 只会热更新 发生改变的模块,不会重新加载整个页面,便可加快开发速度。
开启步骤:
- 修改 devServer 属性
1
2
3
4devServer: {
hot: true,//热加载开启
inline: true,//文件改变时会自动刷新页面
} - 增加热更新插件另外,只有修改 依赖的项目,才会进行实时更新。
1
2
3
4
5const webpack = require("webpack");
//Other property
plugins: [
new webpack.HotModuleReplacementPlugin()
]
源文件
个人总结了很长时间的 Webpack 配置,希望能对你有帮助。
结束语
转载本站文章请注明作者和出处 tomotoes.com,请勿用于任何商业用途。