手动搭建基于 Webpack 的 React 项目开发环境

作为一个「全干」程序员,前端相关的工作是少不了的。JavaScript 作为前端开发的不二语言,生态比较繁荣。Vue 和 React 就是其中比较有代表性的两个选择。一直以来我使用 Vue 比较多,所以对 React 还不是很了解。最近趁着一个项目前端要重构的机会,准备尝试一下 React。

开始之前的想法

在本地体验 React 最简单的方式就是去官网下载打包好的源码,然后通过 <script> 引入几个 React 的基础库到 HTML 页面,就能立马开始体验 React 的魅力了。

我是准备在项目中正式使用,用这种方式就无法应用到各种现代化和流程化的前端工具,比如 Webpack。所以会选择基于 node.js 的方案。

这次除了要尝试 React,另外一个挑战就是不依赖之前 Web 框架「傻瓜化」的前端配置。就像 Laravel 提供的 mix,它会让你不必关心前端要如何配置打包工具,需要些什么组件和扩展。这些基础的工作它都做好了。虽然使用起来非常爽,但时间一长,我发现自己已经快跟不上前端技术各种日新月异的变化,而且也特别依赖这种提供基础配置的框架。这让我有点担心自己逐渐会在项目中会失去对前端技术的掌控。

所以我要从零开始尝试自己搭建一个 React 的开发环境,即便是要添加依赖组件,也需要弄明白为什么需要它。

这样一来,使用 npx create-react-project 创建 React 项目脚手架的命令也就被我放弃了。它虽然相比其他框架提供的前端配置精简了许多,但 package.json 里面依然还是有很多我不太了解的依赖配置。

我的目的很简单,就是要从零开始搭建一个 React 项目环境。说的更具体一点就是要一点一点的实现一个可以编译 React 组件并显示在浏览器上的基础目录,以方便我正式使用时进行扩展和补充。

显示一个页面

万事开头难。我要完成的第一个目标就设置的简单点:规划好目录并显示一个简单的项目页面。先创建项目目录:

mkdir react-app

react-app 是项目目录的名称,这里代表这次实验用的名称。进入项目目录,我还需要创建两个文件夹:

cd react-app
mkdir src
mkdir public

src 目录用来存放项目 js 源码,public 目录用来存放打包好的 js 文件以及一些静态资源。

接下来在 src 目录中创建一个项目源码的入口文件:

touch src/main.js

里面暂时还不需要任何内容。

接下来在 public 目录创建一个 HTML 文件,用来作为浏览器的访问入口:

touch public/index.html

为了方便验证效果,在这个 HTML 文件中添加以下内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Demo</title>
</head>
<body>
    <h1>This a React Demo app.</h1>
</body>
</html>

接下来就需要用到 Node.js 环境了,我已经安装好了,并且可以正常使用 npmyarn 命令。我倾向于使用 yarn 命令,关于原因可以查看我之前写的这篇文章《2021 JavaScript 包管理工具入门指南》。

确保 yarn 命令可用后,用它来初始化一个默认的 js 包配置文件:

yarn init -y

命令执行完后,当前项目目录下会多出一个 package.json 文件。接下来开始添加 Webpack 工具库:

yarn add webpack webpack-cli webpack-dev-server

webpack 是 Webpack 主工具库,webpack-cliwebpack-dev-server 是为了给项目提供开发时的 Web 访问服务功能。

安装好 Webpack 相关库后,编辑 package.json 文件,需要在里面添加一行自定义脚本,完整的内容如下:

{
  "name": "app",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "webpack-dev-server"
  },
  "dependencies": {
    "webpack": "^5.64.0",
    "webpack-cli": "^4.9.1",
    "webpack-dev-server": "^4.5.0"
  }
}

其中 "scripts" 节点就是新添加的自定义脚本内容。后面的 start 代表一个自定义指令,指向了 webpack-dev-server 命令。它会启动一个可供浏览器访问的 Web 服务。

