本文主要分为:
- 环境配置
- 使用配置文件
- CSS 处理
- ES6 代码编辑
- 文件压缩
- SASS 处理
- CSS 与 JS 分离
- 文件处理 file-loader 与 url-loader
- 多入口及自动清理
客位看官可直接 ctrl + f
搜索对应关键字
环境配置
window + r
,输入cmd
打开命令行-
新建并进入
webpack-3.10.0
文件夹mkdir webpack-3.10.0 && cd webpack-3.10.0
-
使用
sublime text3
的subl.exe
打开该文件夹
-
在
webpack-3.10.0
目录下初始化操作,生成package.json
文件npm init -y
也可以直接使用 npm init
来初始化 package.json
文件,但这样需要手动填写项目名之类的东西,加上 -y
表示使用默认配置
-
新建
src
文件夹,今后将要打包的文件全部放入该文件夹下
-
在
src
下新建main.js
并随便敲一点代码
-
安装
webpack
npm install webpack@3.10.0 --save-dev
这里是安装指定版本号的 webpack
,不加版本号则是最新版
安装完成后的 package.json
安装完成后的项目目录
-
修改
package.json
-
打包
# 命令语句 源文件 目标文件 npm run start src/main.js dist/bundle.js
如果没有 dist
目录则自动新建
-
打包结果
在
webpack-3.10.0
目录下创建index.html
文件,引入之前打包好的bundle.js
文件
<!DOCTYPE html>
<html>
<head>
<title>webpack-3.10.0</title>
</head>
<body>
<h1>Hello World!</h1>
<script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>
- 我们同样可以把打包的语句直接写在
package.json
中,免得每次输入很麻烦"start":"webpack src/main.js dist/bundle.js"
这样我们在命令行中直接调用
npm run start
也能实现打包的效果
- 现在有个问题,当我们修改
main.js
文件的内容时,刷新页面并不会显示更新的改动,如果想让页面同步的话,我们还需再执行一次npm run start
语句,每次这样未免太麻烦,可以通过以下几种方式改善:- 方法一:修改
package.json
中之前写好的start
语句
"start":"webpack src/main.js dist/bundle.js --watch",
- 方法二:新定义一个
watch
命令,这种方式根据官方文档说明,由于调用的是之前自定义的npm run start
命令,因此需要在--watch
前额外添加--
# package.json "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start":"webpack src/main.js dist/bundle.js", "watch":"npm run start -- --watch" },
- 方法一:修改
以第二种方式为例:
此时则监听成功,修改
main.js
保存则实时会在 bundle.js
中显示,页面中刷新即可展示;ctrl + c
终止监听。
使用配置文件
- 为了看出效果,我们先把之前生成的
bundle.js
文件删掉。 - 在
webpack-3.10.0
目录下创建webpack.config.js
,并输入如下内容
# webpack.config.js
var webpack = require("webpack");
module.exports = {
entry:'./src/main.js',
output:{
path:'./dist',
filename:'bundle.js'
}
}
此时你的项目结构应该是这样的,dist
目录下 空空如也:
-
跑一下试试
原因是output
中的路径需要是绝对路径absolute path
-
在配置文件中引入
path
模块解决绝对路径问题var webpack = require("webpack"); var path = require("path"); module.exports = { entry:'./src/main.js', output:{ path:path.resolve(__dirname,'./dist'), filename:'bundle.js' } }
-
由于添加了配置文件,因此需要修改一下
package.json
中的启动命令npm run start
更改为如下(因为配置文件中已经设置了路径及文件名,因此不需要命令中再指定)"start":"webpack",
-
跑一下
效果是一样的
CSS 处理
- 在
src
目录下创建main.css
# main.css body{ background: orange; }
- 修改
main.js
# main.js require('./main.css')
- 使用
npm run watch
命令会报错
缺少loader
,这里引用官网说明:
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
- 处理
css
需要安装一个css-loader
的包:npm install css-loader --save-dev
- 安装完成后需要在配置文件中进行处理,注意
module
属性:
# webpack.config.js
var webpack = require("webpack");
var path = require("path");
module.exports = {
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'./dist'),
filename:'bundle.js'
},
module:{
rules:[{
test:/\.css$/, // 正则匹配 .css 后缀
use:'css-loader'
}]
}
}
再跑一下
看一下是否被打包到
bundle.js
中可以看到
main.css
的样式的确被打包到 bundle.js
中了,但为什么浏览器中没有效果?
- 安装
style-loader
npm install style-loader --save-dev
- 修改配置文件,注意:
style-loader
需要写在前面
- 再调用命令
npm run watch
将 ES6 代码编辑为所有浏览器通用的代码
- 将
main.js
内容改为一段ES6
的代码# main.js let a = 11; const b = 22; class Foo{ }
- 直接调用
npm run watch
会发现bundle.js
中的代码依旧为ES6
- 这时需要 Babel 这个工具
Babel 的作用就是将下一代的 JavaScript 语法转换为现今浏览器兼容的语句
- 首先安装
Babel
npm install --save-dev babel-loader babel-core
- 在
webpack.config.js
中添加一条规则:
其中,{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
test
用于判断扩展名为.js
的文件,exclude
表示不包括的文件。
添加规则后,此时的webpack.config.js
文件应该是这样的
- 安装转换
ES2015
及更高版本JavaScript
语法的 env presetnpm install babel-preset-env --save-dev
- 在根目录
webpack-3.10.0
下创建.babelrc
文件,内容如下:{ "presets": ["env"] }
- OK,现在执行命令
npm run watch
,可以看到我们之前main.js
中的语句在bundle.js
中已经成功转换成通用语句了
本节内容可直接参考Babel
官网:https://babeljs.cn/
文件压缩
- 文件压缩需要用
webpack
的插件来实现,比如webpack
自带一个BannerPlugin
插件,用于添加顶部注释,首先在webpack.config.js
中添加如下代码:plugins:[ new webpack.BannerPlugin('顶部注释插件') ]
- 重新打包
npm run watch
,成功后,bundle.js
中顶部出现注释
-
webpack
有个自带的插件UglifyJsPlugin
用于压缩文件
plugins:[
new webpack.BannerPlugin('顶部注释插件'),
new webpack.optimize.UglifyJsPlugin()
]
重新打包后的 bundle.js
- 然而我们在开发调试阶段是不需要压缩代码的,因此需要对开发环境和线上环境做个区分,开发环境不压缩代码,线上环境才压缩
如果是线上环境,则将if(process.env.NODE_ENV === 'production'){ module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin()) }
UngifyJsPlugin
插件填入webpack
的plugins
中 - 回到命令行调用命令
set NODE_ENV=production // 设置为生产环境, windows 系统 npm run watch
- 我们可以直接在
package.json
中添加脚本命令(我尝试了几种写法,发现只有这样是有效的,不知道为什么。此外,有时这样也不好用,需要在命令行中手动制定一次set NODE_ENV=production
,之后调用npm run production
就有效了)"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack", "watch": "npm run start -- --watch", "production":"set NODE_ENV=production && npm run watch", "development":"set NODE_ENV=development && webpack --watch" }
这样在命令行中通过 npm run development
即可切换为开发环境(代码不压缩),npm run production
就是生产环境(代码压缩)
- 对
webpack.config.js
简单做一下整理
var webpack = require("webpack");
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production'
module.exports = {
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'./dist'),
filename:'bundle.js'
},
module:{
rules:[{
test:/\.css$/,
use:['style-loader','css-loader']
},{
test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"
}]
},
plugins:[
new webpack.BannerPlugin('顶部注释插件'),
]
}
if(isProduction){
module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}
SASS 处理
- 安装相关
loader
npm install sass-loader node-sass webpack --save-dev
- 这里我在安装
node-sass
时失败了,改为分别单独安装,node-sass
使用淘宝镜像 其他解决方案# 安装 sass-loader npm install sass-loader --save-dev # 安装 node-sass npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
- 修改配置文件
# webpack.config.js module:{ rules:[{ test: /\.scss$/, use: [ "style-loader", // creates style nodes from JS strings "css-loader", // translates CSS into CommonJS "sass-loader" // compiles Sass to CSS ] },{ test:/\.css$/, use:['style-loader','css-loader'] },{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }] },
- 修改
mian.js
# main.js require('./main.scss')
- 修改
main.css
为main.scss
并输入scss
语句测试# main.scss $default:pink; body{ background:$default }
重新打包,OK
CSS 与 JS 分离
- 通常
webpack
建议所有文件都打包成一个单独的文件,这样可以减少网络请求。但如果有需要分类打包的话,需要使用webpack
的一个外部插件 ExtractTextWebpackPlugin - 安装
npm install --save-dev extract-text-webpack-plugin
- 修改配置文件,注意注释部分
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin"); // 引入插件
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production';
module.exports = {
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'./dist'),
filename:'[name].js'
},
module:{
rules:[{
test: /\.scss$/,
use: ExtractTextPlugin.extract({ // 使用插件
fallback: "style-loader", // 用哪个 loader 加载
use: [{
loader:"css-loader",
options:{
minimize:isProduction // 是否压缩 css
}},
"sass-loader"] // 将资源转换为 css
})
},{
test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"
}]
},
plugins:[
new webpack.BannerPlugin('顶部注释插件'),
new ExtractTextPlugin("[name].css"), // 输出为 style.css 文件
]
}
if(isProduction){
module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}
文件处理 file-loader 与 url-loader
-
首先在
src
目录下新建images
目录并存入两个大小不一的图片
-
在
index.html
及main.scss
中引入两个图片
-
安装
file-loader
npm install --save-dev file-loader
-
修改配置文件
module:{ rules:[{ test: /\.scss$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: [{ loader:"css-loader", options:{ minimize:isProduction }}, "sass-loader"] }) },{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" },{ test:/\.png|jpe?g|gif$/, // 匹配的图片格式 use:['file-loader'] // 使用 file-loader }] }
-
执行
npm run production
,图片被打包并以hash
方式重新命名
-
也可以让图片以原有名字和后缀保存:
{ test:/\.png|jpe?g|gif$/, use:[{ loader:'file-loader', options:{ name:'[name].[ext]' // 以原有名字和后缀保存 } }] }
- 也可以创建指定目录存放文件
或,注意options:{ name:'images/[name].[ext]' }
outputPath
的/
不能少options:{ name:'[name].[ext]', outputPath:'images/' }
效果就是这样
- 至于
url-loader
,它可以限制图片的大小,小于一定值的图片将以DataURL
直接嵌入在页面中,减少请求数 - 安装
npm install --save-dev url-loader
- 修改配置文件
use:[{ loader:'url-loader', options:{ limit:20480, // 小于该值将嵌入页面 name:'[name].[ext]', outputPath:'images/' } }]
-
打包后可看到只有一个图片被打包,另一个图片直接嵌在了页面中:
多入口及自动清理
- 尝试改一下入口属性
entry:{app:'./src/main.js'},
这样生成的 js
和 css
文件将变成 app.js
和 app.css
- 先安装一个
jquery
包,注意名字小写npm install --save-dev jquery
- 修改配置文件
entry:{ main:'./src/main.js', // 将 main.js 打包成 main vendor:'jquery' // 将 jquery 打包成 vendor }
- 自动清理需要 clean-webpack-plugin 插件
npm install clean-webpack-plugin --save-dev
- 如果我们在生成的文件中添加
hash
值会发现,每次打包由于hash
导致名字的不同,进而会出现不同名的同文件,这显然不是我想要的。这个插件就可以用于每次打包前先清除指定目录或文件,避免重复。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
+ new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};