配置开发环境(webpack)以支持开发React项目
(本文介绍手动配置前端开发环境——构建工具链的核心部分,通常这部分我们都是通过前端框架官方脚手架自动搭建的,例如React 的 create-react-app 和 Vue的 Vue CLI。如果你想了解这些脚手架为我们做了什么,本文对你有用。)
当我们手动为了一支现代的「Web 应用」 准备开发环境,这个过程对于新手来说,不是特别的简单,尤其是当前端使用了像React框架的情况,因为社区生态(ecosystem)存在错综复杂的关系。这需要一些 分析,学习,和记录具体过程。
着手准备开发环境的思想准备是说,「全栈web 应用」 开发环境的「标准」到底是怎样的——怎样的生产效果是我们想要的,需要的,高效舒适的开发环境。还有,在技术上是一个怎样的处理过程。
什么是开发环境
我们可随意在本地文件系统中创建一个数据目录,并用npm初化一个 node 包($npm -init),并将VS CODE项目运行在这个目录里($code .),已经算是准备开发环境了。当然,很明显这种环境过于原始。
首先,我们必须明白,即使安装和配置高级的代码编辑器,也提供一定的开发舒适性,像智能提示,自动完成,甚至是提供了调试器,但是我们web 项目是 编辑器无关的,它不是这里所讲的主要的 开发环境配置;
另外,我们可以通用npm 为项目添加「项目源码依赖」($npm install),然而安装依赖包也不是在配置开发环境,因为源码依赖是项目功能的客观需要,不是在为开发操作提供舒适度。
通过以上二的对比,我们比较清楚认识到,在技术上,所谓配置开发环境,主要是指 通过npm 为项目添加「项目开发依赖」($npm install --save-dev)。至于,安装什么样的开发工具包,又怎样配置使用它们,社区则存在太多的观点和选项了。
「Reac 应用」 开发环境的「标准」
效果上,开发舒适[注]是配置开发环境的标准。技术上,由于前端和后端的环境非常不同,配置的任务也非常不同,例如后端node不受浏览器影响,可以直接使用现代JS功能。
后端由于是“一”,不受用户浏览器的“多”影响,天然具备开发舒适性,所以后端项目鲜有安装大量「项目开发依赖」,最常的一项是nodemon包,提供热加载,和调试功能;前端,则主要配置webpack 这个包。
注:舒适性受主观影响,受开发者智力,水平,价值风格影响
前端最基础的开发环境满足以下几点:
- 支持最新的ESM模块,ES6语法
- 支持web 模块,例如css ,png,font等 可以import
- Router, sass 等不是必须的
- ui库也是不必须的
- 支持 JSX, SFC等基本 方便创建 V组件
- 语法帮助 也是不是必须的
- 支持热加载的开发服务器
webpack 配置过程
以下记录了为React项目配置舒适开发环境的过程。全程假定你已经使用npm init创建一个项目目录,并且只列出相应的内容,自行创建源文件。
另外 webpack基础认识,请看我之前的这篇文章(《webpack与项目构建再认识》)。
1 安装 项目开发依赖(webpack webpack-cli)
webpack 和一般开发依赖相似,以D安装:
$ npm install webpack webpack-cli --save-dev
2 了解默认配置,以及打包概念
21 开发目录(src)和发布目录(dist)
开发目录:我们的前端开发,全程在一个“虚拟的”环境(./src) 上开发,可以使用ESM,ES6+ JSX等;
发布目录:它是构建(build)的目标所在,是可被拷走,用作部署到生产服务器的数据
22 配置文件 webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js', // 依赖入口
output: {
filename: 'main.js', // 最终打包好的文件
path: path.resolve(\_\_dirname, 'dist'), // 发布目录
},
};
23 APP页面 dist/index.html
这个是直接在输出目录安排的(手动静态),会有需要动态生成的前端页面,看下面
24 使用npm script执行 打包任务
package.json
{
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "^5.4.0",
"webpack-cli": "^4.2.0"
}
}
3 APP页面的“打包” 插件:html-webpack-plugin
上面的 23 中 index.html 是手动的,在大一点项目中,index.html 也会作为“源码模块”,需要动态打包
31 安装 html-webpack-plugin
$ npm i html-webpack-plugin --save-dev
32 在源码目录创建 index “模块”,并配置webpack
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "index.html")
})
]
};
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>React with Webpack</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
4 安装 webpack专用开发服务器
webpack-dev-server 是基于内存启动的,运行在内存中模拟出发布目录,这样可高效支持热加载。
41 webpack-dev-server
$ npm install webpack-dev-server --save-dev
42 使用npm script 启动服务器
更新package.json,增加一个dev script块:
"dev": "webpack serve --mode development"
Error: ENOSPC: System limit for number of file watchers reached, watch'所在文件路径' 解决方案
在终端按顺序执行下面两个命令即可解决问题
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p sudo sysctl --system
5 配置 清理任务
出口目录(output)不会被webpack跟踪的,所以随项目进展,可能会有“垃圾”,所以最好在每一次构建前先清理目录
51安装清理插件
npm install clean-webpack-plugin --save-dev
52 配置
webpack.config.js:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
...
plugins: [
...
new CleanWebpackPlugin()
],
6 配置 支持 ES6+
开始使用 loader,对「web 模块进行预处理」,这里第一个,当然是生出 ESM 模块——将ES6+的模块转译为ES5模块。
loader 与 plugins认识
这里补充一下loader和 plugins的知识,因为babel作一个 webpack loader 自己也因为功能丰富引入plugins,这个容易和webpack本身的插件机制混淆。
webpack 本身只支持ES5 JS的import 和bundling,webapp其它类型web模块 是通过 loader 实现的。例如 bable loader 支持 ES6 module import ;css loader 支持 css module import 。
61 安装 babel 核心以及转译插件
$ npm i @babel/core babel-loader @babel/preset-env --save-dev
62 配置babel支持ES6+ 转译
configure babel by creating a new file, babel.config.json
{
"presets": [
"@babel/preset-env"
]
}
63 配置 webpack 使用 babel loader
configure webpack to use the loader
module.exports = {
module: {
rules: [
{
test: /\\.js$/, //
exclude: /node_modules/,
use: ["babel-loader"]
}
]
},
plugins: []
};
7 配置支持 JSX
支持 JSX 和支持ES6 的性质很类似(另一个babel 插件),JSX可以看和ES6一样,是一种高级语法,需要转换。只是转换 React 特定的ES5模块。
71 安装 babel 插件
babel 核心前面已经安装了,这里只需安装 react 插件
$ npm i @babel/preset-react --save-dev
72 配置babel支持JSX 转译
configure babel to use the React preset in babel.config.json:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
8 配置支持 CSS
将 JS以外的web 资源进行模块化需要一点点解释。样式,和图片等“web 模块”,与JS模块处理是不同,所以使用独立的loader (JS模块预处理使用babel);另外,这些模块的预处理,和打包操作也是JS模块不同。例如:CSS模块使用 css-loader预处理为web模块,再用 style-loader进行“打包”。
css-loader parses the CSS into JavaScript and resolves any dependencies
style-loader outputs our CSS into a