前言 - 阅读《深入浅出webpack》一书实践
目录
- 安装与使用
- Loader
- Plugin
- Devserver
安装与使用
# npm i -D 是 npm install --save-dev 的简写,
--save 是指安装模块并保存到 package.json 的 devDependencies
# 安装最新稳定版
npm i -D webpack
# 安装指定版本
npm i -D webpack@<version>
# 安装最新体验版本
npm i -D webpack@beta
# 全局安装
npm i -g webpack
下面通过 Webpack 构建一个基于 CommonJS 模块化编写的项目,该项目会使用JavaScript通过webpack编译在网页中显示 Hello,Webpack。
创建一个HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!--引入 Webpack 输出的 JavaScript 文件暂时命名 bundle.js -->
<script src="./dist/bundle.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
创建一个执行入口文件 main.js
var showText = require("./utils.js");
showText('Webpack');
main.js
里边的代码很简单,就是 require 导入一个模块儿 utils.js
在commonJs模块儿规范里边一个Js文件就相当于一个模块儿,紧跟着就是调用这个模块儿里的函数;好,那么此时我需要创建这个模块儿文件utils.js
创建utils.js
// 操作 DOM 元素,把 content 显示到网页上
function showText(content) {
window.document.getElementById('app').innerText = 'Hello,' + content;
}
// 通过 CommonJS 规范导出 show 函数
module.exports = showText;
内容也很简单就是一个函数 showText
,函数体就是在页面显示一段文本,紧跟着后边就是导出这个函数。
好,入口文件以及执行的操作都有了,接下来我们需要一个webpack配置文件,紧接着,我们再创建一个webpack.config.js 文件
创建webpack.config.js
const path = require('path');
module.exports = {
entry: './main.js', // 入口文件,很重要,运行webpack构建唯一执行的文件
output: {
// 把所有依赖的模块合并输出到一个 bundle.js 文件
filename: 'bundle.js',
// 输出文件都放到 dist 目录下
// __dirname 只当前指向目录
path: path.resolve(__dirname, './dist'),
}
};
内容其实也很少啊,我们简单分析一下,path
基于node模块的path
模块儿,主要就是路径(顾名思义啊),然后就是导出一个对象,这个对象里边包含了入口文件和出口文件配置;具体的解释都写在代码注释了。
截至到这里,我们的准备文件都已经就绪了,目录暂时如下:
webpack // 工程目录
index.html
main.js
utils.js
webpack.config.js
看到这里,小伙伴们是不是感觉还差点什么,对,package.json 文件,那么我们初始化一下
npm install
, 会发现命令行里会让我们填写一些东西,例如:webpack项目名字,作者,版本,入口文件等等。我们一一确认一下就好。
package.json 文件,我们需要在 scripts 对象里新增一条执行命令,执行我们的
webpack 配置文件,也就是 webpack.config.js
文件
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "HiSen",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// 新增命令
"build":"webpack --config webpack.config.js"
},
"author": "",
"license": "ISC"
}
准备就绪了,我们安装 webpack npm install -D webpack
, 然后执行我们的webpack构建命令 npm run build
其实就是执行的 "webpack --config webpack.config.js"
看上边的scripts对象。结果不尽人意啊(如下图示),还让我们安装 webpack-cli
理由既然是作为单独的包提供,好吧,照着来吧。
这里有一个小插曲,选择 yes 安装居然会报错,我没有去查看到底是因为什么啊,我直接自己命令装了一下
好了,这一下算是全部文件准备就绪了,此时我们的目录和package.json
文件都发生了一点点小小的改变;如下:
webpack // 工程目录
index.html
main.js
utils.js
webpack.config.js
package.json
node_modules
目录在安装webpack的时候会自动生成一个依赖文件,node_modules
package.json
文件 devDependencies
对象也增加了我们安装的 webpack
和 webpack-cli
;
最后,我们来尝试构建打包一下:npm run build
恭喜你 ,结果很明显,成功了,我们简单的实现了一个webpack构建打包的实例。
代码结构目录
webpack // 工程目录
dist // 构建生成目录
bundle.js
index.html
main.js
utils.js
webpack.config.js
package.json
node_modules
打开本地的HTML就可以看到,我们的页面,可能会遇到一个小小的错误
Cannot set property 'innerText' of null
因为JavaScript运行时,id="app"的那个div元素可能还没解析和加载,只需把整个搬到前面即可,就像这样:
最后结果:
Loader
很重的一个知识点,接下来我们能创建一个css文件 main.css
,然后同样在我们的入口文件main.js
文件引入,结果如下:
main.css
文件内容
#app{
text-align: center;
color:red;
}
main.js
导入
require("./main.css"); // 导入main.css 文件
var showText = require("./utils.js");
showText('Webpack');
显然这样直接构建,Webpack 构建是会报错的,因为 Webpack 不原生支持解析 CSS 文件。要支持非 JavaScript 类型的文件,需要使用 Webpack 的 Loader 机制。所以我们修改webpack.config.js
文件,添加 Loader
配置(Loader 可以理解为是文件解析器,解析类似 css,less,scss等)
module.exports = {
entry: './main.js', // 入口文件
output: {
// 把所有依赖的模块合并输出到一个 bundle.js 文件
filename: 'bundle.js',
// 输出文件都放到 dist 目录下
// __dirname 只当前指向目录
path: path.resolve(__dirname, './dist'),
},
// 添加如下配置
module: {
rules: [
{
test: /\.css$/, // 用正则去匹配要用该 loader 转换的 CSS 文件
use: ['style-loader', 'css-loader'] // 注意这里顺序不能错
}
]
}
};
user 还有另外一种写法,数组对象形式
use: [
'style-loader',
{
loader:'css-loader',
options:{
minimize:true, // minimize 告诉 css-loader 要开启 CSS 压缩。
}
}
]
配置里的 module.rules 数组配置了一组规则,告诉 Webpack 在遇到哪些文件时使用哪些 Loader 去加载和转换。
这里的配置告诉 Webpack 在遇到以 .css 结尾的文件时先使用 css-loader 读取 CSS 文件,再交给 style-loader 把 CSS 内容注入到 JavaScript 里。
注意:
use 属性的值需要是一个由 Loader 名称组成的数组,Loader 的执行顺序是由后到前的; 每一个 Loader 都可以通过 URL querystring (或者数组对象)的方式传入参数。
好,接下来,我们来实践一下,在构建之前,首先需要安装 Loader,在这里使用到了 style-loader,css-loader
,安装一下
npm i -D style-loader css-loader
package.json
文件会显示出来,后续大家请自己关注,我就不贴图了。
效果如下
你会发现 bundle.js 文件被更新了,里面注入了在 main.css 中写的 CSS,而不是会额外生成一个 CSS 文件。 但是重新刷新 index.html 网页时将会发现 Hello,Webpack 居中了,样式生效了! 也许你会对此感到奇怪,第一次看到 CSS 被写在了 JavaScript 里!这其实都是 style-loader 的功劳,它的工作原理大概是把 CSS 内容用 JavaScript 里的字符串存储起来, 在网页执行 JavaScript 时通过 DOM 操作动态地往 HTML head 标签里插入 HTML style 标签。 也许你认为这样做会导致 JavaScript 文件变大并导致加载网页时间变长,想让 Webpack 单独输出 CSS 文件。接着往下看
Plugin
首先我们需要下载插件 extract-text-webpack-plugin
npm i -D extract-text-webpack-plugin
然后直接看向 webpack.config.js
配置文件,进行如下配置:
1,引入extract-text-webpack-plugin
插件, 作用是提取出 JavaScript 代码里的 CSS 到一个单独的文件
2,module
里添加 plugin
数组,通过插件的 filename
属性,告诉插件输出的 CSS 文件名称是通过 [name]_[contenthash:8].css
字符串模版生成的,里面的[name]
代表文件名称,[contenthash:8]
代表根据文件内容算出的8位 hash 值,
3,修改rules
里边use
,使用ExtractTextPlugin
插件转换 css-loader
,这里不需要再使用style-loader
解析了。
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); // 引入 plugin 插件
module.exports = {
entry: './main.js', // 入口文件
output: {
// 把所有依赖的模块合并输出到一个 bundle.js 文件
filename: 'bundle.js',
// 输出文件都放到 dist 目录下
// __dirname 只当前指向目录
path: path.resolve(__dirname, './dist'),
},
// 添加如下配置
module: {
rules: [
{
// 用正则去匹配要用该 loader 转换的 CSS 文件
test: /\.css$/,
// use: ['style-loader', 'css-loader'],
use: ExtractTextPlugin.extract({
// 转换 .css 文件需要使用的 Loader
use: ['css-loader']
}),
}
]
},
plugins: [
new ExtractTextPlugin({
// 从 .js 文件中提取出来的 .css 文件的名称
filename: `[name]_[contenthash:8].css`,
}),
]
};
以上修改完成后,我们开始构建,索嘎,成功的构建出来了,如果发现报错,请检查webpack
版本和ExtractTextPlugin
版本是否匹配。
构建出来的 dist
目录如下:
dist
bundle.js // js 里边也不含有 css 样式代码了
main_69bba57c.css // 而这个css文件就是我们的 main.css 文件
DevServer
前面的几节只是让 Webpack 正常运行起来了,但在实际开发中你可能会需要:
1,提供 HTTP 服务而不是使用本地文件预览;
2,监听文件的变化并自动刷新网页,做到实时预览;
3,支持 Source Map,以方便调试。
当然这些 webpack
都为你想好了,DevServer
会启动一个 HTTP 服务器用于服务网页请求,同时会帮助启动 Webpack
,并接收 Webpack
发出的文件更变信号,通过 WebSocket 协议自动刷新网页做到实时预览。
好了,我们实践一下,安装 webpack-dev-server
这里有版本兼容问题,我用的是2.9.4,webpack@3.6.0,大家需要注意以下。
npm i -D webpack-dev-server
运行命令 webpack-dev-serve
, 如下运行成功,此时有一个地方,注意看,第三行,四行
这意味着 DevServer 启动的 HTTP 服务器监听在 http://localhost:8081/ ,DevServer 启动后会一直驻留在后台保持运行。
细心的小伙伴已经发现了问题,我们的打开 http://localhost:8081/
发现网页内容没错,可是样式却没了,而且 ./dist/bundle.js
加载404了;原因是 DevServer
会把 Webpack
构建出的文件保存在内存中,在要访问输出的文件时,必须通过HTTP
服务访问。 由于DevServer
不会理会 webpack.config.js
里配置的output.path
属性,所以正确的 index.html 应该修改为:
<link rel="stylesheet" href="main_69bba57c.css">
<script src="bundle.js"></script>
然后大家再尝试着修改任何文件,会发现,犹如热更新一样,随着修改,终端和网页都在随之刷新。
好了,第一章节就到这了,我们下章见。