在上一章还是使用Gulp来启动Webpack的任务,在这一章发现这个教程的很多地方都过期了,尤其是Webpack+Babel的地方。
而且Webpack现在越来越流行,因此这一章开始转向使用Webpack来构建工作流。
Babel做的事情,就像PostCss对CSS做的事情,用一些浏览器并不能解析组织结构来编写JavaScript代码,以及自动解决浏览器兼容性问题。
Webpack也支持各种组件,就像Gulp的插件一样,所以来试着全部用Webpack来搭建CSS+JS的工作流,目标就是搭建Webpack 4.0 + Vue2.x的开发环境。
- 以Webpack作为前端工作流的基础
- 入口起点
- Loader
- Plugin
- DevServer
Webpack
一步一步通过IDE来进行实验。WebStorm新建Node.js项目,自动选择Node.js和NPM版本,创建一个空项目。
项目目录下会自动执行npm init
,自动创建package.json
。
然后通过NPM安装,npm i -D
表示install --save-dev
:
npm i -D webpack
安装了4.32.0版本。Webpack 4.0以上版本分开了命令行工具和插件本身,所以还需要安装:
npm i -D webpack-cli
安装了webpack-cli 3.3.2版本。
推荐将Webpack安装在本地项目,这样可以避免版本冲突。
入口起点与输出
所谓入口起点就是一个js文件,Webpack把这个文件当成起始的地方,逐步解析依赖。
使用webpack.config.js
文件进行配置。
输入和输出如果不指定,都有默认位置:
- 默认到
./src/index.js
目录寻找入口
- 默认输出到
./dist/main.js
文件
具体写配置:
const path = require('path');
module.exports = {
entry: './script/index.js',
output: {
path: path.resolve(__dirname,"dist/script"),
filename: "app.js"
}
};
这个表示入口在项目根目录的script/index.js
,输出在拼接的项目目录/dist/script
下,文件名叫做app.js
拼接字符串的时候一定要注意,不能写成/dist/script
,别带最前边的反斜杠。
随便建点入口和出口文件,试验了一下,有个坑:
- 导入的如果不是库,需要指定具体的js文件,比如
var show = require("./show.js");
不能写成require("show")
,webpack无法解析。
Loader
Loader就是让Webpack支持其他类型文件的工具。
Webpack本身只支持JS文件,如果要处理其他,就必须要使用Loader。
使用Loader的时候,必须要显式写配置。
const path = require('path');
module.exports = {
//设置模式,可以是development或者production
mode: "development",
// 入口和输出部分
entry: './script/index.js',
output: {
path: path.resolve(__dirname, "dist/script"),
filename: "app.js"
},
//loader部分
module: {
rules: [
{
//匹配文件类型
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
这里使用了一个loader,用于让Webpack支持CSS文件打包。
每个Loader对象放在module-rules,有两个属性,一个是遇到指定后缀名称的资源,一个是用哪个loader进行处理。
处理的结果是CSS资源的样式,被包含在了JS文件里,动态生成了Head中的Style标签,所以样式依然生效。
这样做感觉有点高度耦合和浪费资源,所以还可以使用Plugin来单独生成CSS文件。
Plugin
与Loader能打包多种文件不同,Plugin是用来扩展Webpack的功能。
注意,看了extract-text-webpack-plugin官网: Since webpack v4 the extract-text-webpack-plugin should not be used for css. Use mini-css-extract-plugin instead.
要么安装这个插件,要么按照下边的办法:
需要安装npm i -D extract-text-webpack-plugin@next
,注意一定要是next,然后使用loader加载,使用plugin处理:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
// 入口和输出部分
entry: './script/index.js',
output: {
path: path.resolve(__dirname, "dist/script"),
filename: "app.js"
},
//loader部分
module: {
rules: [
{
//匹配文件类型
test: /\.css$/,
//调用了新的插件的方法,这里使用了css-loader
loaders: ExtractTextPlugin.extract({
use: ['css-loader']
})
}
]
},
//插件部分
plugins: [
new ExtractTextPlugin({
filename: "[name].css"
})
]
};
plugins是一个数组,数组每一个元素都是一个插件的实例。发现不支持[contenthash:8]
这种写法了,无奈就先直接用了名称。
如果用
const path = require('path');
const ExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// 入口和输出部分
entry: './script/index.js',
output: {
path: path.resolve(__dirname, "dist/script"),
filename: "app.js"
},
//loader部分
module: {
rules: [
{
//匹配文件类型
test: /\.css$/,
//调用了新的插件的方法,这里使用了css-loader
use: [
{
loader: ExtractPlugin.loader,
},
'css-loader'
]
}
]
},
//插件部分
plugins: [
new ExtractPlugin({
filename: "[name].css"
})
]
};
DevServer
Webpack也能做到实时预览加载,通过WebSocket刷新页面。来看一下如何配置。
先要安装服务器:
npm i -D webpack-dev-server
然后在项目根目录执行:webpack-dev-server
:
i 「wds」: Project is running at http://localhost:8080/
i 「wds」: webpack output is served from /
i 「wds」: Content not from webpack is served from D:\Coding\sites\webpackworkflow
服务器直接就启动了。但是会发现没有样式,打开console看,会发现404找不到JS文件。这是因为DevServer不会理会配置文件中的output-path路径,而是会把编译后的文件都放在内存中,对应的就是根目录。
所以要把index.html中的js和css文件链接都修改成直接就在根目录下,比如:
<link rel="stylesheet" href="main.css">
<script src="app.js"></script>
这样就可以正常显示了。不过要注意的是,更新index.html并不能触发自动更新,这是因为Webpack监听的对象是以entry为起点的,不包含在相关依赖内的文件不会被监听。而且单页面应用基本上就加载一个外层框架元素,不大更改HTML。
还可以使用webpack-dev-server --hot
来启用模块热替换,刷新的效果更好。
SourceMap
DevServer还有个功能非常方便调试,就是使用 webpack-dev-server --devtool source-map
参数,之后在Chrome开发工具中就能查看Source,方便调试。
这里自己试验了一下好像Sources中没有显示。
不管怎么说,现在已经初步搭建好了一个CSS和JS直接处理的程序,剩下就是加上各种可以采取高级编写手段的插件,比如post-css和Babel等工具,来搭建一个基础的前端工具流了。另外架构师朋友说为了Vue的话还可以直接研究Vue-cli,先都记下来。