create-react-app-from-scratch
create-react-app-from-scratch
React社区中提供了类似create-react-app
这样的命令行工具,作为React项目的脚手架,这个工具提供了大而全的功能,直接拿过来使用,你可能不明白背后的原理,这里跟着Creating a React App… From Scratch这篇文章一起从零搭建一个React App,有条件的同学可以直接阅读英文版,这里实现的是一个最简单的功能,支持ES6+和JSX语法、热加载。
起步
创建一个目录并且通过npm init
初始化一个项目,有需要也可以通过git init
创建版本管理,新项目的文件结构如下:
.
+-- public
+-- src
此时可以添加一个.gitignore
文件,并把node_modules
和dist
目录排除在提交范围。
在public
目录中,将会存放一些静态的资产,最主要的是放置index.html
文件,让react用来渲染app用。
index.html
如下:
<!-- 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相关的软件包:
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-react
和preset-env
用于预先配置要转换的代码类型,env
预置用以转换ES6+的代码到ES5的代码,react
预置转换JSX的代码。
接着在项目的根目录,创建一个文件.babelrc
,用于告诉bebel我们要配置的预置项。
{
"presets": ["@babel/env", "@babel/preset-react"]
}
Babel还有很多的插件值得研究。
Webpack
接下来需要配置Webpack来打包和启用开发热加载等功能。
安装开发依赖:
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配置的对象:
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.2
和react-dom@16.5.2
npm install --save react@16.5.2 react-dom@16.5.2
接下来,要告诉React app在哪里关联DOM,在src
文件夹中创建一个index.js
文件:
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组件。
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
文件
.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
在webpack的script中增加一个脚本命令,start
start: webpack-dev-server --mode development
使用npm start
命令即可启动
Finishing HMR
这个时候修改文件内容,页面并不会自动更新,要增加热加载功能,需要另外一个软件包的支持
npm install --save react-hot-loader@4.3.11
这个包可以安装在依赖中,而不是开发依赖,因为包会自动判断是否执行。
在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(
<div className="App">
<h1> Hello, World! </h1>
</div>
);
}
}
export default hot(module)(App);
这个时候修改文件的内容,页面就会即时刷新了。
Build
最后,可以在package.json中增加一个build的脚本命令,
build: webpack --mode production