如何构建自己的 React 样板

2025-06-10

如何构建自己的 React 样板

什么是样板?

在编程中,术语“样板代码”是指反复使用的代码块。

假设您的开发堆栈由多个库组成,例如 React、Babel、Express、Jest、Webpack 等。当您启动一个新项目时,您会初始化所有这些库并将它们配置为相互协作。

每启动一个新项目,你都会重复自己之前的工作。你还可能在每个项目中引入不一致的库设置方式。这会导致在项目之间切换时出现混乱。

这就是样板发挥作用的地方。样板是一个模板,您可以克隆它并在每个项目中重复使用。

模块化的 JavaScript 生态系统通过各种库、框架和工具简化了应用程序开发。如果您不了解底层组件的基础知识,那么样板代码可能会令人望而生畏。让我们在创建自己的样板代码的同时,学习这些基本的构建块。

点击此处查看 GitHub 上的源代码

我使用的是 Webstorm、Git、NodeJS v8.9、NPM v5.6 和 React v16。启动你最喜欢的 IDE,创建一个空白项目,然后开始吧!

Git 存储库:设置

创建项目文件夹并初始化 git repo:

mkdir react-boilerplate && cd react-boilerplate
git init
Enter fullscreen mode Exit fullscreen mode

您可以按照这些说明将该项目连接到 GitHub 上的您自己的 repo

自述文件

每个项目都应该包含一个落地页,其中包含对其他开发者有用的说明。让我们在项目根目录下创建一个README.md文件,其中包含以下内容:

# React-Boilerplate
This is my react-boilerplate

## Setup
npm install
npm run build
npm start
Enter fullscreen mode Exit fullscreen mode

GitHub 在项目的登录页面上显示自述文件的内容

现在,将上述更改提交给 git:

git add .
git commit -m "created readme"
Enter fullscreen mode Exit fullscreen mode

在每个部分结束时,你应该将代码提交到 git

文件夹结构

为您的项目创建以下文件夹结构:

react-boilerplate
    |--src
       |--client
       |--server
Enter fullscreen mode Exit fullscreen mode

使用以下命令:

mkdir -p src/client src/server
Enter fullscreen mode Exit fullscreen mode

这个文件夹结构是基本的,并且会随着您在项目中集成其他库而不断发展。

Git 忽略

一旦我们构建了项目,就会自动生成一些文件和文件夹。让我们告诉 git 忽略一些我们事先想到的文件。

在根文件夹下创建.gitignore,内容如下:

# Node
node_modules/

# Webstorm
.idea/

# Project
dist/
Enter fullscreen mode Exit fullscreen mode

.gitignore 文件中的注释以 # 为前缀

Node 包管理器

Node 项目的起点是初始化其包管理器,这会创建一个名为 package.json 的文件。该文件必须提交到 git 中。

它一般包含:

  • 您的 NPM 项目描述
  • 所有已安装软件包的引用列表
  • 自定义命令行脚本
  • 已安装软件包的配置

转到项目根目录并输入以下内容:

npm init
Enter fullscreen mode Exit fullscreen mode

填写所有详细信息,接受后,npm 将创建一个如下所示的 package.json 文件:

{
  "name": "react-boilerplate",
  "version": "1.0.0",
  "description": "Basic React Boilerplate",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/theoutlander/react-boilerplate.git"
  },
  "keywords": [
    "Node",
    "React"
  ],
  "author": "Nick Karnik",
  "license": "Apache-2.0",
  "bugs": {
    "url": "https://github.com/theoutlander/react-boilerplate/issues"
  },
  "homepage": "https://github.com/theoutlander/react-boilerplate#readme"
}
Enter fullscreen mode Exit fullscreen mode

静态内容

让我们创建一个静态 HTML 文件src/client/index.html,其内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Boilerplate</title>
</head>
<body>
    <div id="root">
        Welcome to React Boilerplate!
    </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Express Web 服务器

为了提供上述静态文件,我们需要在ExpressJS中创建一个 Web 服务器。

NPM v5 会自动将已安装的包保存在 package.json 的依赖项部分下,因此--save属性不是必需的

npm install express
Enter fullscreen mode Exit fullscreen mode

我建议遵循文件命名约定,文件名采用小写字母,多个单词之间用点号分隔。这样可以避免跨平台遇到大小写敏感问题,并简化大型团队中多个单词的文件命名。