最后再创建一个 Webpack 配置文件:

touch webpack.config.js

并添加以下配置内容:

module.exports = {
    mode: 'development',
    devServer: {
        host: 'localhost',
        port: 8000
    },
    entry: './src/main.js',
    output: {
        filename: 'bundle.[hash].js'
    }
}

其中 devServer 节点定义了浏览器中可以访问的项目地址和端口。来尝试运行一下刚才在 package.json 中自定义的开发服务指令:

yarn start

打开浏览器,访问 http://localhost:8000,一切正常的话就可以看到以下内容。

image-20211114173412256

成功迈出了第一步。目前项目下的文件结构看起来如下:

.
├── node_modules/
├── package.json
├── public/
│   └── index.html
├── src/
│   └── main.js
├── webpack.config.js
└── yarn.lock

各文件和目录的解释如下:

  • node_modules:通过 yarn 命令安装的组件源码目录。
  • package.json:项目包和依赖信息文件。
  • public:编译打包和静态资源目录。
  • src:项目源码目录。
  • webpack.config.js:Webpack 配置文件。
  • yarn.lock:通过 yarn 命令安装组件后当前的版本锁定信息文件。

显示 React 组件

只显示一个原始的 HTML 页面还没多大用处,所以接下来就是实现最终目的:实现 React 组件的功能显示。

在前面的基础工作上,这一步其实已经不再复杂了。首先是安装 Babel 代码转译工具库:

yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react

接着继续引入 React 的依赖库:

yarn add react react-dom

再添加一个 Webpack 的 HTML 插件,它能辅助处理访问入口页面的脚本插入:

yarn add html-webpack-plugin

这样核心的依赖组件和库就全部到位,接下来就是完善代码和配置的工作。

首先补充一下 Webpack 配置文件。打开 webpack.config.js,然后修改成如下的内容:

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode: 'development',
    devServer: {
        host: 'localhost',
        port: 8000,
        hot: true
    },
    entry: './src/main.js',
    output: {
        filename: 'bundle.[hash].js'
    },
    module: {
        rules: [
            {
                test: /\.(js)$/,
                exclude: /node_modules/,
                use: ['babel-loader']
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'public/index.html'
        })
    ]
}

主要新增了 moduleplugins 节点。然后 devServer 节点补充了一个 hot: true 的配置项,这个配置可以实现修改源码后自动刷新浏览器的功能,非常实用。

public/index.html 文件中添加一个渲染组件时要绑定的节点元素:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Demo</title>
</head>
<body>
    <h1>This a React Demo app.</h1>
    <div id="app"></div>
</body>
</html>

上面 id="app" 那行就是刚添加的,这是要绑定组件的节点标签。

另外还需要创建一个 Babel 的配置文件,文件名为 .babelrc,放到项目的根目录,内容如下:

{
    "presets": ["@babel/preset-env", "@babel/preset-react"]
}

最后编辑 src/main.js 文件,写一个简单的 React 组件:

import React from 'react';
import ReactDOM from 'react-dom';

// 一个欢迎消息组件
class Welcome extends React.Component {
    render() {
        return <h1>Welcome, { this.props.name }.</h1>;
    }
}

// 绑定并渲染组件内容到入口页面的 #app 标签元素
ReactDOM.render(<Welcome name="zzxworld" />, document.getElementById('app'))

再次运行 yarn start 命令,然后在浏览器访问 http://localhost:8000,一切正常的话应该会发现下面多了一行信息。

image-20211114212328119

这说明 React 组件正常显示了。可以在 src/main.js 中把 zzxworld 换成别的名字试试,如果在保存代码的那一刻,浏览器内容自动变了,那说明自动刷新功能也起作用了。

至此,这个最基础的 React 开发环境就算完成了,我也已经迫不及待的想要在实际项目中去体验 React。

后续更新

发表评论