代碼地址 github.com/Maricaya/ad… , 有幫助請 star ~css
剛接觸 react 的時候,你們都是經過 create-react-app 等腳手架來快速建立應用。當基本配置知足不了咱們的特殊需求時(好比使用 sass),咱們會修改 eject 出來的 webpack 配置文件。html
面對各類配置項一臉懵逼,不知道怎麼快速修改。其實,學習項目搭建與配置沒有什麼技巧,都是經驗(套路)。前端
這篇文章會介紹使用 webpack 手動搭建一個 react 項目的套路,來看看個人踩坑經歷吧。node
npm init -y
複製代碼
這一步建立 package.jsonreact
打開 webpack 官網,找到安裝命令。linux
yarn add webpack webpack-cli typescript --dev
yarn add react react-dom
yarn add @types/react @types/react-dom --dev
複製代碼
在這個文件中寫入幾行 TypeScript 代碼。webpack
console.log(123);
複製代碼
index.tsx 在瀏覽器中是不能運行的,須要 webpack 幫咱們打包成瀏覽器可執行的 index.js。git
在根目錄新建 webpack.config.js。程序員
如下配置都寫在 module.export 對象內部。github
module.export = {}
複製代碼
mode 是 webpack 4 中新增長的選項, 有兩個可選值:production(生產環境)和 development(開發環境)。 mode 不可省略。 咱們先配置成開發環境,後面有須要再修改。
mode: 'development'
複製代碼
打包的入口文件。
entry: {
<key>: <value> } 複製代碼
在這裏只介紹對象形式,是由於這個是最完整的entry配置,其餘形式只是它的簡化而已。
對象中的每一對屬性對,都表明着一個入口文件。所以多頁面配置時,確定是這種形式的 entry。
key 能夠是字符串變量,對應輸出文件的名稱;也能夠是路徑,好比 'a/b/c',對應着文件的輸出路徑。 詳細解釋能夠看這篇文章。
entry: {
index: './lib/index.tsx' // ./ 當前目錄下
}
複製代碼
webpack在啓動後會從配置的入口模塊觸發找出全部依賴的模塊, resolve 配置 webpack 如何尋找模塊對應的文件。
在導入語句沒帶文件後綴時,webpack 會自動帶上後綴去嘗試訪問文件是否存在。 resolve.extensions 用於配置在嘗試過程當中用到的後綴列表。
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
}
複製代碼
接下來配置解釋 tsx 的 loader。那麼問題來了,怎麼知道哪些是最合適的 loader?
答案是沒有標準 loader,只能是一個一個試。
把網上能找到的配置方式所有試一遍以後,我找到一個我認爲最好的方式 awesome-typescript-loader
。
安裝
yarn add awesome-typescript-loader --dev
複製代碼
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader'
}
]
}
複製代碼
再配置翻譯 scss 的模塊,須要使用三個 loader,style-loader, css-loader,sass-loader
yarn add --dev style-loader css-loader sass-loader
複製代碼
能夠看出 webpack 中 loader 的原則,一個loader只作一件事情
<style>css</style>
{
test: /\.s([ac])ss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
複製代碼
配置完了輸入、中間 loader,接下來咱們來配置輸出 output。
path 輸出地址 我原本覺得這裏能夠直接寫絕對路徑__dirname + './dist'
,後來發如今 windows 上會報錯。 由於在不一樣的操做系統上,路徑表示方法不同。
__dirname + '\\dist'
,__dirname + './dist'
。因此,咱們直接使用 node.js 提供的方法 path.resolve(__dirname, 'dist')
, 這個 API 會根據操做系統的類型將兩個目錄鏈接起來。
library: 'adorable-react'
開發 npm 包的時候會用到這個命令,library 是指定用戶使用require時的模塊名。 這個模塊在使用時,命令是 require("adorable-react")
。
libraryTarget 表示庫的輸出格式是什麼,輸出模塊規範。有這麼幾種選擇 umd、amd、commonjs2。
通常都選 'umd',一種在全部模塊定義下均可運行的方案。
下面問題來了,umd 究竟是什麼呢?
要知道 umd 是什麼,咱們須要先了解下前端打包的歷史。
前端最開始是沒有包管理系統的,全部的js代碼都經過 script 標籤一個一個加載。 這個階段 js 包內重名的全局變量會互相影響。這時就須要打包工具,把變量做用域限制在局部。
前端程序員提出了 AMD 打包方案,Node.js 社區也提出了另外一套打包規則 commonJS。
define (function () {
// 這裏是咱們的變量
var a = 1 ...
})
複製代碼
這個標準叫作 amd 異步模塊定義。
var a = 1 // 只在當前文件有效
module.exports = { ... }
複製代碼
咱們正在寫的 webpack.config.js 也遵循這個規範。
commonJS 只在 Node.js 中使用,AMD 只在瀏覽器中使用。 致使你在使用時,必須區分代碼是運行在客戶端仍是服務端。
這時,有人發明了一套統一的規則 UMD 統一模塊定義。 UMD 會判斷當前運行環境是什麼,根據運行環境選擇使用 commonJS 或者 AMD。
因此在這裏,咱們選擇最完整的 UMD。
最後,完整的 output 代碼以下:
const path = require('path')
// mo
output: {
path: path.resolve(__dirname, 'dist/lib'),
- library: 'adorable-react',
libraryTarget: 'umd'
}
複製代碼
在根目錄下建立 tsconfig.json,它是 TypeScript 的配置文件。
主要包含兩塊內容:
咱們這篇文章主要講 webpack 4.0 的配置,ts 的配置文件先略過,能夠直接拷貝個人倉庫裏 tsconfig.json 文件。
配置完這些基本規則以後,咱們能夠嘗試用 npx webpack
打包啦。
打包後的文件是這樣的:
根目錄/dist/lib/index.js
— 這是 index.tsx 翻譯以後的文件
根目錄/lib/index.d.ts
— 包含了聲明的全部類型
index.d.ts 放置的目錄不對,生成的 *.d.ts 類型文件都應該放入dist目錄中。
一頓搜索後,我在 tsconfig.json "compilerOptions"
中配置 "outDir": "dist"
。
再次打包,全部文件都放進了 dist 目錄,第一次用 webpack 打包就完成啦。
目前 webpack 就作了一件事,把 ts、tsx 翻譯成 js。
接下來咱們安裝 webpack-dev-server,讓代碼可以自動編譯,實現熱更新。
yarn add webpack-dev-server --dev
npx webpack-dev-server
複製代碼
此時,訪問 http://localhost:8080/index.js 咱們能夠看到編譯後的文件。
隨意改動 lib/index.tsx
中的文件,http://localhost:8080/index.js 會自動更新。
那麼問題來了,webpack-dev-server 爲何編譯這麼快?什麼是熱更新?
整個的過程咱們能夠簡化一下,webpack-dev-server 會啓動一個小型服務器(稱爲 Bundle Server)。
Bundle Server就是一個服務器,會執行這些編譯後的文件,讓瀏覽器能夠訪問到。
webpack 打包好的文件 index.js 會傳輸給 Bundle Server,放在內存中,
等用戶訪問 index.tsx 時,服務器直接從內存中拋出index.js,因此編譯很快。
在應用程序的開發環境,方便開發人員在不刷新頁面的狀況下,就能修改代碼, 而且直觀地在頁面上看到變化的機制。
到目前爲止,我尚未 html 文件,在根目錄新建 html 入口文件 index.html。
下面問題來了,引入 js 的文件路徑是什麼?
只要 entry 下的文件名稱修改,咱們就須要手動修改 js 的路徑。那爲何不自動生成路徑呢?
安裝插件 html-webpack-plugin
,根目錄建立 index.html 文件,把 webpack 打包後的靜態文件自動插入到 html 中。
yarn add --dev html-webpack-plugin
複製代碼
webpack.config.js 配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
title: "adorable-react", // 頁面 title
template: "index.html"
})
],
複製代碼
把 index.tsx 的 ReactDom 掛載到 index.html 上。 index.tsx 中:
const div = document.createElement('div');
div.innerText = 'div';
document.body.appendChild(div);
複製代碼
若是咱們想引用一個庫,可是又不想讓webpack打包, 能夠經過配置 externals 實現。
這個功能主要用在,建立一個 npm 庫的時候。
好比:咱們開發了一個 React 的組件庫,裏面引用了 react 和 react-dom。 可是咱們不必把 react 和 react-dom 打包起來,由於用戶會在使用時會本身下載。
那麼咱們就能夠 externals 的方式,將 react/react-dom 從咱們的源代碼中排出去。
externals: {
// 配置如何引入
react: {
// 運行在 Node.js 環境中,import * as React from 'react' 等價於 const react = require('react')
commonjs: 'react',
commonjs2: 'react',
// 使用require.js等加載,等價於 define(["react"], factory);
amd: 'react',
//在瀏覽器中使用,須要提供一個全局的變量'React',等價於 var React = (window.React) or (React);
root: 'React'
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'react-dom',
root: 'ReactDom'
}
}
複製代碼
看到這裏,你已經完成了 webpack 全部基本配置!給本身鼓鼓掌吧!
不過目前 develop 模式和 production 模式都寫在一塊兒,難道每次打包都須要手動修改嗎?
別急,webpack 爲咱們提供了自動切換方式。
將 webpack 文件分爲 develop 模式和 production 模式,公共部分寫入 webpack.config.js。
develop 寫入 webpack.config.prod.js,production 寫入 webpack.config.dev.js。
完整寫法能夠點擊連接查看,這裏這給出核心代碼: webpack.config.prod.js
const base = require('./webpack.config')
// 使用 Object.assign
module.exports = Object.assign({}, base,{
mode: 'production'
})
複製代碼
咱們在 package.json scripts 中配置好命令,直接使用 yarn xxx
就能夠運行項目。
直接看最後的命令:
{
"script": {
"start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js"
}
}
複製代碼
開發模式命令 webpack-dev-server
,webpack 的配置是 webpack.config.dev.js
。 生產模式命令 webpack
,webpack 的配置是 webpack.config.prod.js
。
NODE_ENV=development
是咱們寫入的環境變量。
你可能也有這個疑問,webpack.dev.config.js 中不是有 mode 嗎? 爲何要手動寫入環境變量?
由於 webpack 處理的這個入口腳本文件及其引用的腳本文件都沒法訪問 webpack.dev.config.js 的屬性, 因此手動寫入環境變量,讓全部文件能夠訪問到 process.env.NODE_ENV。
cross-env 插件的做用是:保證環境變量在各個平臺都能添加成功。(在 unix、windows 上環境變量寫法不同)
安裝方式
yarn add --dev cross-env
複製代碼
引入 react 社區最流行的測試框架 jest,官網
測試配置不是重點,你們能夠直接看倉庫
這裏簡單說下配置:
yarn add --dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
yarn add --dev ts-jest
複製代碼
建立 .babelrc
{ "presets": ["react-app"] }
複製代碼
配置 scripts test
"test": "cross-env NODE_ENV=test jest --config=jest.config.js --runInBand"
複製代碼
配置 Enzyme Enzyme 是用於 React 的 JavaScript 測試實用程序,能夠更輕鬆地測試 React 組件。
yarn add --dev enzyme enzyme-adapter-react-16
複製代碼
建立 test 文件夾,寫入配置,這裏不贅述了,有興趣直接看源碼吧~
終於完成了項目搭建,最後來看看每一個目錄的做用吧!
如今每一個文件的功能咱們都很是清楚,出了問題,咱們也知道應該在哪裏修改。
.
├── .babelrc // babel 配置
├── README.md
├── index.html // 首頁
├── jest.config.js // jest 配置
├── dist // 最終代碼
├── lib // 源代碼
│ ├── __tests__
│ │ └── index.unit.tsx
│ ├── index.scss
│ └── index.tsx
├── package.json
├── test // test 配置
│ ├── __mocks__
│ │ ├── file-mock.js
│ │ └── object-mock.js
│ └── setupTests.js
├── tsconfig.json // ts 配置
├── tsconfig.test.json // ts 測試配置
├── tslint.json // 代碼檢測配置
├── webpack.config.dev.js // webpack 配置
├── webpack.config.js
├── webpack.config.prod.js
├── webpack.config.wheel.js
└── yarn.lock
複製代碼
恭喜你完成了項目搭建,接下來咱們能夠愉快地 coding 了!