2

配置开发环境(webpack)以支持开发React项目

 2 years ago
source link: http://nakeman.cn/engineering/webprogramming/setup-your-webpack-dev-environment-for-react.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

(本文介绍手动配置前端开发环境——构建工具链的核心部分,通常这部分我们都是通过前端框架官方脚手架自动搭建的,例如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 这个包

注:舒适性受主观影响,受开发者智力,水平,价值风格影响

前端最基础的开发环境满足以下几点:

  1. 支持最新的ESM模块,ES6语法
  2. 支持web 模块,例如css ,png,font等 可以import
  3. Router, sass 等不是必须的
  4. ui库也是不必须的
  5. 支持 JSX, SFC等基本 方便创建 V组件
  6. 语法帮助 也是不是必须的
  7. 支持热加载的开发服务器

# webpack 配置过程

以下记录了为React项目配置舒适开发环境的过程。全程假定你已经使用npm init创建一个项目目录,并且只列出相应的内容,自行创建源文件。

另外 webpack基础认识,请看我之前的这篇文章(《webpack与项目构建再认识》)。

1 安装 项目开发依赖(webpack webpack-cli)

webpack 和一般开发依赖相似,以D安装:

$ npm install webpack webpack-cli --save-dev
  1. $ npm install webpack webpack-cli --save-dev
$ 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'), // 发布目录
  },
};
  1. const path = require('path');
  2. module.exports = {
  3. entry: './src/index.js', // 依赖入口
  4. output: {
  5. filename: 'main.js', // 最终打包好的文件
  6. path: path.resolve(__dirname, 'dist'), // 发布目录
const path = require('path');
module.exports = {
  entry: './src/index.js', // 依赖入口
  output: {
    filename: 'main.js', // 最终打包好的文件
    path: path.resolve(__dirname, 'dist'), // 发布目录
  },
};

23 APP页面 dist/index.html

这个是直接在输出目录安排的(手动静态),会有需要动态生成的前端页面,看下面

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Getting Started</title>
  </head>
<body>
 <script src="main.js"></script>
</body>
</html>
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Getting Started</title>
  6. </head>
  7. <body>
  8. <script src="main.js"></script>
  9. </body>
  10. </html>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Getting Started</title>
  </head>
<body>
 <script src="main.js"></script>
</body>
</html>

24 使用npm script执行 打包任务

package.json

{
  "scripts": {
  "build": "webpack"
},
"devDependencies": {
  "webpack": "^5.4.0",
  "webpack-cli": "^4.2.0"
}
}
  1. "scripts": {
  2. "build": "webpack"
  3. "devDependencies": {
  4. "webpack": "^5.4.0",
  5. "webpack-cli": "^4.2.0"
{
  "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
  1. $ npm i html-webpack-plugin --save-dev
$ 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")
    })
 ]
};
  1. const HtmlWebpackPlugin = require("html-webpack-plugin");
  2. const path = require("path");
  3. module.exports = {
  4. plugins: [
  5. new HtmlWebpackPlugin({
  6. template: path.resolve(__dirname, "src", "index.html")
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>
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>React with Webpack</title>
  6. </head>
  7. <body>
  8. <div id="root"></div>
  9. </body>
  10. </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
  1. $ npm install webpack-dev-server --save-dev
$ npm install webpack-dev-server --save-dev

42 使用npm script 启动服务器

更新package.json,增加一个dev script块:

"dev": "webpack serve --mode development"
  1. "dev": "webpack serve --mode development"
"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
  1. npm install clean-webpack-plugin --save-dev
npm install clean-webpack-plugin --save-dev

webpack.config.js:

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

...

plugins: [
...
new CleanWebpackPlugin()
],
  1. const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  2. plugins: [
  3. new CleanWebpackPlugin()
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
  1. $ npm i @babel/core babel-loader @babel/preset-env --save-dev
$ 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"
  ]
}
  1. "presets": [
  2. "@babel/preset-env"
{
  "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: []
};
  1. module.exports = {
  2. module: {
  3. rules: [
  4. test: /\.js$/, //
  5. exclude: /node_modules/,
  6. use: ["babel-loader"]
  7. plugins: []
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
  1. $ npm i @babel/preset-react --save-dev
$ 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"]
}
  1. "presets": ["@babel/preset-env", "@babel/preset-react"]
{
"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 <style> tag in the HTML document.

如果使用scss,那么处理CSS WEB模块前,还有一些预处理,使用 sass-loader 。

81 安装 loader

$ npm i css-loader style-loader --save-dev
  1. $ npm i css-loader style-loader --save-dev
$ npm i css-loader style-loader --save-dev

82 配置 loader

注意loader顺序敏感,反向从右到左,要先预处理,再打包
configure them in webpack.config.js:

module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
  1. module: {
  2. rules: [
  3. test: /\.css$/,
  4. use: ["style-loader", "css-loader"]
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
  • A mostly complete guide to webpack 5 (2020)
  • https://www.valentinog.com/blog/webpack/
  • A Beginner’s Guide to Webpack
  • https://www.sitepoint.com/webpack-beginner-guide/
  • How to setup your perfect Webpack dev server environment for React
  • https://linguinecode.com/post/how-to-setup-webpack-dev-server-react-babe

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK