本文詳細介紹瞭如何從零開始搭建一個 React 開發的腳手架,包含如何新增 Redux 以及 React Router 的環境。
本文程式碼地址:react-mobx-starter。
建議將程式碼拉下來之後,配合本文一起檢視,效果更佳。
程式碼下載命令:
git clone https://github.com/beichensky/react-mobx-starter.git
複製程式碼
最近將腳手架中的 babel 配置更新到了 7.0.0 版本,所以部分地方作出了修改。目前腳手架中的各類庫的版本如下:
- node:10.15.3
- npm:6.4.1
- webpack: 4.29.6
- webpack-cli: 3.3.0
- webpack-dev-server: 3.1.4
- @babel/core: 7.0.0
- react: 16.8.6
- mobx: 5.9.4
- react-router-dom: 5.0.0
如果是從低版本升級到 7.0.0
版本,官方提供了一個新的命令可以直接幫助我們對專案進行更新:
npx babel-upgrade --write --install
複製程式碼
更多關於 babel-upgrade
的介紹可以參考官方說明 。
一、前情提要
本文的 Demo
分為兩個環境,一個是開發環境,另一個是生產環境。
-
開發環境中講述的是如何配置出一個更好的、更方便的開發環境;
-
而生產環境中講述的是如何配置出一個更優化、更小版本的生產環境。
之前我也就 Webpack
的使用寫了幾篇文章,本文也是在 Webpack
的基礎上進行開發,也是在之前的程式碼上進行的擴充套件。
-
開發環境的配置是在 從零開始搭建一個 Webpack 開發環境配置(附 Demo) 一文的基礎上進行的擴充套件。
-
生產環境的配置是在 使用 Webpack 進行生產環境配置(附 Demo) 一文的基礎上進行的擴充套件。
建議:對於 Webpack 還不瞭解的朋友,可以先看一下 從零開始搭建一個 Webpack 開發環境配置(附 Demo) 和 使用 Webpack 進行生產環境配置(附 Demo) 這兩篇文章,可以更好的入手本文。
雖然本文是在之前文章上進行的擴充套件,但本文還是會詳細的介紹每一步的配置。
二、建立專案結構
新建資料夾,命名為:react-mobx-starter
mkdir react-mobx-starter
複製程式碼
初始化 package.json
檔案
cd react-mobx-starter
# 直接生成預設的 package.json 檔案
npm init -y
複製程式碼
建立 src
目錄,用來存放我們編寫的程式碼
建立 public
目錄,用來存放公共的檔案
建立 webpack
目錄,用來存放 webpack
配置檔案
mkdir src
mkdir public
mkdir webpack
複製程式碼
在 src 目錄下 新建 pages 資料夾,用來存放書寫的頁面元件 新建 components 資料夾,用來存放公共元件 新建 utils 資料夾,用來存放常用的工具類
cd src
mkdir pages
mkdir components
mkdir utils
複製程式碼
在 public
目錄下新建 index.html
檔案
在 src
目錄下新建 index.js
檔案
在 webpack
目錄下建立 webpack.config.dev.js
和 webpack.config.prod.js
webpack.config.dev.js
用來編寫 webpack 開發環境配置webpack.config.prod.js
用來編寫 webpack 生產環境配置
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>React + Mobx 全家桶腳手架</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
複製程式碼
index.js
function createElement() {
const ele = document.createElement('div');
ele.innerHTML = 'Hello, React';
const root = document.querySelector('#root');
root.appendChild(ele);
}
createElement();
複製程式碼
webpack.config.dev.js
和 webpack.config.prod.js
此時還沒有書寫內容,我們之後會詳細的進行講述。
我們看一下此時的專案結構,之後就可以進行 webpack 的配置了。
react-mobx-starter
├─ public/
└─ index.html
├─ src/
├─ components/
├─ pages/
├─ utils/
└─ index.js
├─ webpack/
├─ webpack.config.dev.js
└─webpack.config.prod.js
├─ package.json
複製程式碼
三、React 開發環境配置
在 package.json 檔案中新增一個執行指令碼,用來執行 webpack 命令:
{
...,
"scripts": {
"start": "webpack --config webpack/webpack.config.dev.js"
},
...
}
複製程式碼
安裝 webpack 相關外掛
安裝 webpack 和 webpack-cli
npm install webpack webpack-cli --save-dev
複製程式碼
入口和出口
使用 webpack 進行專案配置的時候,必須要有入口和出口,作為模組引入和專案輸出。
webpack.config.dev.js
const path = require('path');
const appSrc = path.resolve(__dirname, '../src');
const appDist = path.resolve(__dirname, '../dist');
const appPublic = path.resolve(__dirname, '../public');
const appIndex = path.resolve(appSrc, 'index.js');
module.exports = {
entry: appIndex,
output: {
filename: 'public/js/[name].[hash:8].js',
path: dist,
publicPath: '/'
}
}
複製程式碼
新增 html-webpack-plugin 外掛
執行 npm run start 指令碼,可以看到 dist/public/js
目錄下多了一個 js
檔案,但是這個是由 hash
值命名的的,我們每次都手動引入到 index.html 檔案裡面過於麻煩,所以可以引入 html-webpack-plugin
外掛。
html-webpack-plugin 外掛有兩個作用
- 可以將
public
目錄下的資料夾拷貝到dist
輸出資料夾下 - 可以自動將
dist
下的js
檔案引入到html
檔案中
安裝 html-webpack-plugin
外掛
npm install html-webpack-plugin --save-dev
複製程式碼
使用 html-webpack-plugin
外掛
webpack.config.dev.js
const path = require('path');
+ const HTMLWebpackPlugin = require('html-webpack-plugin');
const appSrc = path.resolve(__dirname, '../src');
const appDist = path.resolve(__dirname, '../dist');
const appPublic = path.resolve(__dirname, '../public');
const appIndex = path.resolve(appSrc, 'index.js');
+ const appHtml = path.resolve(appPublic, 'index.html');
module.exports = {
entry: appIndex,
output: {
filename: 'public/js/[name].[hash:8].js',
path: appDist,
publicPath: '/'
},
+ plugins: [
+ new HTMLWebpackPlugin({
+ template: appHtml,
+ filename: 'index.html'
+ })
+ ]
}
複製程式碼
設定開發模式
webpack 配置中的 mode 屬性,可以設定為 'development' 和 'production',我們目前是進行開發環境配置,所以可以設定為 'development'
webpack.config.dev.js
...
module.exports = {
+ mode: 'development',
...
}
複製程式碼
設定 devtool
為了方便在專案出錯時,迅速定位到錯誤位置,可以設定 devtool,生成資源對映,我們這裡使用 inline-source-map
,更多選擇可以在這裡檢視區別。
webpack.config.dev.js
...
module.exports = {
mode: 'development',
+ devtool: 'inline-source-map',
...
}
複製程式碼
使用 webpack-dev-server 啟動專案服務
安裝 webpack-dev-server
npm install webpack-dev-server --save-dev
複製程式碼
配置 webpack-dev-server
webpack.config.dev.js
...
module.exports = {
mode: 'development',
devtool: 'inline-source-map',
+ devServer: {
+ contentBase: appPublic,
+ hot: true,
+ host: 'localhost',
+ port: 8000,
+ historyApiFallback: true,
+ // 是否將錯誤展示在瀏覽器蒙層
+ overlay: true,
+ inline: true,
+ // 列印資訊
+ stats: 'errors-only',
+ // 設定代理
+ proxy: {
+ '/api': {
+ changeOrigin: true,
+ target: 'https://easy-mock.com/mock/5c2dc9665cfaa5209116fa40/example',
+ pathRewrite: {
+ '^/api/': '/'
+ }
+ }
+ }
+ },
...
}
複製程式碼
修改一下 package.json
檔案中的 start
指令碼:
{
...,
"scripts": {
"start": "webpack-dev-server --config webpack/webpack.config.dev.js"
},
...
}
複製程式碼
使用 friendly-errors-webpack-plugin 外掛
friendly-errors-webpack-plugin
外掛可以在命令列展示更有好的提示功能。
安裝 friendly-errors-webpack-plugin
:
npm install friendly-errors-webpack-plugin --save-dev
複製程式碼
使用 friendly-errors-webpack-plugin
:
webpack.config.dev.js
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
+ const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
...
module.exports = {
...
plugins: [
new HTMLWebpackPlugin({
template: appHtml,
filename: 'index.html'
}),
+ new FriendlyErrorsWebpackPlugin(),
]
}
複製程式碼
啟用熱載入
webpack.config.dev.js
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
+ const webpack = require('webpack');
...
module.exports = {
...
plugins: [
...
new FriendlyErrorsWebpackPlugin(),
+ new webpack.HotModuleReplacementPlugin()
]
}
複製程式碼
執行專案,測試配置成果
執行 npm run start
命令,命令列提示成功後,在瀏覽器開啟 http://localhost:8000
,可以看到 Hello React
,說明基本的Webpack 配置已經成功了。
配置 babel
我們現在 index.js
裡面的程式碼量比較少,所以沒有問題。但是我如果想在裡面使用一些 ES6 的語法或者是還未被標準定義的 JS 特性,那麼我們就需要使用 babel 來進行轉換了。下面我們來配置一下 babel
。
安裝 babel 相關外掛
npm install @babel/core babel-loader --save-dev
複製程式碼
使用 babel-loader
設定 cacheDirectory 屬性,指定的目錄將用來快取 loader 的執行結果。之後的 webpack 構建,將會嘗試讀取快取,來避免在每次執行時,可能產生的、高效能消耗的 Babel 重新編譯過程。
webpack.config.dev.js
...
module.exports = {
...
plugins: [ ... ],
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader?cacheDirectory',
include: [ appSrc ],
exclude: /node_modules/
}
]
}
}
複製程式碼
在專案根目錄下新建 babel.config.js 檔案
babel.config.js
檔案是執行時控制檔案,在專案編譯的時候會自動讀取 babel.config.js
檔案中的 babel
配置。
使用 babel 相關 presets
安裝相關外掛:
@babel/preset-env
:可以在專案中使用所有ECMAScript
標準裡的最新特性。@babel/preset-react
:可以在專案中使用react
語法。
npm install babel-preset-env babel-preset-react --save-dev
複製程式碼
配置 babel.config.js
檔案:
module.exports = (api) => {
api.cache(true);
return {
presets: [
"@babel/preset-env",
"@babel/preset-react"
]
}
}
複製程式碼
使用 babel 相關 plugins
babel
升級到 7.0.0
版本之後, @babel/preset-stage-0
被廢棄,用到的外掛需要自己進行安裝。
如果是從低版本升級到 7.0.0
版本,官方提供了一個新的命令可以直接幫助我們對專案進行更新:
npx babel-upgrade --write --install
複製程式碼
更多關於 babel-upgrade
的介紹可以參考官方說明 。
安裝相關外掛:
@babel/plugin-proposal-decorators
:可以在專案中使用裝飾器語法。@babel/plugin-proposal-class-properties
:可以在專案中使用新的 class 屬性語法。@babel/plugin-transform-runtime
:使用此外掛可以直接使用 babel-runtime 中的程式碼對js
檔案進行轉換,避免程式碼冗餘。@babel/runtime-corejs2
:配合babel-plugin-transform-runtime
外掛成對使用@babel/plugin-syntax-dynamic-import
:可以在專案中使用import()
這種語法@babel/plugin-proposal-export-namespace-from
:可以使用 export * 這種名稱空間的方式匯出模組@babel/plugin-proposal-throw-expressions
:可以使用異常丟擲表示式@babel/plugin-proposal-logical-assignment-operators
:可以使用邏輯賦值運算子@babel/plugin-proposal-optional-chaining
:可以使用可選鏈的方式訪問深層巢狀的屬性或者函式 ?.@babel/plugin-proposal-pipeline-operator
:可以使用管道運算子 |>@babel/plugin-proposal-nullish-coalescing-operator
:可以使用空值合併語法 ??@babel/plugin-proposal-do-expressions
:可以使用 do 表示式(可以認為是三元運算子的複雜版本)@babel/plugin-proposal-function-bind
:可以使用功能繫結語法 obj::func
npm install @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime @babel/runtime-corejs2 @babel/plugin-syntax-dynamic-import @babel/plugin-proposal-export-namespace-from @babel/plugin-proposal-throw-expressions @babel/plugin-proposal-logical-assignment-operators @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-pipeline-operator @babel/plugin-proposal-nullish-coalescing-operator @babel/plugin-proposal-do-expressions @babel/plugin-proposal-function-bind --save-dev
複製程式碼
配置 babel.config.js
檔案:
module.exports = (api) => {
api.cache(true);
return {
presets: [
"@babel/preset-env",
"@babel/preset-react"
],
plugins: [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
[
"@babel/plugin-transform-runtime",
{
"corejs": 2
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose": true
}
],
"@babel/plugin-syntax-dynamic-import",
// 可以使用 export * 這種名稱空間的方式匯出模組
"@babel/plugin-proposal-export-namespace-from",
// 可以使用異常丟擲表示式,
"@babel/plugin-proposal-throw-expressions",
// 預設匯出
"@babel/plugin-proposal-export-default-from",
// 可以使用邏輯賦值運算子
"@babel/plugin-proposal-logical-assignment-operators",
// 可以使用可選鏈的方式訪問深層巢狀的屬性或者函式 ?.
"@babel/plugin-proposal-optional-chaining",
// 可以使用管道運算子 |>
[
"@babel/plugin-proposal-pipeline-operator",
{
"proposal": "minimal"
}
],
// 可以使用空值合併語法 ??
"@babel/plugin-proposal-nullish-coalescing-operator",
// 可以使用 do 表示式(可以認為是三元運算子的複雜版本)
"@babel/plugin-proposal-do-expressions",
// 可以使用功能繫結語法 obj::func
"@babel/plugin-proposal-function-bind"
]
}
}
複製程式碼
這裡需要注意
@babel/plugin-proposal-decorators
外掛的放置順序,最好放在第一位,否則可能會出現某些註解失效的問題。
至此,babel 相關的基本配置完成了。之後我們就可以在專案中肆意使用各種新的 JS 特性了。
新增 css 相關 loader
js
檔案相關的 babel-loader
配置好了,但是有時候我們想在專案中為元素新增一些樣式,而 webpack
中認為一切都是模組,所以我們這時候也需要別的 loader
來解析一波樣式程式碼了。
安裝相關外掛:
css-loader
:處理css
檔案中的url()
等。style-loader
:將css
插入到頁面的style
標籤。less-loader
:是將less
檔案編譯成css
。postcss-loader
:可以整合很多外掛,用來操作css
。我們這裡使用它整合autoprefixer
來自動新增字首。
npm install css-loader style-loader less less-loader postcss-loader autoprefixer --save-dev
複製程式碼
配置樣式相關 loader
- 由於
React
無法直接使用類似Vue
中scope
這種區域性作用變數,所以我們可以使用webpack
提供的CSS Module
。 2、由於等會兒會使用antd
,所以引入antd
時需要開啟less
的javascript
選項,所以要將less-loader
中的屬性javascriptEnabled
設定為true
。
在 webpack.config.dev.js 中配置:
...
const autoprefixer = require('autoprefixer');
module.exports = {
...,
plugins: [...],
module: {
rules: [
...,
{
test: /\.(css|less)$/,
exclude: /node_modules/,
use: [{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
sourceMap: true,
modules: true,
localIdentName: '[local].[hash:8]'
}
},
{
loader: 'postcss-loader',
options: {
plugins: () => [autoprefixer()]
}
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true
}
}
]
},
{
test: /\.(css|less)$/,
include: /node_modules/,
use: [{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {}
},
{
loader: 'postcss-loader',
options: {
plugins: () => [autoprefixer()]
}
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true
}
}
]
},
]
}
}
複製程式碼
新增其他模組解析 loader 配置
安裝相關外掛:
npm install file-loader csv-loader xml-loader html-loader markdown-loader --save-dev
複製程式碼
在 webpack.config.dev.js 中配置:
...
module.exports = {
...,
plugins: [...],
module: {
rules: [
...,
// 解析圖片資源
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
// 解析 字型
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
// 解析資料資源
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
// 解析資料資源
{
test: /\.xml$/,
use: [
'xml-loader'
]
},
// 解析 MakeDown 檔案
{
test: /\.md$/,
use: [
'html-loader',
'markdown-loader'
]
}
]
}
}
複製程式碼
額外的 webpack 配置優化
新增 resolve allias 屬性,設定別名
在專案開發過程中,隨著專案越來越大, 檔案層級越來越深,引入檔案的時候可能會需要一層一層的找路徑,就會比較繁瑣,我們可以使用 resolve
中的 alias
屬性為一些常用的資料夾設定別名
webpack.config.dev.js
···
module.exports = {
...,
plugins: [...],
module: {...},
+ resolve: {
+ alias: {
+ src: appSrc,
+ utils: path.resolve(__dirname, '../src/utils'),
+ pages: path.resolve(__dirname, '../src/pages'),
+ components: path.resolve(__dirname, '../src/components')
+ }
+ }
}
複製程式碼
新增 resolve.modules 屬性,指明第三方模組存放位置
我們知道,一般進行模組搜尋時,會從當前目錄下的 node_modules
一直搜尋到磁碟根目錄下的 node_modules
。所以為了減少搜尋步驟,我們可以設定 resolve.modules
屬性強制只從專案的 node_modules
中查詢模組。
webpack.config.dev.js
···
module.exports = {
...,
plugins: [...],
module: {...},
resolve: {
...,
+ modules: [path.resolve(__dirname, '../node_modules')],
}
}
複製程式碼
安裝 React、MObx 以及 React Router 相關外掛
npm install react react-dom prop-types mobx mobx-react react-router-dom --save
複製程式碼
引入 antd
按照 antd
官網的說明,直接在 babel.config.js
檔案中新增配置,之後即可在專案中正常使用了。
安裝 antd 相關外掛:
npm install antd moment --save
複製程式碼
安裝 babel-plugin-import 對元件進行按需載入:
npm install babel-plugin-import --save-dev
複製程式碼
在 babel.config.js
檔案中新增 antd 配置:
module.exports = (api) => {
api.cache(true);
return {
presets: [
...
],
plugins: [
...,
+ [
+ "import",
+ {
+ "libraryName": "antd",
+ "style": true
+ }
+ ],
...
]
}
複製程式碼
四、進行 React 開發
基本上需要的外掛目前都已經引入了,是時候進行開發了。
修改根目錄下的 index.js 檔案
index.js
import React from 'react';
import ReactDom from 'react-dom';
import { Provider } from 'mobx-react'
import { LocaleProvider } from 'antd';
import { HashRouter } from 'react-router-dom';
import zh_CN from 'antd/lib/locale-provider/zh_CN';
import 'moment/locale/zh-cn';
import GlobalModel from './GlobalModel';
// import App from './App';
const globalModel = new GlobalModel();
const App = () => {
return <div>開發環境配置完成</div>
}
ReactDom.render(
<Provider globalModel={ globalModel }>
<LocaleProvider locale={zh_CN}>
<HashRouter>
<App />
</HashRouter>
</LocaleProvider>
</Provider>,
document.querySelector('#root')
);
複製程式碼
執行 npm run start
命令,在瀏覽器開啟 http://localhost:8000/
,就能夠看到 開發環境配置完成 正常顯示。
此時說明我們各種外掛、庫都已經引入完成,可以正常使用了。
使用 React Route 進行頁面間路由跳轉
在 src 目錄下新建 App.js 檔案:
App.js
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from 'pages/home';
import Settings from 'pages/settings';
import Display from 'pages/display';
import NotFound from 'pages/exception'
import styles from './App.less';
export default (props) => {
return (
<div className={ styles.app }>
<Switch>
<Route path='/settings' component={ Settings } />
<Route path='/display' component={ Display } />
<Route exact path='/' component={ Home } />
<Route component={ NotFound } />
</Switch>
</div>
)
}
複製程式碼
在 src
目錄下建立 App.less
檔案,編寫 App
元件樣式
App.less
.app {
padding: 60px;
}
複製程式碼
在 pages 目錄下編寫 Home、Settings、Display、NotFound 元件
Home
元件是根路由元件,用來跳轉到Setting
介面和Display
介面Settings
元件演示瞭如何獲取和修改mobx
的全域性Model
Display
元件演示瞭如何使用 mobx 進行同步和非同步的資料處理NotFound
元件在匹配不到正確路由時展示
Home、Settings、Display 相關的程式碼我就不貼了,佔的篇幅較長,大家需要的話可以去我的 Github 上看一下或者下載下來也可以。比較方便。地址:Github
再修改一下 index.js 檔案
index.js
import React from 'react';
import ReactDom from 'react-dom';
import { Provider } from 'mobx-react'
import { LocaleProvider } from 'antd';
import { HashRouter } from 'react-router-dom';
import zh_CN from 'antd/lib/locale-provider/zh_CN';
import 'moment/locale/zh-cn';
import GlobalModel from './GlobalModel';
import App from './App';
const globalModel = new GlobalModel();
ReactDom.render(
<Provider globalModel={ globalModel }>
<LocaleProvider locale={zh_CN}>
<HashRouter>
<App />
</HashRouter>
</LocaleProvider>
</Provider>,
document.querySelector('#root')
);
複製程式碼
可以看到這裡有一個 GlobalModel
存放全域性通用資料的 Model,裡面的邏輯比較簡單,我們稍微看一下。
GlobalModel.js
import { observable, action } from 'mobx';
export default class GlobalModel {
@observable username = '小明';
@action
changeUserName = (name) => {
this.username = name;
}
}
複製程式碼
新增 fetch 工具類進行網路請求
由於我們在 Display 元件中需要進行網路請求的非同步操作,所以我們這裡引入 fetch 進行網路請求。
安裝 fetch 相關外掛:
npm install whatwg-fetch qs --save
複製程式碼
編寫網路請求工具類
在 utils
目錄下建立 request.js
檔案。
utils/request.js
import 'whatwg-fetch';
import { stringify } from 'qs';
/**
* 使用 Get 方式進行網路請求
* @param {*} url
* @param {*} data
*/
export const get = (url, data) => {
const newUrl = url + '?' + stringify(data) + (stringify(data) === '' ? '' : '&') +'_random=' + Date.now();
return fetch(newUrl, {
cache: 'no-cache',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8'
},
method: 'GET',
})
.then(response => response.json());
}
/**
* 進行 Post 方式進行網路請求
* @param {*} url
* @param {*} data
*/
export const post = (url, data) => {
return fetch(url, {
body: JSON.stringify(data),
cache: 'no-cache',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8'
},
method: 'POST',
})
.then(response => response.json()) // parses response to JSON
}
複製程式碼
至此,簡單的 React 框架搭建完成了
執行 npm run start
,編譯成功後,可以看到介面長這樣。
Home 介面:
Settings 介面:
Display 介面:
NotFound 介面:
五、進行 React 專案打包配置
先在 package.json 檔案中新增一個執行指令碼:
{
...,
"scripts": {
"start": "webpack-dev-server --config webpack/webpack.config.dev.js",
"build": "webpack --config webpack/webpack.config.prod.js"
},
...
}
複製程式碼
配置 webpack.config.prod.js 檔案
其中大部分的 module
和 plugin
還有 resolve
都與開發環境的一致。所以我們就以 webpack.config.dev.js
檔案中的配置為基礎進行說明。
- 將 mode 屬性值修改為:'production'
- 將 devtool 屬性值修改為:'hidden-source-map'
- 刪除 devServer 屬性所有的配置。
- 刪除使用的熱載入外掛:·webpack.HotModuleReplacementPlugin`,
新增 optimization 屬性進行程式碼壓縮
安裝相關外掛:
npm install uglifyjs-webpack-plugin optimize-css-assets-webpack-plugin --save-dev
複製程式碼
新增程式碼壓縮配置:
webpack.config.prod.js
...;
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
...;
module.exports = {
mode: 'production',
devtool: 'hidden-source-map',
entry: ...,
output: {...},
plugins: [...],
module: {...},
optimization: {
// 打包壓縮js/css檔案
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
compress: {
// 在UglifyJs刪除沒有用到的程式碼時不輸出警告
warnings: false,
// 刪除所有的 `console` 語句,可以相容ie瀏覽器
drop_console: true,
// 內嵌定義了但是隻用到一次的變數
collapse_vars: true,
// 提取出出現多次但是沒有定義成變數去引用的靜態值
reduce_vars: true,
},
output: {
// 最緊湊的輸出
beautify: false,
// 刪除所有的註釋
comments: false,
}
}
}),
new OptimizeCSSAssetsPlugin({})
],
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.(css|less)/,
chunks: 'all',
enforce: true,
reuseExistingChunk: true // 表示是否使用已有的 chunk,如果為 true 則表示如果當前的 chunk 包含的模組已經被抽取出去了,那麼將不會重新生成新的。
},
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2,
reuseExistingChunk: true
},
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
}
}
},
runtimeChunk: true
},
resolve: {...}
}
複製程式碼
使用 mini-css-extract-plugin 外掛提取 CSS 程式碼
安裝相關外掛:
npm install mini-css-extract-plugin --save-dev
複製程式碼
配置 mini-css-extract-plugin
外掛:
- 在
plugins
屬性中引入 - 將
module
的rules
中使用的style-loader
替換為MiniCssExtractPlugin.loader
webpack.config.prod.js
...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
...,
plugins: [
...,
new MiniCssExtractPlugin({
filename: 'public/styles/[name].[contenthash:8].css',
chunkFilename: 'public/styles/[name].[contenthash:8].chunk.css'
})
],
modules: {
rules: [
...,
{
test: /\.(css|less)$/,
exclude: /node_modules/,
use: [
{
- loader: 'style-loader'
+ loader: MiniCssExtractPlugin.loader
},
...
]
},
{
test: /\.(css|less)$/,
exclude: /node_modules/,
use: [
{
- loader: 'style-loader'
+ loader: MiniCssExtractPlugin.loader
},
...
]
},
...
]
},
...
}
複製程式碼
使用 DefinePlugin 外掛定義當前為生產環境
webpack.config.prod.js
...
module.exports = {
...,
plugins: [
...,
new webpack.DefinePlugin({
// 定義 NODE_ENV 環境變數為 production
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
],
...
}
複製程式碼
使用 clean-webpack-plugin 清理 dist 目錄
打包的過程中,由於部分檔名使用的是 hash 值,會導致每次檔案不同,因而在 dist 中生成一些多餘的檔案。所以我們可以在每次打包之前清理一下 dist 目錄。
安裝外掛:
npm install clean-webpack-plugin --save-dev
複製程式碼
使用外掛:
webpack.config.prod.js
...,
module.exports = {
...,
plugins: [
...,
new CleanWebpackPlugin()
],
...
}
複製程式碼
新增其他優化配置
- 新增 stats 配置過濾打包時出現的一些統計資訊。
- 新增 performance 配置關閉效能提示
webpack.config.prod.js
module.exports = {
...,
stats: {
modules: false,
children: false,
chunks: false,
chunkModules: false
},
performance: {
hints: false
}
}
複製程式碼
進行專案的打包釋出
打包專案
執行 npm run build
指令,控制檯打包完成之後,根目錄下多出了 dist
資料夾。
使用 Nginx 釋出專案
我這裡是用的是 Nginx
作為伺服器,釋出在本地。
Nginx
下載地址:nginx.org/en/download…。
下載完成之後,解壓完成。開啟 Nginx
目錄,可以找到一個 conf
資料夾,找到其中的 nginx.conf
檔案,修改器中的配置:
將圖中標註的
html
更換為dist
。
然後我們就可以放心的將打包生成的 dist
資料夾直接放到 Nginx
的安裝目錄下了。(此時 dist
目錄與剛才的 conf
目錄應該是同級的)。
啟動 Nginx
服務:
start nginx
複製程式碼
開啟瀏覽器,輸入
http://127.0.0.1
或者http://localhost
即可看到我們的專案已經正常的跑起來了。
Nginx 其他命令:
# 停止 Nginx 服務
nginx -s stop
# 重啟 Nginx 服務
nginx -s reload
# 退出 nginx
nginx -s quit
複製程式碼
更多 Ngnix 相關請參考:Nginx官方文件
注意:需要在 Nginx 安裝目下執行 nginx 相關命令!
六、使用 webpack-merge 引入webpack 公共配置
觀察 webpack.config.dev.js
和 webpack.config.prod.js
檔案,可以發現有大量的程式碼和配置出現了重複。所以我們可以編寫一個 webpack.common.js
檔案,將共有的配置放入其中,然後使用 webpack-merge
外掛分別引入到 webpack.config.dev.js
和 webpack.config.prod.js
檔案中使用。
外掛安裝:
npm install webpack-merge --save-dev
複製程式碼
使用:
+ const merge = require('webpack-merge');
+ const common = require('./webpack.common.js');
+ module.exports = merge(common, {
+ mode: 'production',
+ ...
+ });
複製程式碼
這裡就展示了一下用法,由於篇幅太長,三個檔案中具體的配置程式碼我就不貼了,
大家可以到 我的 GitHub 上檢視一下使用 webpack-merge
後的配置檔案。
七、本文原始碼地址
歡迎Star,謝謝各位!
文章及程式碼中如有問題,歡迎指正,謝謝!