创建文件src/server/web.server.js并添加以下代码以通过 express 应用程序托管 Web 服务器并提供静态 html 文件:

const express = require('express')

export default class WebServer {
  constructor () {
    this.app = express()
    this.app.use(express.static('dist/public'))
  }

  start () {
    return new Promise((resolve, reject) => {
      try {
        this.server = this.app.listen(3000, function () {
          resolve()
        })
      } catch (e) {
        console.error(e)
        reject(e)
      }
    })
  }

  stop () {
    return new Promise((resolve, reject) => {
      try {
        this.server.close(() => {
          resolve()
        })
      } catch (e) {
        console.error(e.message)
        reject(e)
      }
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

我们上面创建了一个简单的 Web 服务器,带有启动和停止命令。

单击此处了解有关 Promises 的更多信息

启动文件

接下来,我们需要创建一个索引文件,用于初始化各种高级组件。在本例中,我们将初始化 Web 服务器。不过,随着项目规模的扩大,您还可以初始化其他组件,例如配置、数据库、记录器等。

创建文件src/server/index.js,内容如下:

import WebServer from './web.server'

let webServer = new WebServer();
webServer.start()
  .then(() => {
    console.log('Web server started!')
  })
  .catch(err => {
    console.error(err)
    console.error('Failed to start web server')
  });
Enter fullscreen mode Exit fullscreen mode

巴别塔

要运行上面的ES6代码,我们需要先通过 Babel 将其转换为ES5。让我们安装Babel以及支持 ES2015 转译的babel-preset-env依赖项:

npm i babel-cli babel-preset-env --save-dev
Enter fullscreen mode Exit fullscreen mode

在根目录下创建一个名为 .babelrc 的 babel 配置文件,并向其中添加以下详细信息:

{
  "presets": ["env"]
}
Enter fullscreen mode Exit fullscreen mode

env 预设隐式包含 babel-preset-es2015、babel-preset-es2016 和 babel-preset-es2017,这意味着您可以运行 ES6、ES7 和 ES8 代码。

构建命令

让我们创建命令来构建项目的服务器和客户端组件并启动服务器。在package.json的 scripts 部分下,删除包含 test 命令的行,并添加以下内容:

"scripts": {
    "build": "npm run build-server && npm run build-client",
    "build-server": "babel src/server --out-dir ./dist",
    "build-client": "babel src/client --copy-files --out-dir ./dist/public",
    "start": "node ./dist/index.js"
}
Enter fullscreen mode Exit fullscreen mode

上面的 build 命令会在根目录下创建一个dist/public文件夹。build-client 命令只是将 index.html 文件复制到 dist/public 文件夹。

启动

您可以在上面的代码上运行 babel 转译器并使用以下命令启动 Web 服务器:

npm run build
npm start
Enter fullscreen mode Exit fullscreen mode

打开浏览器并导航至http://localhost:3000。您应该会看到静态 HTML 文件的输出。

React 样板

您可以通过按<Ctrl> C来停止 Web 服务器

测试工具:Jest

我再怎么强调在项目开始时引入单元测试的重要性也不为过。我们将使用Jest 测试框架,它旨在快速且对开发人员友好。

首先,我们需要安装jest并将其保存到开发依赖项中。

npm i jest --save-dev
Enter fullscreen mode Exit fullscreen mode

单元测试

让我们添加两个测试用例来启动和停止 Web 服务器。

对于测试文件,你应该添加 .test.js 扩展名。Jest 会扫描 src 文件夹中所有文件名包含 .test 的文件,你可以将测试用例与要测试的文件放在同一文件夹下。

创建一个名为src/server/web.server.test.js的文件并添加以下代码:

import WebServer from './web.server'

describe('Started', () => {
  let webServer = null

  beforeAll(() => {
    webServer = new WebServer()
  })

  test('should start and trigger a callback', async () => {
    let promise = webServer.start()
    await expect(promise).resolves.toBeUndefined()
  })

  test('should stop and trigger a callback', async () => {
    let promise = webServer.stop()
    await expect(promise).resolves.toBeUndefined()
  })
})
Enter fullscreen mode Exit fullscreen mode

测试命令

让我们在 package.json 的 scripts 部分添加一个 npm 命令来运行测试。默认情况下,jest 会运行所有文件名中带有.test 的文件。我们希望将其限制为只运行src文件夹下的测试。

"scripts": {
...
    "test": "jest ./src"
...
}
Enter fullscreen mode Exit fullscreen mode

安装 Jest 时会自动安装 babel-jest,如果您的项目中存在 babel 配置,它将自动转换文件。

让我们通过以下命令运行测试:

npm test
Enter fullscreen mode Exit fullscreen mode

React 样板

我们的应用程序已设置为通过Express Web 服务器提供静态HTML文件。我们集成了Babel以启用 ES6 和Jest进行单元测试。现在,让我们将重点转移到前端设置上。

React 设置

安装 react 和 react-dom 库:

npm i react react-dom
Enter fullscreen mode Exit fullscreen mode

创建一个名为src/client/app.js 的文件,内容如下:

import React, {Component} from 'react'

export default class App extends Component {
    render() {
        return <div>Welcome to React Boilerplate App</div>
    }
}
Enter fullscreen mode Exit fullscreen mode

让我们通过src/client/index.js下的索引文件呈现应用程序

import React from 'react'
import ReactDOM from 'react-dom'
import App from './app'

ReactDOM.render(<App />, document.getElementById('root'))
Enter fullscreen mode Exit fullscreen mode

Babel React

如果你执行npm run build-client,你将会得到一个错误,因为我们还没有告诉 babel 如何处理 React / JSX。

React 样板

让我们通过安装babel-preset-react依赖项来解决这个问题:

npm install --save-dev babel-preset-react
Enter fullscreen mode Exit fullscreen mode

我们还需要修改 .babelrc 配置文件以启用转换反应:

{
  "presets": ["env", "react"]
}
Enter fullscreen mode Exit fullscreen mode

现在,当您运行npm run build-client时,它将在dist/public下创建 app.js 和 index.js ,并将 ES6 代码转换为 ES5。

在 HTML 中加载脚本

要将 React App 连接到 HTML 文件,我们需要在index.html文件中加载index.js文件。不要忘记清空#root节点的文本,因为 React App 将会被挂载到这个节点上:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Boilerplate</title>
</head>
<body>
    <div id="root"></div>
    <script src="index.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

运行服务器

如果您启动 Web 服务器并转到http://localhost:3000,您将在控制台中看到一个带有错误的空白页。

未捕获的 ReferenceError:require 未定义

React 样板

这是因为 Babel 只是一个转译器。为了支持动态加载模块,我们需要安装 webpack。

首先将 package.json 中 scripts 下的构建命令更改为 build-babel:

"scripts": {
    "build-babel": "npm run build-babel-server && npm run build-babel-client",
    "build-babel-server": "babel src/server --out-dir ./dist",
    "build-babel-client": "babel src/client --copy-files --out-dir ./dist/public",
    "start": "node ./dist/index.js",
    "test": "jest ./src"
  }
Enter fullscreen mode Exit fullscreen mode

Webpack

Webpack 使我们能够轻松地模块化代码并将其打包成单个 JavaScript 文件。它支持众多插件,几乎任何你能想到的构建任务都有相应的插件。首先安装 Webpack:

本教程是在 webpack v4 发布之前发布的,因此我们将明确安装 webpack v3。

npm i webpack@^3
Enter fullscreen mode Exit fullscreen mode

默认情况下,webpack 会查找名为webpack.config.js的配置文件,因此我们在根文件夹中创建它,并定义两个入口点,一个用于 Web 应用程序,另一个用于 Web 服务器。让我们创建两个配置对象并将它们导出为集合:

const client = {
    entry: {
        'client': './src/client/index.js'
    }
};

const server = {
    entry: {
        'server': './src/server/index.js'
    }
};

module.exports = [client, server];
Enter fullscreen mode Exit fullscreen mode

现在,让我们指定 webpack 的输出位置,并设置目标构建,使其忽略诸如“fs”和“path”之类的原生 Node 模块。对于客户端,我们将其设置为web,对于服务器,我们将其设置为node

let path = require('path');

const client = {
    entry: {
        'client': './src/client/index.js'
    },
    target: 'web',
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist/public')
    }
};

const server = {
    entry: {
        'server': './src/server/index.js'
    },
    target: 'node',
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    }
};

module.exports = [client, server];
Enter fullscreen mode Exit fullscreen mode

Babel 加载器

在运行 webpack 之前,我们需要配置它来处理 ES6 和 JSX 代码。这可以通过 loader 来完成。我们先安装babel-loader

npm install babel-loader --save-dev
Enter fullscreen mode Exit fullscreen mode

我们需要修改 webpack 配置,让 babel-loader 在所有 .js 文件上运行。我们将创建一个共享对象,定义模块部分,以便在两个 target 中复用。

const path = require('path');

const moduleObj = {
    loaders: [
        {
            test: /\.js$/,
            exclude: /node_modules/,
            loaders: ["babel-loader"],
        }
    ],
};

const client = {
    entry: {
        'client': './src/client/index.js',
    },
    target: 'web',
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, '/pub')
    },
    module: moduleObj
};

