《React+Redux前端开发实战》—1.5.3 Hello World进阶
1.5.3 Hello World进阶
前面使用Webpack实现了最简单的项目构建,每次写完代码都需要手动刷新浏览器来查看实时效果。接下来继续完善上面的构建项目,实现如下功能:
项目启动,开启HTTP服务,自动打开浏览器;
实时监听代码变化,浏览器实时更新;
生产环境代码构建。
模块热替换(Hot Module Replacement,HMR)是Webpack中最令人兴奋的特性之一。当项目中的代码有修改并保存后,Webpack能实时将代码重新打包,并将新的包同步到浏览器,让浏览器立即自动刷新。
在开始配置前,读者可以先思考一个问题,如何实现浏览器实时更新呢?也许会想到让浏览器每隔一段时间向本地服务器发送请求,采用轮询(Polling)方式来实现;或者让服务器端来通知客户端,服务器端接收到客户端有资源需要更新,就主动通知客户端;或者直接使用WebSocket?
说明:WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC6455,并由RFC7936补充规范。
WebSocket API也被W3C定为标准。WebSocket使客户端和服务器端之间的数据交换变得更加简单,允许服务器端主动向客户端推送数据。以上信息参考来源于维基百科。
其实HMR原理就是上面说的那样,早期HMR的原理是借助于EventSource,后来使用了WebSocket。可以在本地开发环境开启一个服务,将其作为本地项目的服务端,然后与本地浏览器之间进行通信即可。欲了解详情,请读者自行学习。
注意:WebSocket是基于TCP的全双工通信协议。
大致了解了HMR的原理之后,开始动手实践吧。
实时更新的Hello World示例:
(1)首先,采用webpack-dev-server作为HMR的工具。在之前的项目基础上安装:
npm install webpack-dev-server –D
(2)修改webpack.config.js文件:
+ devServer: {
+ port: 3000,
+ contentBase: "./dist"
+ },
devServer.port是服务启动后的端口号,devServer.contentBase是配置当前服务读取文件的目录。启动后可以通过localhost:3000端口访问当前项目。
(3)修改package.json文件:
"scripts": {
+ "start": "webpack-dev-server --open --mode development",
"test": "echo \"Error: no test specified\" && exit 1"
},
按照上面配置start命令后,执行npm start会直接找到webpack.config.js来启动项目。
(4)最后安装html-webpack-plugin和clean-webpack-plugin。
npm install html-webpack-plugin clean-webpack-plugin -D
html-webpack-plugin插件用于简化创建HTML文件,它会在body中用script标签来包含我们生成的所有bundles文件。配置如下:
plugins: [
new HtmlWebpackPlugin({
template: "index.html",
// favicon: 'favicon.ico',
inject: true,
sourceMap: true,
chunksSortMode: "dependency"
})
]
clean-webpack-plugin插件在生产环境中编译文件时,会先删除build或dist目录文件,然后生成新的文件。
(5)随着文件的增、删,打包的dist文件内可能会产生一些不再需要的静态资源,我们并不希望将这些静态资源部署到服务器上占用空间,所以最好在每次打包前清理dist目录。在Webpack中配置如下:
plugins: [
new CleanWebpackPlugin(["dist"])
]
此时,Webpack代码清单如下:
var webpack = require("webpack");
var path = require("path");
const CleanWebpackPlugin = require("clean-webpack-plugin");
var BUILD_DIR = path.resolve(__dirname, "dist"); // 输出路径
var APP_DIR = path.resolve(__dirname, "src"); // 项目路径
const HtmlWebpackPlugin = require("html-webpack-plugin");
var config = {
entry: APP_DIR + "/index.jsx", // 项目入口
output: {
path: BUILD_DIR, // 输出路由
filename: "bundle.js" // 输出文件命名
},
module: {
rules: [
{
test: /\.(js|jsx)$/, // 编译后缀为js和jsx的格式文件
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
},
devServer: { // 在开发模式下,提供虚拟服务器用于项目开发和调试
port: 3000, // 端口号
contentBase: "./dist"
},
plugins: [ // 拓展Webpack功能
new HtmlWebpackPlugin({ // 生成HTML文件
template: "index.html",
// favicon: 'theme/img/favicon.ico',
inject: true,
sourceMap: true, // 是否生成sourceMap
chunksSortMode: "dependency"
}),
new CleanWebpackPlugin(["dist"]) // 清除文件
]
};
module.exports = config;
(6)在根目录终端执行npm run start:
AllandeMacBook-Pro:react-hello-world jack$ npm start
> myfirstapp@1.0.0 start /Users/allan/react-hello-world
> webpack-dev-server --open --mode development
// 删除dis文件
clean-webpack-plugin: /Users/alan/react-hello-world/dist has been removed.
wds: Project is running at http://localhost:3000/
wds: webpack output is served from /
wds: Content not from webpack is served from ./dist
wdm: wait until bundle finished: /
wdm: Hash: 4bfc0734100357258e1f
Version: webpack 4.23.1
Time: 1358ms
Built at: 2018-11-06 20:11:12
Asset Size Chunks Chunk Names
bundle.js 1.12 MiB main [emitted] main
index.html 342 bytes [emitted]
Entrypoint main = bundle.js
[0] multi ./node_modules/_webpack-dev-server@3.1.10@webpack-dev-server/ clienthttp://localhost:3000 ./src/index.jsx 40 bytes {main} [built]
[./node_modules/_ansi-html@0.0.7@ansi-html/index.js] 4.16 KiB {main} [built]
[./node_modules/_ansi-regex@2.1.1@ansi-regex/index.js] 135 bytes {main} [built]
[./node_modules/_events@1.1.1@events/events.js] 8.13 KiB {main} [built]
[./node_modules/_loglevel@1.6.1@loglevel/lib/loglevel.js] 7.68 KiB {main} [built]
[./node_modules/_react-dom@16.6.0@react-dom/index.js] 1.33 KiB {main} [built]
[./node_modules/_react@16.6.0@react/index.js] 190 bytes {main} [built]
[./node_modules/_strip-ansi@3.0.1@strip-ansi/index.js] 161 bytes {main} [built]
[./node_modules/_url@0.11.0@url/url.js] 22.8 KiB {main} [built]
[./node_modules/_webpack-dev-server@3.1.10@webpack-dev-server/client/index.jshttp://localhost:3000] ./node_modules/_webpack-dev-server@3.1.10@webpack-dev-server/clienthttp://localhost:3000 7.78 KiB {main} [built]
[./node_modules/_webpack-dev-server@3.1.10@webpack-dev-server/client/overlay.js] 3.58 KiB {main} [built]
[./node_modules/_webpack-dev-server@3.1.10@webpack-dev-server/client/socket.js] 1.05 KiB {main} [built]
[./node_modules/_webpack@4.23.1@webpack/hot/emitter.js] (webpack)/hot/emitter.js 75 bytes {main} [built]
[./node_modules/webpack/hot sync ^\.\/log$] ./node_modules/webpack/hot sync nonrecursive ^\.\/log$ 170 bytes {main} [built]
[./src/index.jsx] 2.22 KiB {main} [built]
+ 22 hidden modules
Child html-webpack-plugin for "index.html":
1 asset
Entrypoint undefined = index.html
[./node_modules/_html-webpack-plugin@3.2.0@html-webpack-plugin/lib/loader.js!./index.html] 506 bytes {0} [built]
[./node_modules/_lodash@4.17.11@lodash/lodash.js] 527 KiB {0} [built]
[./node_modules/_webpack@4.23.1@webpack/buildin/global.js] (webpack)/ buildin/global.js 489 bytes {0} [built]
[./node_modules/_webpack@4.23.1@webpack/buildin/module.js] (webpack)/ buildin/module.js 497 bytes {0} [built]
wdm: Compiled successfully.
此时,一旦项目内的文件有改动,就会自动执行编译,并通知浏览器自动刷新。
(7)至此开发配置已经完成,接下来配置生产命令,只需执行webpack-p即可。webpack -p表示压缩打包代码。在package.json内配置:
"scripts": {
"start": "webpack-dev-server --open --mode development",
+ "build": "webpack -p",
"test": "echo \"Error: no test specified\" && exit 1"
},
(8)打包的时候只需执行npm run build即可,打包成功会出现:
AllandeMacBook-Pro:react-hello-world allan$ npm run build
> myfirstapp@1.0.0 build /Users/allan/react-hello-world
> webpack -p
clean-webpack-plugin: /Users/allan/react-hello-world/dist has been removed.
Hash: 97bb34a13d3fc8cbfccc
Version: webpack 4.23.1
Time: 2647ms
Built at: 2018-11-06 20:22:45
Asset Size Chunks Chunk Names
bundle.js 110 KiB 0 [emitted] main
index.html 342 bytes [emitted]
Entrypoint main = bundle.js
[2] ./src/index.jsx 2.22 KiB {0} [built]
+ 7 hidden modules
Child html-webpack-plugin for "index.html":
1 asset
Entrypoint undefined = index.html
[0] ./node_modules/_html-webpack-plugin@3.2.0@html-webpack-plugin/lib/loader.js!./index.html 506 bytes {0} [built]
[2] (webpack)/buildin/global.js 489 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
+ 1 hidden module
上面的打包结果展示了此次打包的哈希值、耗时,以及打包后每个包的大小等信息。此时项目的结构为:
.
├── README.md
├── dist
│ ├── bundle.js
│ └── index.html
├── index.html
├── package-lock.json
├── package.json
├── src
│ └── index.jsx
└── webpack.config.js
以上项目的完整代码可以在https://github.com/khno/react-hello-world中下载,分支为dev。本书中后面章节的代码案例默认将以此为基础运行,读者可以自行下载。
- 点赞
- 收藏
- 关注作者
评论(0)