前言
上一篇介绍完 HMR 热更新之后,接着我们会讲解 React 项目搭建。
正文
题外话
首先官方提供了一个 create-react-app 脚手架工具来创建 React 项目。
*本项目不采用该脚手架进行搭建。
*下面使用 npm 举例,与 yarn 大同小异。
*仅简述,不感兴趣可跳过该内容。
# 安装 create-react-app $ npm install -g create-react-app # 创建项目 $ create-react-app your_project # 打开项目 $ cd your_project # 运行项目 $ npm run start # 项目打包 $ npm run build # 自定义配置,注意执行这个命令是不可逆的 $ npm run eject
我们通过
create-react-app
创建的项目,可以看到它只有react
、react-dom
、react-scripts
等少数依赖。其实,它将webpack
、Babel
、ESLint
等依赖包通过creat-react-app
封装到了react-scripts
当中,包括基本启动命令都是通过调用react-scripts
这个依赖下面的命令来完成的。除了
start
、build
、test
命令。它还有一个"eject": "react-scripts eject"
命令。它的作用是什么呢?它会将原本
creat-react-app
对webpack
、Babel
、ESLint
等相关配置的封装“弹出”。假如我们要将creat-react-app
配置文件进行修改,现有目录下是没有地方修改的。此时,我们就可以通过npm run eject
命令将原本被封装到脚手架当中的命令弹射出来,然后在项目目录下看到很多配置文件。注意,该命令是单向操作,不可逆。(在README.md
中对此命令有简述。)
使用 Babel
Babel 是什么?
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能为你做的事情:
- 语法转换
- 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块,babel 7.4 开始废弃
@babel/polyfill
)- 源码转换 (codemods)
- 更多! (查看这些 视频 获得启发)
babel 配置
- 安装依赖
$ yarn add --dev babel-loader@8.0.6 @babel-core/core@7.7.4
- 添加
module.rules
配置
// webpack.config.js { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader' }
- 创建
.babelrc
配置文件
我们已经配置了 Babel,但实际上并未做任何事情。在项目根目录中创建一个.babelrc
配置文件(JSON),并启用一些预设和插件。
- @babel/preset-env:解析 ES6 语法,它只做语法转换,如
const
、let
。它并不处理includes
、Promise
等 api。 - @babel/preset-react:解析 JSX 语法。
- @babel/plugin-transform-runtime:解决全局变量污染,以及重复声明 helper 函数的问题。
$ yarn add --dev @babel/preset-env@7.7.4 $ yarn add --dev @babel/preset-react@7.7.4 $ yarn add --dev @babel/plugin-transform-runtime@7.7.4 $ yarn add --dev core-js@3.6.0
// .babelrc { "presets": [ [ "@babel/preset-env", { "modules": false, // 将 ESM 转化为其他模块规范,默认值 false。 "useBuiltIns": "usage", // 按需加载 "corejs": 3, // Babel 建议使用 useBuiltIns 选项时显式设置 core-js 版本 "debug": false // 打印插件使用情况 } ], "@babel/preset-react" // 解析 JSX 语法 ], "plugins": ["@babel/plugin-transform-runtime"] }
*关于 .babelrc
相关预设与插件详解,在后续会专门出一篇文章整理介绍;
*顺序问题:1 Plugins 在 Presets 前运行;2 Plugins 按照声明次序顺序执行;3 Presets 按照声明次序逆序执行。
React
- 首先安装
react
、react-dom
依赖包。
$ yarn add react@16.12.0 react-dom@16.12.0
插个话题:为什么 react 和 react-dom 要分成两个包?
对于具有跨平台能力的 React 体系来说,分包可以将抽象逻辑与平台实现分开。
- react 包即是抽象逻辑,它包含了 React 的主干逻辑。例如组件实现、更新调度等。
- react-dom 顾名思义就是一种针对 dom 的平台实现,主要用于在 web 端进行渲染。而声名在外的 React Native 则是原生应用实现,可以通过 React Native 内部的相应机制与操作系统进行通信来调用原生控件进行渲染。
*以上简述来自知乎 Shockw4ver 回答。
- 引入 react
// index.js import React from 'react' import { render } from 'react-dom' import './main.js' import './style.css' // 最简单的 React 示例 const rootElem = document.getElementById('app') render(<div>Hello React!</div>, rootElem) if(module.hot) { module.hot.accept('./main.js', () => { console.log('Accept update!') }) }
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <div id="app"></div> </body> </html>
至此,最简单的 React 示例已经成功了。
接下来,我们将会先介绍接入 react-hot-loader
实现 react 的局部刷新问题。
最后附上
// package.json { "name": "webpack4_demo", "version": "1.0.0", "description": "从零到一搭建 react 项目", "main": "src/index.js", "repository": "git@github.com:toFrankie/webpack4_demo.git", "author": "Frankie <1426203851@qq.com>", "license": "MIT", "private": true, "scripts": { "dev": "webpack-dev-server --config webpack.config.js --colors", "build": "webpack --config webpack.config.js --progress --colors --mode=production" }, "dependencies": { "react": "16.12.0", "react-dom": "16.12.0", "webpack": "4.41.2", "webpack-cli": "3.3.10" }, "devDependencies": { "@babel/core": "7.7.4", "@babel/plugin-transform-runtime": "7.7.4", "@babel/preset-env": "7.7.4", "@babel/preset-react": "7.7.4", "babel-loader": "8.0.6", "clean-webpack-plugin": "3.0.0", "core-js": "3.6.0", "css-loader": "3.2.0", "html-webpack-plugin": "3.2.0", "style-loader": "1.0.0", "webpack-dev-server": "3.9.0" } }