apollo-build
apollo-build 是(shì)一(yī / yì /yí)個(gè)構建工具,提供 server
、 build
、buildDll
和(hé / huò) test
四個(gè)命令,分别用于(yú)本地(dì / de)調試、構建、打包 dll 和(hé / huò)測試,并且提供了(le/liǎo)特别易用的(de) mock 功能。命令行體驗和(hé / huò) create-react-app 一(yī / yì /yí)緻,配置略有不(bù)同,比如默認開啓 css modules,然後還提供了(le/liǎo) [JSON 格式的(de)配置方式]。
快速開始
首先,我們會幫您搭建 npm 私有倉庫。
安裝
# --registry 爲(wéi / wèi) npm 私有倉庫的(de)地(dì / de)址
$ npm i apollo-build -g --registry=http://xxx.x.x.x
使用
本地(dì / de)開發
$ apollo-build server
打包發布
$ apollo-build build
打包 dll 靜态文件
$ apollo-build buildDll
測試,默認會跑 ./test
目錄下的(de)所有文件
$ apollo-build test
特性
- HMR (熱替換)
CSS 在(zài)開發模式下會走 style-loader (被内嵌在(zài) JavaScript 文件中),所以(yǐ)隻要(yào / yāo)保證 JavaScript 的(de)熱更新,即可實現 CSS 的(de)熱更新。
如果大(dà)家使用 apollo ,配上(shàng) babel-plugin-dva-hmr 即可實現 routes 和(hé / huò) components 以(yǐ)及相關 CSS 修改的(de)熱更新,其他(tā)修改會自動刷新頁面。
"env": {
"development": {
"extraBabelPlugins": ["dva-hmr"]
}
}
- Mock
server 支持 mock 功能,默認讀取根目錄下的(de).roadhogrc.mock.js文件
比如:
export default {
// 支持值爲(wéi / wèi) Object 和(hé / huò) Array
'GET /api/users': { users: [1,2] },
// GET POST 可省略
'/api/users/1': { id: 1 },
// 支持自定義函數,API 參考 express@4
'POST /api/users/create': (req, res) => { res.end('OK'); },
// Forward 到(dào)另一(yī / yì /yí)個(gè)服務器
'GET /assets/*': 'https://assets.online/',
// Forward 到(dào)另一(yī / yì /yí)個(gè)服務器,并指定子(zǐ)路徑
// 請求 /someDir/0.0.50/index.css 會被代理到(dào) https://g.alicdn.com/tb-page/taobao-home, 實際返回 https://g.alicdn.com/tb-page/taobao-home/0.0.50/index.css
'GET /someDir/(.*)': 'https://g.alicdn.com/tb-page/taobao-home',
};
- 智能重啓
配置文件修改的(de)修改會觸發 server 的(de)自動重啓,會觸發重啓的(de)文件有:
.roadhogrc
.roadhogrc.js
.roadhogrc.mock.js
- theme 配置指定的(de)文件
配置
關于(yú)配置的(de)一(yī / yì /yí)些基本概念:
- 配置存于(yú)
.roadhogrc
文件中(如果你不(bù)喜歡 JSON 配置,可以(yǐ)用.roadhogrc.js
以(yǐ) JS 的(de)方式編寫,支持 ES6) - 格式爲(wéi / wèi)
JSON
,允許注釋 - 支持通過
webpack.config.js
以(yǐ)編碼的(de)方式進行配置,但不(bù)推薦,升級可能會引起兼容問題。使用時(shí)會給予警告。(webpack.config.js
本身的(de)編寫支持 ES6,會通過 babal-register 做一(yī / yì /yí)層轉換。)
/**
* webpack.config.js 例子(zǐ)
* @param webpackConfig webpack配置文件
* @param env process env
* @param webpack webpack對象,用于(yú)部分插件配置
* @param args 命令行參數對象
* @returns {*}
*/
module.exports = function (webpackConfig, env, webpack, args) {
//覆蓋默認的(de)webpackConfig
return webpackConfig
}
默認配置:
{
"entry": "src/index.js",
"disableCSSModules": false,
"cssModulesExclude": [],
"publicPath": "/",
"outputPath": "./dist",
"extraBabelPlugins": [],
"extraBabelPresets": [],
"extraPostCSSPlugins": [],
"sass": false,
"hash": true,
"autoprefixer": null,
"proxy": null,
"externals": null,
"library": null,
"libraryTarget": "var",
"define": null,
"env": null,
"theme": null,
"templatePath" : null,
"commonChunks": null,
"publicFilePath": "public"
}
entry
指定 webpack 入口文件,支持對象、字符串、 glob 格式以(yǐ)及數組格式
如果你的(de)項目是(shì)單入口類型,直接使用字符串定位路徑到(dào)入口文件即可
如果你的(de)項目是(shì)多入口類型,并希望按照模塊目錄來(lái)輸出(chū)類似src/project1/index.js
和(hé / huò) src/project2/index.js
的(de)文件作爲(wéi / wèi)入口。可以(yǐ)這(zhè)樣配:
"entry": {
"project1/index": "./src/project1/index.js",
"project2/index": "./src/project2/index.js",
},
這(zhè)樣的(de)最終build打包的(de)輸出(chū)會是(shì):
/dist
-project1
-index.hash.js
-project2
-index.hash.js
- 注意需要(yào / yāo)結合 templatePath 的(de)多入口配置和(hé / huò)對應多入口模闆一(yī / yì /yí)起使用比較好,否則無法正确自動生成 html 入口文件,需要(yào / yāo)手工去更新 html 入口文件
- 注意 static 靜态資源的(de)引入相對路徑會因爲(wéi / wèi)多入口打包路徑的(de)不(bù)同而(ér)變化
- 多入口具體使用可以(yǐ)參考下面多入口的(de)使用說(shuō)明
disableCSSModules
禁用 CSS Modules。最好别關,熟悉并使用他(tā)後,你會發現寫樣式簡單了(le/liǎo)很多。
cssModulesExclude
支持 CSSModules 混用,通過 cssModulesExclude 可指定不(bù)需要(yào / yāo)走 CSSModules 的(de)文件列表。
"cssModulesExclude": [
'./src/a.css',
'./src/b.less',
]
hash
使用 hash 文件名。
"hash": true
publicPath
配置生産環境的(de) publicPath,開發環境下永遠爲(wéi / wèi) /
。
outputPath
配置輸出(chū)路徑,默認是(shì) ./dist
。
publicFilePath
配置 build 和(hé / huò) server 模式下要(yào / yāo)拷貝到(dào) outputPath 根目錄下的(de)文件路徑,默認是(shì) public
.
extraBabelPlugins
配置額外的(de) babel plugin。babel plugin 隻能添加,不(bù)允許覆蓋和(hé / huò)删除。
比如,同時(shí)使用 antd, dva 時(shí),通常需要(yào / yāo)這(zhè)麽配:
"extraBabelPlugins": [
"transform-runtime",
"dva-hmr",
["import", { "libraryName": "antd", "libraryDirectory": "lib", "style": "css" }]
]
同時(shí)安裝相關依賴:
$ npm i babel-plugin-transform-runtime babel-plugin-import babel-plugin-dva-hmr --save-dev
$ npm i babel-runtime --save
注意:這(zhè)麽配還有個(gè)問題,dva-hmr
是(shì)開發環境的(de)插件,如果 build 時(shí)也(yě)用上(shàng)就(jiù)會打出(chū)冗餘代碼。解決方案詳見 #env。
extraBabelPresets
配置額外的(de) babel preset
比如:
"extraBabelPresets": ["stage-1"]
同時(shí)安裝相關依賴:
$ npm i babel-preset-stage-1 --save-dev
extraPostCSSPlugins
配置額外的(de) postcss 插件。
注意:由于(yú) postcss 的(de)插件是(shì)以(yǐ)函數的(de)方式進行配置的(de),所以(yǐ)這(zhè)個(gè)配置隻能在(zài) .roadhogrc.js
裏使用。
比如:
extraPostCSSPlugins: [
pxtorem({
rootValue: 100,
propWhiteList: [],
}),
],
autoprefixer
配置 autoprefixer 參數,詳見 autoprefixer 和(hé / huò) browserslist。
比如,如果是(shì)做移動端的(de)開發,可以(yǐ)配成:
"autoprefixer": {
"overrideBrowserslist": [
"iOS >= 8", "Android >= 4"
]
}
sass
支持 sass,值爲(wéi / wèi) node-sass 的(de)配置參數。
注意:開啓 sass 支持需在(zài)項目代碼中安裝 node-sass 和(hé / huò) sass-loader 兩個(gè)依賴。
因爲(wéi / wèi)安裝 node-sass 需要(yào / yāo)下載 github 上(shàng)面的(de)一(yī / yì /yí)些庫,因此容易失敗,如果失敗可以(yǐ)查看下面的(de)鏈接 node sass 安裝失敗解決方法
proxy
配置代理,詳見 webpack-dev-server#proxy。
如果要(yào / yāo)代理請求到(dào)其他(tā)服務器,可以(yǐ)這(zhè)樣配:
"proxy": {
"/api": {
"target": "http://jsonplaceholder.typicode.com/",
"changeOrigin": true,
"pathRewrite": { "^/api" : "" }
}
}
然後訪問 /api/users
就(jiù)能訪問到(dào) http://jsonplaceholder.typicode.com/users 的(de)數據。
如果要(yào / yāo)做數據 mock,可以(yǐ)考慮和(hé / huò) json-server 結合使用,把 /api
代理到(dào) json-server 啓動的(de)端口。
externals
配置 webpack 的(de) externals 屬性。
library
配置 webpack 的(de) library 屬性。
libraryTarget
配置 webpack 的(de) libraryTarget 屬性。
define
配置 webpack 的(de) DefinePlugin 插件,define 的(de)值會自動做 JSON.stringify
處理。
env
針對特定的(de)環境進行配置。server 的(de)環境變量是(shì) development
,build 的(de)環境變量是(shì) production
。
比如:
"extraBabelPlugins": ["transform-runtime"],
"env": {
"development": {
"extraBabelPlugins": ["dva-hmr"]
}
}
這(zhè)樣,開發環境下的(de) extraBabelPlugins 是(shì) ["transform-runtime", "dva-hmr"]
,而(ér)生産環境下是(shì) ["transform-runtime"]
。
theme
配置主題,實際上(shàng)是(shì)配 less 的(de) modifyVars
。支持 Object 和(hé / huò)文件路徑兩種方式的(de)配置。
比如:
"theme": {
"@primary-color": "#1DA57A"
}
或者,
"theme": "./node_modules/abc/theme-config.js"
svgSpriteLoaderDirs
配置一(yī / yì /yí)個(gè)路徑數組, 該路徑下的(de) svg 文件會全部交給 svg-sprite-loader 處理
// npm i antd-mobile -S
const path = require('path');
const svgSpriteDirs = [
require.resolve('antd-mobile').replace(/warn\.js$/, ''), // antd-mobile 内置svg
path.resolve(__dirname, 'src/my-project-svg-foler'), // 業務代碼本地(dì / de)私有 svg 存放目錄
];
export default {
// ...
svgSpriteLoaderDirs: svgSpriteDirs,
//...
}
templatePath 支持輸入是(shì)字符串或者是(shì)對象。 對于(yú)普通的(de)單頁應用,直接傳入字符串指定模闆路徑即可。 對于(yú)多入口應用,需要(yào / yāo)傳入類似下面的(de)對象:
"templatePath": [{
template: "src/project1/index.ejs",
filename: 'project1/index.htm',
inject: false,
chunks: ['project1/index'],
},
{
template: "src/project2/index.ejs",
filename: 'project2/index.htm',
inject: false,
chunks: ['project2/index'],
}],
參數信息可以(yǐ)參考 html-webpack-template
- 注意多入口應用的(de) template 一(yī / yì /yí)般需要(yào / yāo)關閉默認的(de) inject, 需要(yào / yāo)使用定制化的(de)模闆來(lái)保證 chunks 可以(yǐ)正确插入,多入口具體使用可以(yǐ)參考下面多入口的(de)使用說(shuō)明
- 注意 static 靜态資源的(de)引入相對路徑會因爲(wéi / wèi)打包路徑的(de)不(bù)同而(ér)變化
commonChunks
傳入數組,用來(lái)指定把相應的(de)包和(hé / huò)對應依賴抽取成單獨的(de)文件。
- name 字符串 代表 chunk名,也(yě)對應最後生成的(de)文件名。
- chunks 數組 代表需要(yào / yāo)抽取的(de)包名
如下配置,會從 appllo 和(hé / huò) react 依賴中生成 stable.[hash:8].js 和(hé / huò) react.[hash:8].js
"commonChunks": [{
"name": "stable",
"chunks": ["apollo"]
}, {
"name" : "react",
"chunks": ["react"]
}]
dllPlugin 配置是(shì)否需要(yào / yāo)使用 webpack dll plugin 。默認會把 node_modules 裏面的(de)引用庫到(dào) node_modules/roadhog-dlls 。可以(yǐ)使用 include 來(lái) 包含更多的(de)庫,庫的(de)引用路徑爲(wéi / wèi) app 當前路徑以(yǐ)及 node_modules , 使用 exclude 來(lái)去掉包含的(de)庫。 注意:庫的(de) package.json 裏面沒有包含有效入口的(de)庫以(yǐ)及 css 庫無法引入到(dào) dll中,例如下面的(de)例子(zǐ),exclude 的(de)庫是(shì)無法編成 dll 的(de)。
"dllPlugin": {
include:[],
exclude:['babel-runtime','apollo-component-mobile','normalize.css']
},
環境變量
環境變量可配置一(yī / yì /yí)些參數,包括:
PORT
,端口号,默認 8000HOST
,默認 localhostHTTPS
,是(shì)否開啓 https,默認關閉BROWSER
,設爲(wéi / wèi) none 時(shí)不(bù)自動打開浏覽器CLEAR_CONSOLE
,設爲(wéi / wèi) none 時(shí)清屏
比如,使用 3000 端口開啓服務器可以(yǐ)這(zhè)樣:
// OS X, Linux
$ PORT=3000 apollo-build server
// Windows (cmd.exe)
$ set PORT=3000&&apollo-build server
命令行參數
apollo-build server
$ apollo-build server -h
Usage: apollo-build server [options]
Options:
-h 顯示幫助 [boolean]
--ie8 支持 IE8 [boolean] [default: false]
apollo-build build
$ apollo-build build -h
Usage: apollo-build build [options]
Options:
--debug 不(bù)壓縮構建 [boolean] [default: false]
--watch, -w 監聽文件變化并重構建 [boolean] [default: false]
--output-path, -o 指定輸出(chū)路徑 [string] [default: null]
--analyze 可視化分析 webpack bundle [boolean] [default: false]
--ie8 支持 IE8 [boolean] [default: false]
--sourcemap 構建時(shí)生成 sourcemap [boolean] [default: false]
--dropconsole 構建時(shí)移除 console 日志 [boolean] [default: false]
-h 顯示幫助 [boolean]
apollo-build buildDll
把通用庫打成 dll,再使用 apollo-build server 的(de)時(shí)候能夠減少編譯時(shí)間,具體詳情可以(yǐ)參考 webpack dll plugin
$ apollo-build buildDll -h
Usage: apollo-build buildDll [options]
Options:
-h 顯示幫助 [boolean]
apollo-build test
$ apollo-build test -h
Usage: apollo-build test [options] [mocha-options]
Options:
--coverage 輸出(chū)覆蓋率 [boolean] [default: false]
-h 顯示幫助 [boolean]
使用 public
目錄
我們約定默認在(zài) public
目錄下的(de)文件會在(zài) server 和(hé / huò) build 時(shí)被自動 copy 到(dào)輸出(chū)目錄(默認是(shì) ./dist
)下。所以(yǐ)可以(yǐ)在(zài)這(zhè)裏存放 favicon, iconfont, html, html 裏引用的(de)图片等。
注意約定 public/opt 下面的(de) js類型文件會在(zài) apollo build 的(de)時(shí)候被壓縮。
FAQ
那麽爲(wéi / wèi)什麽提供 JSON 級别的(de)約定型配置,而(ér)非類似 webpack.config.js 的(de)編碼型配置?
首先是(shì) JSON 的(de)方式比較簡單,true
/false
或是(shì)一(yī / yì /yí)些簡單的(de)字符串就(jiù)可完成配置;另外,JSON 方式能有效控制使用場景,而(ér)編程式的(de)非常不(bù)可控,roadhog 的(de)一(yī / yì /yí)個(gè)簡單改動都可能導緻之(zhī)前的(de)配置不(bù)可用。
報 Unexpected token
錯誤,類似下面這(zhè)樣
Error in ./index.js
Module parse failed: /Users/chencheng/Documents/Work/Misc/dva-cli/boilerplates/demo/index.js Unexpected token (15:23)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (15:23)
@ multi index
把源碼放到(dào) src 目錄下,因爲(wéi / wèi)非 src 目錄下的(de)文件不(bù)會走 babel 編譯。
Windows/Ubuntu 下每次啓動後打開新 Tab 比較煩
# Ubuntu
$ BROWSER=none apollo-build server
# Windows
$ set BROWSER=none&&apollo-build server
多入口的(de)使用說(shuō)明
- 多入口核心是(shì)需要(yào / yāo)在(zài) entry 裏面使用對象,指定多個(gè)入口地(dì / de)址,一(yī / yì /yí)般都需要(yào / yāo) templatePath 配合來(lái)配置, 才能自動化注入正确生成到(dào)chunk到(dào)不(bù)同的(de)入口 html。同時(shí)多入口一(yī / yì /yí)般有抽取公用 chunk的(de) 需求,這(zhè)時(shí)候可以(yǐ)結合 commonChunk 來(lái)進行公共模塊的(de)抽取
- 注意 static 靜态資源的(de)引入相對路徑會因爲(wéi / wèi)多入口打包路徑的(de)不(bù)同而(ér)變化
- 多入口 Demo 項目可以(yǐ)參考apollo-build-multi-entry-demo
注意
當前版本的(de) apollo build 基于(yú)webpack^4.29.6
通過webpack.config.js修改webpack配置時(shí),請按照webpack@4的(de)方式配置
在(zài)配置 extraBabelPlugins 和(hé / huò) extraBabelPresets 時(shí),使用 Babel@6 版本的(de) plugin 和(hé / huò) preset
roadhog is not defined 的(de)錯誤是(shì)配置裏面配置了(le/liǎo)dll , 但是(shì)沒有運行apollo-build buildDll
css 壓縮
目前使用OptimizeCssAssetsPlugin來(lái)壓縮css, 沒有使用css-loader和(hé / huò)post-css來(lái)壓縮