【翻译】从零开始创建 React 应用

React 应用的搭建有多种方式,官方文档说明了可以使用的现成工具,在最后还提到可以自己从零搭建 React 应用,本文就针对这一点进行详细的说明,来看一看 React(可以推广到一般的前端应用)是如何搭建起来的。

本文翻译自一篇英文博客 《Creating a React App... From Scratch》

原文链接:https://blog.usejournal.com/creating-a-react-app-from-scratch-f3c693b84658

【翻译】从零开始创建 React 应用_第1张图片

React 并非开箱即用(out of the box),它使用一些 node(本教程中讨论的是 v.9.3.0 版本)还不能识别的关键字和语法。解决这个问题还真是需要费一点力气去搭建应用,然而 Facebook 已经提供了一个使构建 React 应用简单的选择,就不需要再为这个问题而费心了不是吗?

问题是,create-react-app将 React 应用运行的许多东西抽取出来,你并不会接触到,至少不需要 eject 和自己手动调试配置项了。可是总会有许许多多的情况下,你想要自定义一些实现,或者至少你想要知道在底层究竟发生了什么。

正如我所说的,在开始一个 React 应用时会遇到两个困难。第一个是 node 并不能处理所有的语法规则(如 import/export 和 jsx);第二个是你或者需要构建(build)你的文件,或者需要在开发的时候模拟一个服务器工作环境,后者尤为重要。

幸运的是,我们可以使用 Bable 和 Webpack 处理这些难题。

搭建(Setup)

首先,为你的 React 应用新建一个目录。然后使用 npm init 初始化项目并使用任意编辑器打开。同时这也是使用 git init 的好时机。在你的新项目文件夹中,新建以下的目录结构:

.
+-- public
+-- src

往后想一点,我们最终将希望构建我们的应用,并且很可能需要从提交(commit)中排除构建版本和 node 模块,所以我们还要添加 .gitignore 文件排除(至少)node_modulesdist 目录。

public 目录将处理所有的静态资源(assets),其中最重要的是存放 index.html 文件,React 将会使用该文件来渲染你的应用。下面的代码来自 React 文档,只做了非常小的改动。你可以将这些 HTML 代码复制到 public 目录里新建的 index.html 文件中。




  
    
    
    React Starter
  
  
    

最需要注意的就是第 10 行(

),这是 React 应用嵌入的根部,和第 14 行(),这里引用了(将要被)构建好的 React 应用。你可以按自己喜欢随意为构建好的脚本起名,本教程将会使用 bundle.js

现在我们建立好了 HTML 页面,可以开始严肃认真起来了。我们将需要建立更多的一些东西。首先,需要确保我们写的代码可以被编译,因此我们需要 Babel。

Babel

下一步,执行 npm install --save-dev [email protected] [email protected] [email protected] [email protected]

babel-core 是主要的 babel 包,我们需要它来对我们的代码进行所有的转换。babel-cli 允许你使用命令行来编译文件。babel-preset-envbabel-preset-react 都是转换特殊风格代码的预编译设置(presets)——env 可以将 ES6+ 转换为传统的 JavaScript 代码,而 react 功能是相同的,只不过使用了 JSX。

在项目的根目录下,新建文件 .babelrc。此处我们要告诉 babel 需要使用 envreact 预设。

{
  "presets": ["env", "react"]
}

如果你仅需要转换特定的特性或 env 中没有的特性,Babel 有许许多多可用的插件可供使用。我们暂时不用担心这些,不过你可以在这里查看他们。

Webpack

现在我们需要获得并配置 Webpack。我们还需要几个包,你需要他们保存为开发依赖:npm install --save-dev [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]

Webpack 使用 加载器(loaders)来打包处理不同类型的文件。它也能方便地协同开发环境服务器协同工作,我们使用开发环境服务器来运行开发环境的 React 项目,并且在我们改动(并保存)React 组件后重新加载浏览器页面。但是为了使用这些功能,我们需要配置 Webpack,使用我们的加载器并准备开发环境服务器。

在项目根目录下新建一个文件,命名为 webpack.config.js,这个文件导出一个 Webpack 配置对象。

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: "./src/index.js",
  mode: "development",
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules|bower_components)/,
        loader: 'babel-loader',
        options: { presets: ['env']}
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  resolve: { extensions: ['\*', '.js', '.jsx'] },
  output: {
    path: path.resolve(\_\_dirname, "dist/"),
    publicPath: "/dist/",
    filename: "bundle.js"
  },
  devServer: {
    contentBase: path.join(\_\_dirname, "public"),
    port: 3000,
    publicPath: "http://localhost:3000/dist/",
    hotOnly: true
  },
  plugins:[new webpack.HotModuleReplacementPlugin()]
};

我们来快速过一遍:entry 告诉 Webpack 应用从哪里开始运行,也是打包文件的起点。下面的一行告诉 Webpack 我们当前工作在开发模式下——当我们运行开发模式服务器时,就不需要添加模式标志(mode flag)了。

module 对象定义了你导出的 JavaScript 模块如何转换,根据给出的 rules 数组确定转换那些类型的文件。

我们的第一条规则就是关于转换 ES6 和 JSX 语法的。testexclude 属性是文件匹配条件。当前案例中,它将会匹配 node_modulesbower_components 以外的所有文件。由于我们将会转换 .js.jsx 文件,需要指示 Webpack 使用 Babel。最后,我们在 options 中指明想要使用 env 预设。

下一条规则是用于处理 CSS 的。由于没有使用预处理或后处理 CSS,我们只需要确保添加 style-loadercss-loaderuse 属性。css-loader 需要 style-loader 才能工作。在仅仅使用一个加载器时,loaderuse 属性的一个简写形式。

