create-react-app-from-scratch

React社区中提供了类似create-react-app这样的命令行工具,作为React项目的脚手架,这个工具提供了大而全的功能,直接拿过来使用,你可能不明白背后的原理,这里跟着Creating a React App… From Scratch这篇文章一起从零搭建一个React App,有条件的同学可以直接阅读英文版,这里实现的是一个最简单的功能,支持ES6+和JSX语法、热加载。

起步

创建一个目录并且通过npm init初始化一个项目,有需要也可以通过git init创建版本管理,新项目的文件结构如下:

1
2
3
.
+-- public
+-- src

此时可以添加一个.gitignore文件,并把node_modulesdist目录排除在提交范围。

public目录中,将会存放一些静态的资产,最主要的是放置index.html文件,让react用来渲染app用。

index.html如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- sourced from https://raw.githubusercontent.com/reactjs/reactjs.org/master/static/html/single-file-example.html -->
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>React Starter</title>
</head>

<body>
<div id="root"></div>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<script src="../dist/bundle.js"></script>
</body>

</html>

这里react通过root这个id进行关联渲染元素,我们后续打包的文件名称为bundle.js

Babel

接下来添加babel相关的软件包:

1
npm install --save-dev @babel/core@7.1.0 @babel/cli@7.1.0 @babel/preset-env@7.1.0 @babel/preset-react@7.0.0

babel-core是主要的babel包,用于转译代码。babel-cli用于在命令行中编译文件。preset-reactpreset-env用于预先配置要转换的代码类型,env预置用以转换ES6+的代码到ES5的代码,react预置转换JSX的代码。

接着在项目的根目录,创建一个文件.babelrc,用于告诉bebel我们要配置的预置项。

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

Babel还有很多的插件值得研究。

Webpack

接下来需要配置Webpack来打包和启用开发热加载等功能。

安装开发依赖:

1
npm install --save-dev webpack@4.19.1 webpack-cli@3.1.1 webpack-dev-server@3.1.8 style-loader@0.23.0 css-loader@1.0.0 babel-loader@8.0.2

Webpack使用loader来处理不同类型的文件并进行打包,并提供一个开发服务器方便高效的进行开发。

在项目根目录下创建一个新文件webapck.config.js,在这里导出一个包含webpack配置的对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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: ["@babel/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()]
};

这里webpack的配置项暂时不解释,接下来进行React的配置。

React

首先,我们要添加两个软件包: `react@16.5.2react-dom@16.5.2`

1
npm install --save react@16.5.2 react-dom@16.5.2

接下来,要告诉React app在哪里关联DOM,在src文件夹中创建一个index.js文件:

1
2
3
4
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
ReactDOM.render(<App />, document.getElementById("root"));

ReactDOM.render这个函数告诉React渲染什么和在哪里渲染,这里渲染一个叫做App的组件,并且渲染在ID为root的DOM元素上。

接下来在src文件夹下创建一个App.js文件,这是一个React组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, { Component} from "react";
import "./App.css";

class App extends Component{
render(){
return(
<div className="App">
<h1> Hello, World! </h1>
</div>
);
}
}

export default App;

src目录下创建一个App.css文件

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

最终的项目结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
.
+-- public
| +-- index.html
+-- src
| +-- App.css
| +-- App.js
| +-- index.js
+-- .babelrc
+-- .gitignore
+-- package-lock.json
+-- package.json
+-- webpack.config.js

在webpack的script中增加一个脚本命令,start

1
start: webpack-dev-server --mode development

使用npm start命令即可启动

Finishing HMR

这个时候修改文件内容,页面并不会自动更新,要增加热加载功能,需要另外一个软件包的支持

1
npm install --save react-hot-loader@4.3.11

这个包可以安装在依赖中,而不是开发依赖,因为包会自动判断是否执行。

App.js中导入react-hot-loader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React, { Component} from "react";
import {hot} from "react-hot-loader";
import "./App.css";

class App extends Component{
render(){
return(
<div className="App">
<h1> Hello, World! </h1>
</div>
);
}
}

export default hot(module)(App);

这个时候修改文件的内容,页面就会即时刷新了。

Build

最后,可以在package.json中增加一个build的脚本命令,

1
build: webpack --mode production
您的支持将鼓励我继续创作!
0%