const server = {
    entry: {
        'server': './src/server/index.js'
    },
    target: 'node',
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: moduleObj
}

module.exports = [client, server];
Enter fullscreen mode Exit fullscreen mode

对于合并嵌套共享对象,我建议查看Webpack Merge模块

排除文件

Webpack 会打包引用的库,这意味着 node_modules 中包含的所有内容都会被打包。我们不需要打包外部代码,因为这些包通常会被压缩,而且会增加构建时间和文件大小。

让我们配置 webpack 以排除 node_modules 文件夹下的所有包。这可以通过webpack-node-externals模块轻松完成:

npm i webpack-node-externals --save-dev
Enter fullscreen mode Exit fullscreen mode

然后配置webpack.config.js来使用它:

let path = require('path');
let nodeExternals = require('webpack-node-externals');

const moduleObj = {
    loaders: [
        {
            test: /\.js$/,
            exclude: /node_modules/,
            loaders: ["babel-loader"],
        }
    ],
};

const client = {
    entry: {
        'client': './src/client/index.js',
    },
    target: 'web',
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist/public')
    },
    module: moduleObj
};

const server = {
    entry: {
        'server': './src/server/index.js'
    },
    target: 'node',
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: moduleObj,
    externals: [nodeExternals()]
}

module.exports = [client, server];
Enter fullscreen mode Exit fullscreen mode