resolve 属性让我们指定 Webpack 解析那些扩展名——这让我们能够不需要写扩展名便能导入需要的模块。

output 属性告诉 Webpack 将打包好的代码放置到哪里。属性 publicPath 指定代码包存放的目录,同时也告诉 webpack-dev-server 从哪里获取文件。

属性 publicPath 是一个帮助我们使用开发环境服务器的特殊属性。它指定目录的公共 URL——至少是 webpack-dev-server 知道和关心的。如果设置错误,将会得到 404,因为服务器无法从正确的位置获取文件!

我们在 devServer 属性中配置 webpack-dev-server。对于我们的需求来说,不需要太多的配置——只需要静态文件(例如 index.html)的存放位置和服务端口就可以了。注意 devServer 也有一个 publicPath 属性,它告诉服务器打包后的文件究竟在哪个位置上。

最后的这一点可能有些困惑——要十分注意:output.publicPathdevServer.publicPath 是不相同的。请阅读相关词条,两次。

最后,由于我们想使用 热模块替换(Hot Module Replacement, HMR),以至于不需要反复刷新来看到我们的修改。就这个文件而言,我们要做的就是在 plugins 属性中实例化一个新的插件(plugin)实例,并确保在 devServer 中设置 hotOnlytrue。在 HMR 工作之前我们还需要在 React 中设置一样东西。

至此复杂的搭建工作就完成了,下面让我们让 React 工作起来。

React

首先,我们还是需要获取两个新包:[email protected][email protected],安装并保存为一般依赖。

我们需要告诉 React 应用挂载到 DOM 的位置(index.html 文件中)。在 src 目录中新建一个名为 index.js 的文件,这是一个很小的文件,但是在 React 应用中却起到很大的作用。文件内容如下。

import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
ReactDOM.render(
  ,
  document.getElementById("root")
);

ReactDOM.render 函数告诉 React 需要渲染什么,渲染到哪里——在本例中,我们将渲染一个叫做 App 的组件(后面将会创建)到 ID 是 root 的 DOM 元素上。

现在,在 src 下面再新建一个名为 App.js 的文件。如果你使用过 create-react-app 创建 React 应用,这部分你肯定非常熟悉。该文件就是一个 React 组件。

import React, { Component } from "react";
import "./App.css";

class App extends Component {
  render() {
    return (
      

Hello, World!

); } }

我曾经提到过 Webpack 也处理 CSS(并且我们在组件中需要引入它)。让我们在 src 目录中添加一个非常简单的样式。

.App {
  margin: 1rem;
  font-family: Arial, Helvetica, sans-serif;
}

你最终的项目结构应该看起来像下面这样,除非你改变了一些文件的名字:

.
+-- public
| +-- index.html
+-- src
| +-- App.css
| +-- App.js
| +-- index.js
+-- .babelrc
+--.gitignore
+-- package-lock.json
+-- package.json
+-- webpack.config.js

现在我们有了一个可以运行的 React 应用了!我们可以在终端执行 webpack-dev-server --mode developemnt 命令启动开发环境服务器。我建议将命令放到 package.json 中的 start 脚本处,可以让你少敲打九个键。

完成 HMR

如果你现在启动服务器,你会发现你的改动并没有在客户端产生审核影响,什么原因呢?

HMR 需要知道究竟要替换什么,而我们目前什么也没有给出。对于这一点,我们要使用 React 团队提供的一个包:react-hot-loader

你可以将它作为一般依赖安装——根据文档所示。

注意:你可以安全地将 react-hot-loader 安装为一般依赖而不是开发依赖,因为它会自动确保在生成环境中不会执行,并且它是最小封装的

现在,在 App.js 中导入 react-hot-loader,并将导出的对象标记为热重载,修改代码如下。

import React, { Component } from "react";
import { hot } from "react-hot-loader";
import "./App.css";

class App extends Component {
  render() {
    return (
      

Hello, World!

); } } export default hot(module)(App);

现在当你运行你的应用时,代码修改在保存后会立刻在客户端更新了。

最后的细节

你也许会注意到一些关于运行你的项目的有趣(甚至惊讶)的事情:构建后的文件从未在 dist 目录下面出现。看吧,webpack-dev-server 实际上是从内存中提供打包好的文件的——一旦服务停止,他们就没有了。要想真正地构建你的文件,我们要适当地使用 webpack——在 package.json 中添加一个名为 build 的脚本,命令是:webpack --mode developent你可以把 developent 替换成 production,但是如果你完全省略 --mode,它将会使用前者并且给出一个警告。

以上内容差不多覆盖了渲染一个基本 React 应用需要的所有内容,不需要 create-react-app 的帮助。然而还有更多需要添加到实现中的东西,来使项目更加完整——例如图片没有设置给 Webpack 处理,但是有一个加载器来完成这个任务。这就交给你们自己去实现了。毕竟,如果你不需要或不想提供文件服务,那就只是个累赘了,对吧?

我希望这篇文章可以帮助你稍微了解运行 React 应用所需要的东西,以及底层的基本原理。关于 Babel 和 Webpack 我并没有涉及得太过深入,但是请访问任何出现在文章中的无数链接或者直接访问他们的文档。他们都是非常棒的工具,乍看上去
非常的吓人,但实际上并非如此。他们可以使你的应用更上一层楼。

请随意查看我在 github 上的实现(它更加深入一些),或者在 twitter 上给我留言。

你可能感兴趣的:(【翻译】从零开始创建 React 应用)