全文介绍
本文主要介绍从0搭建一个React+webpack项目的过程,从而深刻了解webpack的基础用法。
1. 通过npm scripts执行webpack命令
上篇文章中我们通过 ./node_modules/.bin/webpack 执行打包任务,这样很不方便,现在介绍一种通过npm scripts执行构建的方式
修改package.json文件,在“scripts”对象中新增:"build": "webpack"
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
然后执行npm run build 即可执行webpack打包任务。 这种方式的原理是通过shell脚本在node_modules/.bin目录下创建一个软链接。
2.开始配置吧
2.1 使用babel-loader解析React和es新特性
首先在根目录下创建一个webpack的默认配置文件wenpack.config.js。然后安装react项目所需的react依赖。安装完成之后我们编写一个react组件。
/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
const MyComp = () => {
return <div>React & Webpack</div>
}
ReactDOM.render(
<MyComp />,
document.getElementById('app')
)
执行打包命令,不出意外,报错了。报错信息:
这是因为webpack开箱即用只支持JS和JOSN两种文件类型,我们需要通过loaders去支持其他文件类型并且把它们转化为有效模块。laoders的本事是一个函数,接受源文件作为参数,返回转换的结果。考虑到我们的项目,我们需要安装如下依赖:
- babel-loader 转换ES6,ES7等JS新特性语法。
- @babel/core和@babel/preset-env babel-loader的依赖
- @babel/preset-react react语法的解析配置 新增babel的配置文件.babelrc
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
在webpack.config.js的配置中增加对js文件的babel-loader的使用:
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
}
这样,再执行打包命令,就执行成功了。在打包后输出的dist文件夹中增加html文件,去加载打包出来的js文件看看效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React & Webpack</title>
</head>
<body>
<div id="app"></div>
<script src="./main.js"></script>
</body>
</html>
完美解析打包运行~
2.2 解析css和less
往往项目中还需要使用样式文件去修改我们的页面样式,webpack开箱即用也是不支持的,同理我们也需要使用laoder去解析样式文件。
- 解析css: 安装依赖:
- style-loader 将css-loader生成的内容,以style挂载到⻚面的heade部分
- css-loader 分析css模块之间的关系,并合成一个css
在webpack.config.js中增加配置
const path = require('path')
module.exports = {
...
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader']
+ }
]
}
}
laoder是按照从右至左的顺序加载的,所以css-loader要写在style-loader后面 给元素增加样式,并引入css文件
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
const MyComp = () => {
return <div className="red">React & Webpack</div>
}
ReactDOM.render(
<MyComp />,
document.getElementById('app')
)
//index.css
.red {
color: red;
}
打包完成后刷新浏览器,可以看到样式赋予成功,字体颜色修改为红色。
- 解析less 只需要在使用一个less-loader 安装less-loader依赖和less依赖(less-loader依赖于less),并在解析less文件时调用该loader即可。
const path = require('path')
module.exports = {
...
module: {
rules: [
...
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader']
+ },
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader', 'less-laoder']
+ }
]
}
}
2.3 解析文本图片
安装依赖:
- file-loader 解析图片、文本资源
在webpack.config.js中增加配置
const path = require('path')
module.exports = {
...
module: {
rules: [
...
+ {
+ test: /\.(png|jpg|jpeg|gif)$/,
+ use: 'file-loader'
+ }
]
}
}
上述2.2与2.3中最终运行效果:
3. webpack文件监听
在上面几个步骤中,我们每次修改项目代码都需要手动执行打包更新,这不仅繁琐而且耗时。webpack作为目前最流行的模块打包器之一,自然也考虑到了这一痛点。webpack支持文件监听模式,当文件改变时,自动重新执行打包命令。启用 Watch 模式。这意味着在初始构建之后,webpack 将继续监听任何已解析文件的更改。
3.1 配置方式
webpack开启文件监听有两种方式:
- webpack支持在CLI中传递--watch参数。
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --watch"
},
- 配置webpack.config.js中设置watch为true
3.2 原理分析
webpack文件监听的原理就是轮询判断文件的 最后编辑时间 是否发生改变,某个文件发生改变后,并不会立即告诉监听者,而是先缓存起来,等待aggregateTimeout。webpack会将这段时间内进行的任何其他更改都聚合到一次重新构建里。
module.export={
// 默认是false,不开启文件监听
watch: true,
watchOptions: {
// 不监听的文件或文件夹
ignored: /node_modules/,
// 监听到变化后,等待多长时间再去执行,单位ms
aggregateTimeout: 300,
// 轮询频次,默认每秒询问1000次
poll: 1000
}
}
4. webpack热更新
上述操作仍然需要通过手动刷新浏览器来同步代码修改内容,那有没有办法不刷新浏览器就达到目的呢?显然是有的。在webpack中有两种方式可以实现热更新:方式一借助webpack-dev-server(WDS)来实现热更新,WDS与打包不同,它不输出文件,而是放到内存中,因此构建速度更快。WDS一般还需要搭配HotModuleReplacementPlugin插件一起使用。方式二使用webpack-dev-middleware(WDM)来实现热更新。
4.1 WDS的使用
安装依赖webpack-dev-server(如果你和我一样安装是webpack5+,并且webpack-cli版本是4+,那么需要手动将webpack-cli版本降级为3,否则报错,方式可参考另一篇文章Cannot find module 'webpack-cli/bin/config-yargs'在package.json的scripts中增加dev命令
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --watch",
// --open 会自动打开默认浏览器
"dev": "webpack-dev-server --open"
},
在webpack.config.js中修改mode为development,并增加devServer。除此之外还需要使用webpack的HotModuleReplacementPlugin内置插件,来对webpack进行热更新增强。
const path = require('path')
const webpack = require('webpack')
module.exports = {
...
mode: 'development',
devServer: {
port: 9000,
contentBase: path.resolve(__dirname, './dist'),
hot: true
},
module: {
rules: [
...
]
}
}
然后执行 npm run dev,更改代码,查看浏览器,达到热更新效果。
4.2 WDM的使用
WDM需要借助node来实现,webpack输出的文件传输给服务器,一般适用于更加灵活地定制场景。
const express = require(’express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const app = express()
const config = require('./webpack.config.js)
const compiler = webpack(config)
app.use(webpackDevMiddleware(compiler), {
publicPath: config.output.publicPath
})
app.listen(8080, () => {
console.log('app listening on port 8080')
})