安装及问题
-
全局安装
cnpm i webpack -g
-
安装问题及解决
// 问题 We will use "npm" to install the CLI via "npm install -D webpack-cli". Do you want to install 'webpack-cli' (yes/no): no You need to install 'webpack-cli' to use webpack via CLI. // 解决 // 参考 https://blog.csdn.net/qq_43238599/article/details/97026566 这里提示安装 webpack-cli// 是因为到了webpack4, webpack 已经将 webpack 命令行相关的内容都迁移到 webpack-cli,所以除了 webpack 外,我们还需要安装 webpack-cli: npm install --save-dev webpack-cli -g
-
检查是否安装成功
webpack -v
使用
新建webpack.config.js
// 指定打包入口和出口‘
module.exports = {
entry: './src/app.js',
output: {
filename: './dist/app.bundle.js'
}
};
在package.json中配置命令
{
"name": "01_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack -d --watch",
"prod": "webpack -p"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"webpack": "^3.0.0"
},
"devDependencies": {
"webpack": "^3.0.0"
}
}
// -d 这个参数之前没介绍过,它的意思就是说包含 source maps,这个有什么用呢,就是让你在用浏览器调试的时候,可以很方便地定位到源文件
命令启动
npm run dev
npm run prod
puglins插件
html-Webpack-plugin 处理html
-
插件地址https://github.com/jantimon/html-webpack-plugin
-
安装
cnpm install html-webpack-plugin@3.2.0 --save-dev
-
使用
const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: 'index.js', output: { path: __dirname + '/dist', filename: 'index_bundle.js' }, plugins: [ new HtmlWebpackPlugin() ] }
-
细节配置
const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { entry: './src/app.js', output: { path: __dirname + '/dist', filename: 'app.bundle.js' }, plugins: [ new HtmlWebpackPlugin({ title: 'Custom template', // Load a custom template (lodash by default) // 页面模板 template: './src/index.html', // 压缩html minify: { // 去除文件空格 collapseWhitespace: true, }, }) ] }
-
template对应的html模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1, maximum-scale=1, user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.js"></script> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> hello </body> </html>
extract-text-webpack-plugin 把 CSS 分离成文件
-
安装
cnpm install --save-dev extract-text-webpack-plugin@2.1.2
-
使用
const HtmlWebpackPlugin = require("html-webpack-plugin"); const ExtractTextPlugin = require("extract-text-webpack-plugin"); const webpack = require('webpack'); module.exports = { entry: "./src/app.js", output: { path: __dirname + "/dist", filename: "app.bundle.js", }, // 插件 plugins: [ // 处理打包的html new HtmlWebpackPlugin({ title: "Custom template", // Load a custom template (lodash by default) template: "./src/index.html", minify: { collapseWhitespace: true, }, hash: true, }), // 分离打包后的css new ExtractTextPlugin("style.css"), // 添加 hmr plugin new webpack.HotModuleReplacementPlugin() ], module: { rules: [ { test: /\.scss$/i, // 自右向左处理 use: ExtractTextPlugin.extract({ fallback: "style-loader", use: ["css-loader", "sass-loader"], }), }, }, // devServer devServer: { //表示服务器将从哪个目录去查找内容文件(即页面文件,比如 HTML) // contentBase: path.join(__dirname, "dist"), port: 9000, open: true, // 将 webpack-dev-server 的重载代码添加到产出的 bundle 中 // inline: true, // 开启 hmr 支持 hot: true, }, };
clean-webpack-plugin 清除
-
安装
cnpm i clean-webpack-plugin@0.1.17 --save-dev
-
引入
const CleanWebpackPlugin=require('clean-webpack-plugin');
-
在plugins中使用
// 清除之前的打包 new CleanWebpackPlugin(['dist'])
uglifyjs-webpack-plugin 压缩js
我们需要在webpack.config.js中引入uglifyjs-webpack-glugin插件
const uglify = `require`('uglifyjs-webpack-plugin');
引入后在plugins配置里new一个 uglify对象就可以了,代码如下。
plugins:[
new uglify()
],
autoprefixer(自动添加前缀的插件)
自动处理css3属性前缀
PostCSS
PostCSS是一个CSS的处理平台,它可以帮助你的CSS实现更多的功能,但是今天我们就通过其中的一个加前缀的功能,初步了解一下PostCSS。
安装
需要安装两个包postcss-loader 和autoprefixer(自动添加前缀的插件)
cnpm i postcss-loader@3.0.0 autoprefixer@8.0.0 -D
postcss.config.js
postCSS推荐在项目根目录(和webpack.config.js同级),建立一个postcss.config.js文件。
postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
这就是对postCSS一个简单的配置,引入了autoprefixer插件。让postCSS拥有添加前缀的能力,它会根据 can i use 来增加相应的css3属性前缀。
编写loader
对postcss.config.js配置完成后,我们还需要编写我们的loader配置。
{
test: /\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true
}
}, {
loader: "postcss-loader"
}
]
}
提取CSS
配置提取CSS的loader配置.
{
test: /\.css$/,
use: extractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader'
]
})
}
总结:postcss还有很多功能,我希望小伙伴学会自学。这里给出postcss-loader的github地址:https://github.com/postcss/postcss-loader
PurifyCSS-webpack消除未使用的css
PurifyCSS
使用PurifyCSS可以大大减少CSS冗余,比如我们经常使用的BootStrap(140KB)就可以减少到只有35KB大小。这在实际开发当中是非常有用的。
安装PurifyCSS-webpack
从名字你就可以看出这是一个插件,而不是loader。所以这个需要安装还需要引入。 PurifyCSS-webpack要以来于purify-css这个包,所以这两个都需要安装。
npmn i -D purifycss-webpack purify-css
这里的-D代表的是–save-dev ,只是一个简写。
引入glob
因为我们需要同步检查html模板,所以我们需要引入node的glob对象使用。在webpack.config.js文件头部引入glob。
const glob = `require`('glob');
引入purifycss-webpack
同样在webpack.config.js文件头部引入purifycss-webpack
const PurifyCSSPlugin = `require`("purifycss-webpack");
配置plugins
引入完成后我们需要在webpack.config.js里配置plugins。代码如下,重点看标黄部分。
plugins:[
//new uglify()
new htmlPlugin({
minify:{
removeAttrubuteQuotes:true
},
hash:true,
template:'./src/index.html'
}),
new extractTextPlugin("css/index.css"),
new PurifyCSSPlugin({
// Give paths to parse for rules. These should be absolute!
paths: glob.sync(path.join(__dirname, 'src/*.html')),
})
]
这里配置了一个paths,主要是需找html模板,purifycss根据这个配置会遍历你的文件,查找哪些css被使用了。
**注意:**使用这个插件必须配合extract-text-webpack-plugin这个插件,这个插件在前边的课程已经讲解过了。如果你还不会请自学一下。
配置好上边的代码,我们可以故意在css文件里写一些用不到的属性,然后用webpack打包,你会发现没用的CSS已经自动给你删除掉了。在工作中记得一定要配置这个plugins,因为这决定你代码的质量,非常有用。
loader加载器
处理样式
css-loader 和 style-loader 处理 CSS
-
安装
cnpm install --save-dev css-loader@3.3.0 cnpm install --save-dev style-loader@1.0.0
-
报错
TypeError: this.getResolve is not a function at Object.loader (/Users/honor/Downloads/note/webapck学习/webpack3/01_demo/node_modules/_css-loader@5.2.0@css-loader/dist/index.js:62:27)
-
解决参考
- https://blog.csdn.net/qq_36069339/article/details/100544821
- https://blog.csdn.net/qq_43377853/article/details/108485499
-
在webpack.config.js中配置规则
var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/app.js', output: { path: __dirname + '/dist', filename: 'app.bundle.js' }, plugins: [new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html', minify: { collapseWhitespace: true, }, hash: true, })], module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] } };
sass-loader 把 SASS 编译成 CSS
-
安装
cnpm install sass-loader@7.0.0 node-sass --save-dev
-
报错
// sass-loader版本过高运行错误 TypeError: this.getOptions is not a function // 指定版本即可
-
在webpack.config.js中配置相应的规则
var HtmlWebpackPlugin = require('html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { entry: './src/app.js', output: { path: __dirname + '/dist', filename: 'app.bundle.js' }, plugins: [new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html', minify: { collapseWhitespace: true, }, hash: true, }), new ExtractTextPlugin('style.css') ], module: { rules: [ { test: /\.scss$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', //resolve-url-loader may be chained before sass-loader if necessary use: ['css-loader', 'sass-loader'] }) } ] } };
postcss-loader 配合autoprefixer插件处理css前缀
处理图片
file-loader 解决引用路径的问题
拿background样式用url引入背景图来说,我们都知道,webpack最终会将各个模块打包成一个文件,因此我们样式中的url路径是相对入口html页面的,而不是相对于原始css文件所在的路径的。这就会导致图片引入失败。这个问题是用file-loader解决的,file-loader可以解析项目中的url引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件
-
安装
cnpm install --save-dev file-loader@4.0.0
-
在rules中配置
{ test: /\.(png|jpe?g|gif|svg)$/i, use: [ { loader: 'file-loader', options: { // [name] 代表文件名,[ext] 代表文件扩展名,outputPath 是输出的路径 name: '[name].[ext]', outputPath: 'img/', }, }, ], },
url-loader 将图片编码
如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy
配置url-loader
我们安装好后,就可以使用这个loader了,记得在loader使用时不需要用require引入,在plugins才需要使用require引入。
webpack.config.js文件
//模块:例如解读CSS,图片如何转换,压缩
module:{
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},{
test:/\.(png|jpg|gif)/ ,
use:[{
loader:'url-loader',
options:{
limit:500000
}
}]
}
]
},
- test:/.(png|jpg|gif)/是匹配图片文件后缀名称。
- use:是指定使用的loader和loader的配置参数。
- limit:是把小于500000B的文件打成Base64的格式,写入JS。
写好后就可以使用webpack进行打包了,这回你会发现打包很顺利的完成了。具体的Base64的格式,你可以查看视频中的样子。
为什么只使用了url-loader
有的小伙伴会发现我们并没有在webpack.config.js中使用file-loader,但是依然打包成功了。我们需要了解file-loader和url-loader的关系。url-loader和file-loader是什么关系呢?简答地说,url-loader封装了file-loader。url-loader不依赖于file-loader,即使用url-loader时,只需要安装url-loader即可,不需要安装file-loader,因为url-loader内置了file-loader。通过上面的介绍,我们可以看到,url-loader工作分两种情况:
1.文件大小小于limit参数,url-loader将会把文件转为DataURL(Base64格式);
2.文件大小大于limit,url-loader会调用file-loader进行处理,参数也会直接传给file-loader。
也就是说,其实我们只安装一个url-loader就可以了。但是为了以后的操作方便,我们这里就顺便安装上file-loader。
处理html
html-loader 发布HTML
-
安装
cnpm install --save-dev html-loader
-
配置rules
{ test: /\.html$/, use: [ { loader: 'html-loader', options: { minimize: true, hash:true, template:'./src/index.html' } }], }
-
minify:是对html文件进行压缩,removeAttrubuteQuotes是却掉属性的双引号。
-
hash:为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。
-
template:是要打包的html模版路径和文件名称。
image-webpack-loader 压缩图片
-
安装
cnpm install image-webpack-loader --save-dev
-
在webpack.config.js中配置
{ test: /\.(gif|png|jpe?g|svg)$/i, use: [ { loader: 'file-loader', options: { name: '[name].[ext]', outputPath: 'images/' } }, { loader: 'image-webpack-loader', options: { bypassOnDebug: true, } } ] }, { test: /\.html$/, use: [ { loader: 'html-loader', options: { minimize: true } }], }
webpack-dev-derver本地开发服务
-
文档
- https://github.com/webpack/webpack-dev-server
- https://webpack.js.org/configuration/dev-server/#devserver
-
原理
-
webpack-dev-server是一个基于 Express 的本地开发服务器(看 Roadmap 下个版本内核会从 Express 切换到 Koa)。它使用 webpack-dev-middleware 中间件来为通过 Webpack 打包生成的资源文件提供 Web 服务。它还有一个通过 Socket IO 连接着 webpack-dev-server 服务器的小型运行时程序。webpack-dev-server 发送关于编译状态的消息到客户端,客户端根据消息作出响应。
-
Tips:简单来说 webpack-dev-server 就是一个 Express 的小型服务器,它是通过 Express 的中间件 webpack-dev-middleware和 Webpack 进行交互的。所以我们如果自己的项目本身就是个 Express 服务器,那么可以使用 webpack-dev-middleware 和 webpack-hot-middleware 两个中间件来实现 HMR 功能。关于 webpack-dev-middleware 和 webpack-hot-middleware 中间件来实现 webpack-dev-server 的内容
-
-
安装
cnpm install -g webpack-dev-server cnpm install --save-dev webpack-dev-server@
-
在package.json中配置
{ "name": "01_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack -d --watch", "prod": "webpack -p", "serve": "webpack-dev-server" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "webpack": "^3.0.0", "webpack-cli": "^2.0.13" }, "devDependencies": { "css-loader": "^3.3.0", "extract-text-webpack-plugin": "^2.1.2", "html-webpack-plugin": "^3.2.0", "node-sass": "^5.0.0", "sass-loader": "^7.0.0", "style-loader": "^1.0.0", "webpack": "^3.0.0", "webpack-cli": "^2.0.13", "webpack-dev-server": "^2.9.7" } }
-
在webpack.config.js中配置
// devServer devServer: { //表示服务器将从哪个目录去查找内容文件(即页面文件,比如 HTML) // contentBase: path.join(__dirname, "dist"), port: 9000, open: true, // 将 webpack-dev-server 的重载代码添加到产出的 bundle 中 // inline: true, // 开启 hmr 支持 hot: true, },
命令行
webpack-dev-server 安装之后,会提供一个 bin 命令行,通过命令行可以启动对应的服务。
# 项目中安装 webpack-dev-server
npm i webpack-dev-server
# 使用 npx 启动
npx webpack-dev-server
执行webpack-dev-server
命令之后,它会读取 Webpack 的配置文件(默认是 webpack.config.js)然后将文件打包到内存中(所以看不到dist
文件夹的生产,Webpack 会打包到硬盘上),这时候打开 server 的默认地址:localhost:8080
就可以看到文件目录或者页面(默认是显示 index.html,没有则显示目录)。
跟webpack-cli
一样,webpack-dev-server
也有一些选项可以添加:
# 修改端口号和 host
webpack-dev-server --port 3000 --host 127.0.0.1
# 启动inline 模式的自动刷新
webpack-dev-server --hot --inline
# 手动指定 webpack config 文件
webpack-dev-server --config webpack.xxx.js
# 指定 webpack 的 mode
webpack-dev-server --mode development
# watch 功能,文件发生变化则触发重新编译
webpack-dev-server --watch
# dev-server默认会将工作目录(当前目录)作为基本目录,可以手动修改它
webpack-dev-server --content-base ./build
上面只介绍了常用的并且比较重要的一些命令行选项,要查看全部,可以使用webpack-dev-server -h
查看帮助。
我们还可以将webpack-dev-server
放到package.json
的scripts
里面,例如下面的例子,执行npm run dev
实际就是执行的对应webpack-dev-server
命令:
{
"scripts": {
"dev": "webpack-dev-server --mode development --config webpack.config.dev.js --hot --inline --port 3000"
}
}
自动刷新
在开发中,我们希望边写代码,边看到代码的执行情况,webpack-dev-server 提供自动刷新页面的功能可以满足我们的需求。webpack-dev-server 支持两种模式的自动刷新页面。
- iframe 模式:页面被放到一个 iframe 内,当发生变化时,会重新加载;
- inline 模式:将 webpack-dev-server 的重载代码添加到产出的 bundle 中。
两种模式都支持模块热替换(Hot Module Replacement)。模块热替换的好处是只替换更新的部分,而不是整个页面都重新加载。
使用方式:webpack-dev-server --hot --inline
是开启inline
模式的自动刷新。
在开发中,我们希望边写代码,边看到代码的执行情况,webpack-dev-server 提供自动刷新页面的功能可以满足我们的需求。webpack-dev-server 支持两种模式的自动刷新页面。
- iframe 模式:页面被放到一个 iframe 内,当发生变化时,会重新加载;
- inline 模式:将 webpack-dev-server 的重载代码添加到产出的 bundle 中。
两种模式都支持模块热替换(Hot Module Replacement)。模块热替换的好处是只替换更新的部分,而不是整个页面都重新加载。
使用方式:webpack-dev-server --hot --inline
是开启inline
模式的自动刷新。
Hot Module Replacement
HMR 即模块热替换(Hot Module Replacement)的简称,它可以在应用运行的时候,不需要刷新页面,就可以直接替换、增删模块。
Webpack 可以通过配置 webpack.HotModuleReplacementPlugin
插件来开启全局的 HMR 能力,开启后 bundle
文件会变大一些,因为它加入了一个小型的 HMR 运行时(runtime),当你的应用在运行的时候,Webpack 监听到文件变更并重新打包模块时,HMR 会判断这些模块是否接受 update,若允许,则发信号通知应用进行热替换。
要开启 HMR 功能,需要三步:
-
设置
devServer.hot=true
devServer.inline=true
(默认);
devServer.hot=true
:会给 entry 添加webpack/hot/dev-serve
或者webpack/hot/only-dev-serve
(devServer.hotOnly=true
),这个是实现 HMR 的服务端代码;devServer.inline=true
:会给 entry 添加webpack-dev-server/client
,这是通信客户端;
-
在
webpack.config.js
中添加 plugins:new webpack.HotModuleReplacementPlugin()
; -
修改入口文件添加 HMR 支持代码:
// 在入口文件index.js最后添加如下代码
if (module.hot) {
// 通知 webpack 该模块接受 hmr
module.hot.accept(err => {
if (err) {
console.error('Cannot apply HMR update.', err);
}
});
}
最终修改后的webpack.config.js
内容如下:
const path = require('path');
module.exports = {
entry: './src/index.js',
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: 9000,
// 开启 hmr 支持
hot: true
},
plugins: [
// 添加 hmr plugin
new webpack.HotModuleReplacementPlugin()
]
};
经过上面配置之后,再次执行webpack-dev-server
,打开http://localhost:9000
,然后修改index.js
内容,就能看到效果了
Tips:使用 webpack-dev-server 的 CLI 功能只需要命令行中添加
--hot
,webpack-dev-server 会自动将webpack.HotModuleReplacementPlugin
这个插件添加到 Webpack 的配置中去,所以开启 HotModuleReplacementPlugin 最简单的方式就是使用 inline 模式(命令行添加--inline
)
proxy
在实际开发中,本地开发服务器是不能直接请求线上数据接口的,这是因为浏览器的同源安全策略导致的跨域问题,我们可以使用devServer.proxy
来解决本地开发跨域的问题。
下面的配置是将页面访问的/api
所有请求都转发到了baidu.com
上:
module.exports = {
//...
devServer: {
proxy: {
'/api': 'http://baidu.com'
}
}
};
devServer.proxy的值还支持高级属性,通过高级属性我们可以做更多的事情,如上面的需求变成,将/api/users转发到http://baidu.com/users,那么配置就需要改成:
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://baidu.com',
pathRewrite: {'^/api': ''}
}
}
}
};
如果我们需要转发的网站是支持 https 的,那么需要增加secure=false
,来防止转发失败:
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'https://baidu.com',
secure: false,
pathRewrite: {'^/api': ''}
}
}
}
};
又有新的需求了,这时候只能代理json
接口的数据,对于html
文件,还是使用打包后 dist 文件夹中文件,那么我们使用bypass
来实现这个需求:
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://baidu.com',
bypass(req, res, proxyOptions) {
// 判断请求头中的 accept 值
if (req.headers.accept.indexOf('html') !== -1) {
console.log('Skipping proxy for browser request.');
// 返回的是 contentBase 的路径
return '/index.html';
}
}
}
}
}
};
或者,我们需要代理http://baidu.com
下面的/api
和/auth
两个地址,其他的地址都放行,这时候可以使用context
:
module.exports = {
//...
devServer: {
proxy: [
{
context: ['/auth', '/api'],
target: 'http://baidu.com'
}
]
}
};
自定义中间件
在 webpack-dev-server 中有两个时机可以插入自己实现的中间件,分别是在devServer.before
和devServer.after
两个时机,即 webpack-dev-server 加载所有内部中间件之前和之后两个时机。
module.exports = {
//...
devServer: {
before(app, server) {
app.get('/some/path', (req, res) => {
res.json({custom: 'response'});
});
}
}
};
自定义中间件在开发中常常被用来当作 mock server 使用。
详情参见https://juejin.cn/post/6844903606420766734
Webpack Dev Server 常用配置
devServer.historyApiFallback
:配置如果找不到页面就默认显示的页面;devServer.compress
:启用 gzip 压缩;devServer.hotOnly
:构建失败的时候是否不允许回退到使用刷新网页;devServer.inline
:模式切换,默认为内联模式,使用false
切换到 iframe 模式;devServer.open
:启动后,是否自动使用浏览器打开首页;devServer.openPage
:启动后,自动使用浏览器打开设置的页面;devServer.overlay
:是否允许使用全屏覆盖的方式显示编译错误,默认不允许;devServer.port
:监听端口号,默认 8080;devServer.host
:指定 host,使用0.0.0.0
可以让局域网内可访问;devServer.contentBase
:告诉服务器从哪里提供内容,只有在你想要提供静态文件时才需要;devServer.publicPath
:设置内存中的打包文件的虚拟路径映射,区别于output.publicPath
;devServer.staticOptions
:为 Expressjs 的express.static
配置参数,参考文档: http://expressjs.com/en/4x/api.html#express.staticdevServer.clientLogLevel
:在 inline 模式下用于控制在浏览器中打印的 log 级别,如error
,warning
,info
ornone
;devServer.quiet
:静默模式,设置为true
则不在控制台输出 log;devServer.noInfo
:不输出启动 log;devServer.lazy
: 不监听文件变化,而是当请求来的时候再重新编译;devServer.watchOptions
:watch 相关配置,可以用于控制间隔多少秒检测文件的变化;devServer.headers
:自定义请求头,例如自定义 userAgent 等;devServer.https
:https 需要的证书签名等配置。
Webpack 中配置React和Vue开发环境
Webpack 中配置 React 的开发
首先是创建目录、初始化 package.json、安装 React、安装 Webpack 和安装 Babel。
# 新建目录,并且进入
mkdir react-webpack && cd $_
# 创建 package.json
npm init -y
# 安装 react react-dom依赖
cnpm i react react-dom -S
# 安装 webpack 和 webpack-cli 开发依赖
npm i webpack webpack-cli -D
# 安装 babel
cnpm i babel-loader@7.1.5 @babel/core @babel/preset-env -D
# 安装 babel preset-react
cnpm i @babel/preset-react -D
#创建 .babelrc 文件
{
"presets": ["env", "react"]
}
因为 React 中提供了一种 JavaScript 的扩展语法,React 将它们命名为 jsx,所以在这里我们需要给 jsx 文件添加 Babel 的编译支持,现在我们新建一个 webpack.config.js 的配置文件,内容和注释如下:
使用babel-loader
- 安装
cnpm install --save-dev babel-loader@7.1.5
-
问题
-
Module build failed: Error: Plugin/Preset files are not allowed to export objects
-
解决 https://blog.csdn.net/ljxzuishuai/article/details/103886908
-
Error:Node Sass version 5.0.0 is incompatible with ^4.0.0
-
解决 https://blog.csdn.net/weixin_42390302/article/details/109443294
-
-
在webpack.config.js中配置
module: { rules: [ { test: /\.scss$/i, // 自右向左处理 use: ExtractTextPlugin.extract({ fallback: "style-loader", use: ["css-loader", "sass-loader"], }), }, // 这两行是处理 react 相关的内容 { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ } ], },
react 组件
接着我们来准备一些 react 的代码,要来测试一下。
src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
复制代码
src/app.js
import css from './app.scss';
import React from 'react';
import ReactDOM from 'react-dom';
import Root from './Root';
ReactDOM.render(
<Root></Root>,
document.getElementById('root')
);
复制代码
src/Root.js
import React from 'react';
export default class Root extends React.Component {
render() {
return (
<div style={{textAlign: 'center'}}>
<h1>Hello World</h1>
</div>);
}
}
复制代码
效果如下:
参考链接:
- Setting up Webpack, Babel and React from scratch, revisited
- Setup a React Environment Using webpack and Babel
- Setting up React with Webpack 3.0, Yarn and Babel
配置多入口文件
-
多个entry
entry: { "app.bundle": './src/app.js', "contact":"./src/contact.js" },
-
多个HtmlWebpackPlugin
- chunks就是本文件,对应加载的文件
- excludeChunks就是除开该文件
plugins: [ // 处理打包的html new HtmlWebpackPlugin({ title: "Custom template", // Load a custom template (lodash by default) template: "./src/index.html", filename:"index.html", minify: { collapseWhitespace: true, }, hash: true, }), new HtmlWebpackPlugin({ title: "contact page", // Load a custom template (lodash by default) template: "./src/contact.html", filename:"contact.html", minify: { collapseWhitespace: true, }, hash: true, chunks:['contact'] }), // 分离打包后的css new ExtractTextPlugin("style.css"), // 添加 hmr plugin new webpack.HotModuleReplacementPlugin(), // 清除之前的打包 new CleanWebpackPlugin(['dist']) ],
模板引擎
hogan.js
https://www.cnblogs.com/zhangruiqi/p/8547268.html
http://twitter.github.io/hogan.js/
jade
https://github.com/pugjs/pug
-
安装
cnpm install pug --save-dev
raw-loader将文件转化为字符串
https://github.com/webpack-contrib/raw-loader
-
安装
cnpm install raw-loader --save-dev
pug-html-loader
-
安装
cnpm install pug-html-loader@1.1.5 --save-dev
将index.html文件后缀改为index.pug,并在webpack.config.js中配置规则
{ test: /\.pug$/, loader: ['raw-loader', 'pug-html-loader'] }
区分生产环境和开发环境
-
在package.json中定义环境变量NODE_ENV
"scripts": { "dev": "webpack-dev-server", "prod": "NODE_ENV=production webpack -p" },
-
在webpack.config.js中使用环境变量
var isProd = process.env.NODE_ENV === 'production'; // true or false
-
根据环境变量判断是开发环境,还是生产环境,从而决定是否分离css,做相应的extract-text-webpack-plugin插件处理
... var isProd = process.env.NODE_ENV === 'production'; // true or false var cssDev = ['style-loader', 'css-loader', 'sass-loader']; var cssProd = ExtractTextPlugin.extract({ fallback: 'style-loader', //resolve-url-loader may be chained before sass-loader if necessary use: ['css-loader', 'sass-loader'] }) var cssConfig = isProd ? cssProd : cssDev; module.exports = { ... plugins: [ ... new ExtractTextPlugin({ filename: 'style.css', disable: !isProd }), ... ], module: { rules: [ { test: /\.scss$/, use: cssConfig }, ... ] } };
打包后调试
在使用webpack时只要通过简单的devtool配置,webapck就会自动给我们生产source maps 文件,map文件是一种对应编译文件和源文件的方法,让我们调试起来更简单。
四种选项
在配置devtool时,webpack给我们提供了四种选项。
- source-map:在一个单独文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包速度;
- cheap-module-source-map:在一个单独的文件中产生一个不带列映射的map,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便。
- eval-source-map:使用eval打包源文件模块,在同一个文件中生产干净的完整版的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定要不开启这个选项。
- cheap-module-eval-source-map:这是在打包文件时最快的生产source map的方法,生产的 Source map 会和打包后的JavaScript文件同行显示,没有影射列,和eval-source-map选项具有相似的缺点。
四种打包模式,有上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的打包速度的后果就是对执行和调试有一定的影响。
个人意见是,如果大型项目可以使用source-map,如果是中小型项目使用eval-source-map就完全可以应对,需要强调说明的是,source map只适用于开发阶段,上线前记得修改这些调试设置。
简单的配置:
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
}
}
总结:调试在开发中也是必不可少的,但是一定要记得在上线前一定要修改webpack配置,在打出上线包。