更新构建命令

最后,我们需要对 package.json 下的脚本部分进行更改,以包含使用 webpack 的构建命令,并将index.js重命名为npm start 的server.js,因为这是 webpack 配置的输出。

"scripts": {
    "build": "webpack",
    "build-babel": "npm run build-babel-server && npm run build-babel-client",
    "build-babel-server": "babel src/server --out-dir ./dist",
    "build-babel-client": "babel src/client --copy-files --out-dir ./dist/public",
    "start": "node ./dist/server.js",
    "test": "jest ./src"
  }
Enter fullscreen mode Exit fullscreen mode

构建清洁

让我们添加一个命令来清理 dist 和 node_modules 文件夹,以便进行干净构建并确保项目仍然按预期工作。在此之前,我们需要安装一个名为rimraf的包(即rm -rf命令)。

npm install rimraf
Enter fullscreen mode Exit fullscreen mode

脚本部分现在应该包含

"scripts": {
...
"clean": "rimraf dist node_modules",
...
}
Enter fullscreen mode Exit fullscreen mode

使用 Webpack 进行清理构建

现在,您可以使用 webpack 成功清理和构建您的项目:

npm run clean
npm install
npm run build
Enter fullscreen mode Exit fullscreen mode

这将在根文件夹下创建dist/server.jsdist/public/client.js 。

HTML Webpack 插件

但是,你可能注意到了index.html缺失了。这是因为我们之前使用 Babel 复制了未转译的文件。但是,webpack 无法做到这一点,所以我们需要使用HTML Webpack 插件

让我们安装 HTML Webpack 插件:

npm i html-webpack-plugin --save-dev
Enter fullscreen mode Exit fullscreen mode

我们需要在 webpack 配置文件的顶部包含该插件:

const HtmlWebPackPlugin = require('html-webpack-plugin')
Enter fullscreen mode Exit fullscreen mode

接下来,我们需要向客户端配置添加一个插件键:

