正文
前言
在学习 Webpack 之前,我们需要了解一个概念:
模块
。
何为模块?
如果你曾学过 Java , C# 之类的语言,一定会知道 Java 中的 import 或 C# 中的 using 吧?
比如:我想在 C# 中进行数据库操作,我只需要在代码头部加上 下面这两段代码即可。
using System.Data;
using System.Data.SqlClient;
这两段代码可以看成 两个与数据库操作相关的模块。
当我们需求是数据库,或者是读取 IO 等其他操作,我们便加载其他不同的模块。
很明显,这实现了编程中的一个非常重要的功能
按需加载
。
在前端中 模块又该如何定义呢?
按照我个人的理解:
<div class="layer">
<div><%= name %></div>
<% for(var i = 0; i < People.length;++i) { %>
<%= People[i] %>
<% } %>
</div>
header{
display:block;
}
header h1{
font-size: 60px;
}
-
在 Javascript 中 模块 便是一个封装着方法或数据的脚本文件
let People = { name: "Simon" } ;
module.exports = People;
而我们又该怎样实现 在前端中加载模块呢?
下面是两个很常见的例子:
在 Less 中
@import "header";
@import "layout";
@import "footer";
在 Javascript
const $ = require("jQuery");
let People = { name: "Simon" } ;
module.exports = People;
import "./layer.less";
import tpl from "./layer.ejs";
如果你直接运行以上代码,浏览器并不会解析,这个时候,就要依靠 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 的文件,
基本上 一个配置文件的大体结构就是下面这样:
modules.export={
entry:{
},
output:{
},
module:{
rules:[{},{},{}]
},
plugins:[
],
devtool: ...
devServer: {...}
resolve:{...}
}
我们下面就先分析 modules.export 各个属性
入口
entry
代表是入口文件,Webpack 工作的开始。
Webpack 会递归的探索出 入口文件中所依赖的模块,并按照顺序 利用 Loader 进行处理。
官网给出了其 3 种数据类型:
-
字符串
entry: "app.js";
-
数组
数组中的每一项都会被打包,形成互不依赖的文件
entry: ["app.js","main.js"];
-
对象
对象中的每一个属性都会被打包,形成互不依赖的文件
entry:{
app: "./src/js/app.js",
main: "./src/js/main.js"
}
一般入口文件中多是 import 或者 require 等模块导入命令。
出口
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 对象去接受配置参数。
基础结构
module:{
rules:[
{
test:/\.xxx$/,
loader: "xxx-loader",
exclude: {排除的路径},
include: {包含的路径},
options: {Loader配置}
}
]
}
可以很清楚的看到,Loader 利用 test 的正则 找到各个类型文件,然后使用 loader 进行处理,便可转换成浏览器支持的文件。
其中我知道的 loader 的写法有两种:
-
每一个 loader 都是一个对象
loaders:[
{loader:"style-loader"},
{ loader: "css-loader?modules", options: { importLoaders: 1 } },
{loader: "less-loader"}
]
-
使用 ! 号拼接的写法
loader: "style-loader!css-loader?importLoaders=1!less-loader"
下面介绍三个 前端必备的 Loader 方式
css
-
style-loader
通过注入
<style>
标签将 CSS 添加到 DOM
npm install style-loader --save-dev
-
css-loader
css-loader像import / require()一样解释@import和url()并解析它们。
npm install css-loader --save-dev
-
postcss-loader
补充 不兼容的css属性 的浏览器前缀
npm install post-loader --save-dev
-
less-loader
将Less 转换成 CSS
npm install less --save-dev
npm install less-loader --save-dev
javascript
babel
主要用于将 es6 转换成 es2015
npm install --save-dev babel-core babel-loader babel-preset-es2015
图片 & 字体
-
file-loader
用于压缩文件
npm install --save-dev file-loader
-
url-loader
如果文件下于 规定限制,将会转换成 二进制编码
npm install --save-dev url-loader
ejs
另外 我想介绍一下 自己常用的 ejs-loader
-
配置
npm install --save-dev ejs-loader
test:/\.ejs$/ , loader:"ejs-loader",
-
使用
<div class="layer">
<div><%= name %></div>
<% for(let i = 0; i < Array.length;++i) { %>
<%= Array[i] %>
<% } %>
</div>
import tpl from "./layer.ejs";
document.body.innerHTML = tpl({
name:"Simon",
arr:["Apple","Xiaomi"]
});
运行 生成后的页面 ,便会发现 ejs 组件已经被加进去了,
想象一下,我们在平时工作中是否可以把 一个轮播图,或者 排行榜 、评论 当成一个组件呢?
插件
plugins
在日常工作中,我们使用 Loader 处理不同类型的文件,当有某种其他方面的需求时,比如 抽离 CSS 、生成多页面 HTML ,plugins 便派上了用场。
插件的使用,一般都要先 require 出来,然后在 plugins 属性中 进行初始化
const htmlWebpackPlugin = require("html-webpack-plugin");
......
plugins: [ new htmlWebpackPlugin({}) ]
下面将介绍 一些工作中常用的插件
-
clean-webpack-plugin
主要用于 打包之前 先清空 打包目录下的文件,防止文件混乱。
npm install --save-dev clean-webpack-plugin
-
html-webpack-plugin
主要用于生成HTML,可以规定 模板HTML,也可以为 模板传入参数,压缩文件等
npm install --save-dev html-webpack-plugin
这个插件可谓是 前端必备的,它的配置有很多
new htmlWebpackPlugin({
filename: "index.html",
template: "index.html",
inject: false,
title: "参数title",
date: new Date()
favicon: 'path/to/yourfile.ico'
hash: true,
excludeChunks: [''],
chunks: ['app','people'],
minify:{
removeComments: true,collapseWhitespace: true,
minifyJS: true, minifyCSS: true,minifyURLs: true,
}
}),
那么问题来了,我们在模板文件中 又该怎样使用参数呢?
直接按照 ejs 的语法写入 html 文件即可!
<!DOCTYPE html>
<html lang="en">
<%= htmlWeb
packPlugin.options.date %>
</html>
生成后的模板文件
<!DOCTYPE html>
<html lang="en">
Thu Dec 07 2017 10:01:58 GMT+0800 (中国标准时间)
</html>
另外,如果想生成 多页面应用,只需 将上面的配置,多复制几遍即可。
new htmlWebpackPlugin({ filename: "index1.html", }
new htmlWebpackPlugin({ filename: "index2.html", }
new htmlWebpackPlugin({ filename: "index3.html", }
-
UglifyJsPlugin
主要用于压缩 Javascript 文件
npm i -D uglifyjs-webpack-plugin
-
webpack.ProvidePlugin
自动加载模块,全局使用变量,下面借助 官网的DEMO
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
$('#item');
jQuery('#item');