完整搭建一個(gè)React項(xiàng)目
本項(xiàng)目主要讓我們是知道一個(gè)react項(xiàng)目大概需要哪些東西才能夠跑起來。
項(xiàng)目中用到了react、react-dom、antd、webpack 系列、babel、以及一堆loader
項(xiàng)目結(jié)構(gòu)
新建一個(gè)文件夾 demo,目錄結(jié)構(gòu)如下
- demo
- src // 應(yīng)用的所有代碼
- actions // 處理異步請(qǐng)求
- assets // 靜態(tài)資源
- components // 公用組件
- pages // 業(yè)務(wù)邏輯頁面
- reducers // reducer 狀態(tài)處理
- util // 公用方法
- index.html // 項(xiàng)目模板
- index.js // 項(xiàng)目入口
- package.json // npm init 自動(dòng)生成
- webpack.config.js // webpack 配置文件
初始化NPM
在項(xiàng)目的根目錄下打開命令行,輸入:
npm init -y
安裝webpack
npm i webpack webpack-cli webpack-command --save-dev
這里直接將webpack 的三個(gè)基本項(xiàng)安裝好
ps:
--save-dev與--save的區(qū)別
--save-dev表示只是在編譯過程中所依賴的包,例如:webpack、sass-loader等 最后在package.json的devDependencies部分顯示
--save 表示編譯后在運(yùn)行時(shí)還需要依賴的包,例如 react react-dom等 最后在package.json的dependencies部分顯示
也可以指定安裝webpack的版本
npm install --save-dev webpack@[version] //version代表版本號(hào)
配置webpack.config.js文件
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js', // 輸出的文件名
path: path.resolve(__dirname, 'dist')
}
};
// entry 是入口文件
// output 是編譯后文件
// __dirname 全局變量 代表當(dāng)前文件所在文件夾的完整路徑
// path.resolve 返回一個(gè)路徑 __dirname+'/dist'
安裝其他webpack的插件
自動(dòng)創(chuàng)建html文件 html-webpack-plugin
npm i --save-dev html-webpack-plugin
清除無用文件 clean-webpack-plugin
npm i --save-dev clean-webpack-plugin
在每次編譯之前把上一次打包的文件清除
一堆樣式編譯loader插件
node-sass和sass-loader 是用來編譯scss文件
style-loader和css-loader 是用來編譯css文件
file-loader url-loader 加載其他文件,比如圖片,字體
npm i --save-dev style-loader css-loader node-sass sass-loader file-loader url-loader
webpack 服務(wù)器 webpack-dev-server
npm i --save-dev webpack-dev-server
再完善一下webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');//自動(dòng)創(chuàng)建html文件
const CleanWebpackPlugin = require('clean-webpack-plugin');//清除多余文件
module.exports = {
devtool: 'cheap-module-eval-source-map',// 用于開發(fā)調(diào)試,方便清楚是那個(gè)文件出錯(cuò) (共有7種)
entry: {
index: './src/index.js'
},
output: {
filename: 'bundle.js', // 輸出的文件名
path: path.resolve(__dirname, 'dist') //
},
module: {
rules: [{
test: /\.css$/,
use:"style-loader!css-loader"
}, {
test: /\.scss$/,
use:["style-loader","css-loader","sass-loader"]
// 加載時(shí)順序從右向左
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
}]
},
// 開啟一個(gè)虛擬服務(wù)器
devServer: {
contentBase: './dist',
hot: true
},
plugins: [
new CleanWebpackPlugin(['dist']),//每次編譯都會(huì)把dist下的文件清除,我們可以在合適的時(shí)候打開這行代碼,例如我們打包的時(shí)候,開發(fā)過程中這段代碼關(guān)閉比較好
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: 'src/index.html' //使用一個(gè)模板
})
]
};
修改 package.json
...
"scripts": {
"watch": "webpack --watch",
"start": "webpack-dev-server --open",
"build": "webpack"
},
...
其他文件
src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
src/index.js
console.log('hello world')
運(yùn)行
npm run build
編譯成功后在根目錄下就能看到一個(gè)dist文件夾
集成React
安裝react 的東西,以及antd
npm i --save react react-dom antd
修改index.js
import React,{Component} from 'react';
import ReactDom from 'react-dom';
class App extends Component {
constructor(props) {
super(props);
this.state = { };
}
render() {
return (
<div>
<p>Hello World</p>
</div>
);
}
}
export default App;
ReactDom.render(<App />,document.getElementById('root'));
babel的使用
因?yàn)閞eact是使用jsx編寫,瀏覽器無法識(shí)別,所以需要一個(gè)編譯工具,這里使用babel
安裝babel
npm i --save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties
npm i --save @babel/polyfill
npm i --save-dev babel-loader
修改webpack.config.js
在 module的rules中加入
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/
}
最終的webpack.config.js文件如下
const path = require('path');
const webpack = require('webpack');
const HtmlPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'inline-source-map',
entry: {
index: './src/index.js'
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
module: {
rules: [{
test: /\.css$/,
loader:['style-loader', 'css-loader']
}, {
test: /\.scss$/,
loader: ['style-loader', 'css-loader', 'sass-loader']
}, {
test: /\.(png|svg|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'img/[name].[hash:7].[ext]'
}
}, {
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/
}]
},
devServer: {
contentBase: './build',
port: 8081,
inline: true,
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlPlugin({
template: 'src/index.html'
})
]
}
添加babel配置文件
在根目錄下添加文件 .babelrc
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
]
}
運(yùn)行
npm run build
出現(xiàn)一個(gè)警告信息
warning The 'mode' option has not been set, webpack will fallback to
'production' for this value. Set 'mode' option to 'development' or
'production' to enable defaults for each environment.
大概的意思是我們沒有指定命令的模式是開發(fā)還是生產(chǎn)
修改package.json文件
...
"scripts": {
"watch": "webpack --watch",
"build": "webpack --mode production",
"dev": "webpack --mode development& webpack-dev-server --open --mode development",
"start": "webpack-dev-server --open --mode production"
},
...
這次我們可以直接運(yùn)行
npm run dev
看結(jié)果
如果在這過程中有出現(xiàn)其他的報(bào)錯(cuò)信息,可以直接百度,一般的問題其他人都遇到過!
使用scss
在assets目錄下新建style.scss文件
.red{
color:red;
}
修改 index.js,導(dǎo)入scss文件
...
import './assets/style.scss'
...
...
return (
<div>
<p className="red">Hello World</p>
</div>
);
...
頁面刷新后我就能看到樣式改變。
但是這樣有一個(gè)問題就是,css樣式是直接編譯到bundle.js文件中的。不太符合我們的開發(fā)習(xí)慣,所以我們要編譯后把css樣式和js拆分開來,這時(shí)我們就需要用到樣式分離插件
分離文件 extract-text-webpack-plugin
npm i --save-dev extract-text-webpack-plugin
修改webpack.config.js
...
const HtmlPlugin = require('html-webpack-plugin');
+++ const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
....
module: {
rules: [{
test: /\.css$/,
use:ExtractTextPlugin.extract({
fallback:"style-loader",
use:"css-loader"
})
}, {
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback:"style-loader",
use:"css-loader!sass-loader"
})
}
...],
...
plugins: [
+++ new ExtractTextPlugin("styles.css")
]
},
}
...
再一次運(yùn)行,我們就能看到在dist文件夾下出現(xiàn)一個(gè)style.css文件
如果出現(xiàn)報(bào)錯(cuò)
DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
則是因?yàn)楫?dāng)前安裝的文件分離插件不支持webpack4,安裝最新版的即可
npm install extract-text-webpack-plugin@next
至此,一個(gè)簡單的react框架就搭建起來了