const client = {
  entry: {
    'client': './src/client/index.js'
  },
  target: 'web',
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist/public')
  },
  module: moduleObj,
  plugins: [
    new HtmlWebPackPlugin({
      template: 'src/client/index.html'
    })
  ]
}
Enter fullscreen mode Exit fullscreen mode

在构建项目之前,我们先修改一下 HTML 文件,删除对 index.js 脚本的引用,因为上面的插件会帮我们添加。当有一个或多个文件使用动态文件名时(例如,为了清除缓存而生成带有唯一时间戳的文件),这尤其有用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Boilerplate</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

让我们重建项目:

npm run clean
npm install
npm run build
Enter fullscreen mode Exit fullscreen mode

并且,验证我们现有的测试仍在运行:

npm test
Enter fullscreen mode Exit fullscreen mode

我们进一步更新了样板以集成 React 和 Webpack,创建了额外的 NPM 命令,在 HTML 文件中动态引用 index.js,并将其导出。

酶的设置

在添加 React 测试之前,我们需要集成Enzyme,它将允许我们断言、操作和遍历 React 组件。

让我们首先安装 enzyme 和 enzyme-adapter-react-16,这是将 enzyme 连接到使用 react v16 及以上版本的项目所必需的。

enzyme-adapter-react-16 对 react、react-dom 和 react-test-renderer 具有对等依赖

npm i --save-dev enzyme enzyme-adapter-react-16 react-test-renderer
Enter fullscreen mode Exit fullscreen mode

创建一个文件src/enzyme.setup.js,内容如下:

import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

Enzyme.configure({
    adapter: new Adapter()
})
Enter fullscreen mode Exit fullscreen mode

我们需要通过在根对象下添加以下部分来配置 jest 以使用package.json中的src/enzyme.setup.js :

{
...
"jest": {
    "setupTestFrameworkScriptFile": "./src/enzyme.setup.js"
  }
...
}
Enter fullscreen mode Exit fullscreen mode

React 组件测试

让我们测试一下 App 组件,确保它能够渲染预期的文本。此外,我们将对该组件进行快照,以确保其结构在每次测试运行后都不会发生变化。

单击此处了解有关快照测试的更多信息

在src/client/app.test.js下创建测试用例,内容如下:

import App from './app'
import React from 'react'
import {shallow} from 'enzyme'

describe('App', () => {
  test('should match snapshot', () => {
    const wrapper = shallow(<App/>)

    expect(wrapper.find('div').text()).toBe('Welcome to React Boilerplate App')
    expect(wrapper).toMatchSnapshot()
  })
})
Enter fullscreen mode Exit fullscreen mode

如果我们现在运行这个测试,它会通过并出现警告:

React 样板

让我们通过安装一个名为raf的 polyfill 来解决这个问题:

npm i --saveDev raf
Enter fullscreen mode Exit fullscreen mode

并将package.json下的 jest 配置更改为:

{
...
"jest": {
    "setupTestFrameworkScriptFile": "./src/enzyme.setup.js",
    "setupFiles": ["raf/polyfill"]
  }
...
}
Enter fullscreen mode Exit fullscreen mode

现在,您可以验证所有测试是否通过:

npm test
Enter fullscreen mode Exit fullscreen mode

React 样板

运行 React 测试后,你会注意到src/client/snapshots/app.test.js.snap处多了一个新文件。它包含 React 组件的序列化结构。必须将其提交到 git 中,以便在测试运行期间与动态生成的快照进行比较。

最终冲刺

让我们再次启动 Web 服务器并导航到http://localhost:3000以确保一切正常:

npm start
Enter fullscreen mode Exit fullscreen mode

React 样板

希望本文能帮助您了解如何使用 Express | React | Jest | Webpack | Babel 从零开始构建新项目。创建自己的可复用样板代码是一个好主意,这样您就能理解底层原理,并在创建新项目时抢占先机。

我们仅仅触及了表面,还有很大的改进空间来使这个样板准备好投入生产。

您可以尝试以下操作:


您可能还喜欢


如果这篇文章有帮助,请❤️并在 Twitter 上关注我


鏂囩珷鏉ユ簮锛�https://dev.to/theoutlander/build-your-own-react-boilerplate-4b8l
PREV
如何使用 Node、Express 和 Mongo 构建 REST API
NEXT
Back to Basic: Mental Model to Understand Flexbox GenAI LIVE! | June 4, 2025