从零构建一个React项目
从零构建一个React项目
Start
新建文件夹,执行
yarn init
安装基础包
yarn add react react-dom
yarn add webpack webpack-cli
简单编写代码
-
添加 src 文件夹
-
在 src 添加 index.js 文件
-
index.js 文件内容:
import ReactDom from 'react-dom'; ReactDom.render('xxx',document.getElementById('root')); -
添加 webpack.config.js 配置简单配置webpack
module.exports={ entry:'./src/index.js', output:{ filename:'./index.js' } } -
编辑 package.json 文件,添加编译命令
"scripts": { "build": "webpack " }, -
命令行执行编译命令
yarn run build
完成最简版本前端项目,编译出 index.js 手动创建 index.html 添加对该 js 的引用
index.html
<html><body><div id="root"></div><script src="./index.js"></script></body></html>
使用第一个插件
简单版需要手动创建 html 和手动引用资源文件,显然我们并不想这么干,在 css ,图片,等资源丰富之后,一个个手动新增并不现实,于是我们需要一个插件帮助在 build 阶段实现自动输出 index.html。
使用 HtmlWebpackPlugin 插件
-
安装
yarn add --dev html-webpack-plugin -
在 src 下创建 index.html 模板文件,内容如下
<html> <body> <div id='root'> </div> </body> </html> -
配置使用
const HtmlWebpackPlugin=require('html-webpack-plugin'); module.exports={ entry:'./src/index.js', output:{ filename:'./index.js' }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ] } -
再次 build 在 dist 文件夹可以看到 index.js 和 index.html 文件,使用浏览器打开 index.html 出现如我们所期望的内容。
更近一步
简单项目我们使用了 ReactDom 挂载简单的内容到指定 Dom 容器中,显然我们实际工作中并不会如此简单,更近一步的,我们需要做到
- 使用 TypeScript
- 使用 JSX
- 使用 webpack dev server
- 引用 CSS 文件
- 引用静态图片文件
使用JSX
-
创建
src/app文件夹,新建index.js文件,内容如下:import { Component } from 'react' class Index extends Component { render() { return 'xxxx'; } } export default Index; -
在
src/index.js中使用jsximport ReactDom from 'react-dom'; import App from './app/index'; ReactDom.render(<App />,document.getElementById('root')); -
执行
yarn run build这时会报错,因为jsx作为 js 的语法扩展,并不被原生 js 支持,我们需要配置webpack,使用babel-loader -
安装
yarn add --dev babel-loader @babel/preset-react -
配置 webpack.config.js
module: { rules: [ { test: /\.(ts|js|tsx)?$/, use: [ { loader: 'babel-loader', options: { presets: ['@babel/preset-react'] } } ], exclude: /node_modules/, }, ], }, -
执行
yarn run build可以看到成功编译 -
打开 index.html 文件,页面空白,控制台报错
react is not defined发现编译后没有React库 -
修改
src/index.js,添加对 React 的引用import ReactDom from 'react-dom'; import React from 'react'; import App from './app/index'; ReactDom.render(<App />,document.getElementById('root')); -
修改
src/app/index.js,添加对 React 的引用import React, { Component } from 'react' class Index extends Component { render() { return ( <div> xxxxxxxxxxx </div> ); } } export default Index; -
再次编译后,提示成功,打开 html 页面,显示正常。
使用 TypeScript
-
修改
src/app/index.js文件名后缀为index.tsx -
修改
src/app/index.tsx内容为import React, { Component } from 'react' interface IndexProps { name: string; age: number; } class Index extends Component<IndexProps> { render() { return ( <div> xxxxxxxxxxx </div> ); } } export default Index; -
修改
src/index.js文件名后缀为index.tsx -
添加插件
yarn add --dev typescript awesome-typescript-loader source-map-loader -
修改webpack配置,添加 Loader
{ test: /\.tsx?$/, loader: "awesome-typescript-loader" },添加 resolve 配置,实现 webpack 对
tsx后缀文件的识别resolve: { extensions: ['.tsx', '.ts', '.js'], } -
添加
tsconfig.json配置 typescript 编译器选项{ "compilerOptions": { "outDir": "./dist/", "sourceMap": true, "noImplicitAny": true, "module": "commonjs", "target": "es5", "esModuleInterop": true, "jsx": "react" }, "include": [ "src" ], }注意,不添加 esModuleInterop 会导致一些没有默认导出的外部模块报错
-
执行编译,如期报错,因为我们在使用组件时没有给组件添加属性。
-
修改
src/index.tsx文件内容如下import ReactDOM from 'react-dom'; import React from 'react'; import App from './app/index'; ReactDOM.render(<App age={1} name="xxx" />,document.getElementById('root')); -
再次执行
yarn run build,编译成功,打开 index.html 显示正常
使用 webpack dev server
我们使用开发服务器代替打开html文件的方式
-
添加包
yarn add --dev webpack-dev-server -
在
package.json添加执行脚本"start": "webpack-dev-server" -
配置
webpack.config.js文件新增devServer节点devServer: { contentBase: path.join(__dirname, 'dist'), compress: true, port: 9000 } -
使用命令
yarn start启动开发环境。访问http://localhost:9000看到页面正常显示,修改文件,自动编译和刷新
这个配置几乎没有遇到坑点。
引入样式
我们需要事项以下目的:
- 在组件中使用
import { myclassname } from '../index.scss'导入和使用样式。 - 编译后,生成单独的样式文件
步骤:
-
新增
src/style.scss样式文件,并编写样式内容如下.test{ text-align: center; width: 100%; } -
修改
src/app/index.tsx文件,添加引入和使用样式的代码import React, { Component } from 'react' import Styles from '../style.scss'; interface IndexProps { name: string; age: number; } class Index extends Component<IndexProps> { render() { return ( <div className={Styles.test} > xxxxxxxxxxx </div> ); } } export default Index; -
执行
yarn start报错,提示没有处理改类型文件的 Loader。 -
安装 Loader
yarn add --dev css-loader sass-loader style-loader -
修改 webpack配置文件,添加 Loader
{ test: /\.css|scss$/, use: [ "style-loader", { loader: require.resolve('css-loader'), options: { modules: true, } }, "sass-loader" // 将 Sass 编译成 CSS,默认使用 Node Sass ] } -
执行
yarn start提示成功,打开浏览器可以看到文字已居中,但是我们会发现,并没有使用单独的 css 文件,而是通过 js 创建的css,这不利于生产上,用户对资源的缓存,比如我们修改的 js ,但是没有修改样式,最终编译出来的 js 有变化,客户端会重新加载而不使用缓存,所以我们需要分离 js 和 css 。 -
安装插件
yarn add --dev mini-css-extract-plugin修改 webpack 配置,需要修改 Loader 以及添加插件-
替换 style-loader
{ test: /\.css|scss$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { publicPath: '../' } }, { loader: require.resolve('css-loader'), options: { modules: true, } }, "sass-loader" // 将 Sass 编译成 CSS,默认使用 Node Sass ] } -
添加 plugins
plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: '[name].css', chunkFilename: '[id].css' }) ], -
注意需要在开头引入插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-
-
再次执行
yarn start页面成功运行,并且在网络请求中可以看到有单独的 css 文件。
坑点:
- 当前已经不需要使用
typings-for-css-modules-loader来做在 tsx 中应用 css 文件的功能,只需要修改 css-loader 的 options 添加modules: true即可
使用静态图片
我们希望实现
-
图片资源可以在组件中被 import
-
图片资源可以这样使用
import myimg from '../asset/test.png'; .... <img src={myimg} />
步骤:
-
修改
src/app/index.tsx文件,添加图片引用和使用代码import React, { Component } from 'react' import Styles from '../style.scss'; import baiduImg from '../asset/baidu-logo.png'; interface IndexProps { name: string; age: number; } class Index extends Component<IndexProps> { render() { return ( <div className={Styles.test} > <img src={baiduImg} /> xxxxxxxxxxx </div> ); } } export default Index; -
执行
yarn start报错,提示无法处理该类型文件。 -
添加
file-loaderyarn add --dev file-loader -
修改 webpack 配置,添加 Loader
{ loader: require.resolve('file-loader'), // Exclude `js` files to keep "css" loader working as it injects // its runtime that would otherwise be processed through "file" loader. // Also exclude `html` and `json` extensions so they get processed // by webpacks internal loaders. exclude: [/\.(js|mjs|jsx|ts|tsx|css|scss)$/, /\.html$/, /\.json$/], options: { name: `[name].[hash:12].[ext]`, }, }, -
再次执行
yarn start页面正常加载,图片显示。
未发现坑点。
其他
-
开启
source map,在开发阶段方便调试代码。需修改 webpack 配置如下module.exports = { entry: './src/index.tsx', output: { filename: './index.js' }, devtool: "source-map", .....
结束
如此我们大致实现了 create-react-app 帮助实现的基本功能,但是我们观察 create 帮助创建的项目,会发现,仍然有很多插件和实现我们没有使用到过,在下面的开发中,我们尝试构建一个完整的复杂前端项目,发现问题的同时,理解 create 中的其他插件和操作。

浙公网安备 33010602011771号