因爲如今的博客是使用wordpress搭建,本身得常常修改過一些代碼,可是修改第三方源碼真的比較痛苦,因而決定計劃開始使用React + Node.js / Python開發新博客項目,最終替換當前博客代碼,方便之後博客的維護和更新,也能實現自我開發技術,架構設計,解決問題能力的提高,同時記錄下整個開發歷程,總結,分享,但願能與讀者們一塊兒進步。本篇介紹如何使用Webpack和Babel,Eslint,documentation.js等搭建項目開發環境和生產環境,也算項目的準備工做,下一期計劃介紹項目的架構設計和技術棧選擇。javascript
點此查看項目源碼地址css
個人我的博客java
在本項目咱們使用Yarn管理項目三方依賴,不過放心,Yarn和NPM不衝突,也不是要替代NPM,使用方式基本一致,只須要簡單瞭解如下幾點。node
npm 和 Yarn 都使用 package.json
來跟蹤項目的依賴,版本號並不是一直準確,由於你能夠定義版本號範圍,npm的不一樣更新範圍,可能致使在擁有相同 package.json
文件的機器上安裝不一樣版本包,這可能致使一些差別的異常和衝突。react
那npm有解決方式嘛?npm中可使用 npm shrinkwrap
生成一個版本鎖文件npm-shrinkwrap.json
,在 npm install
時會在讀取 package.json
前先讀取這個文件,可是當更新包版本時,版本鎖文件並不會自動更新,咱們得手動再次執行npm shrinkwrap
命令更新它。webpack
那麼Yarn有什麼優點呢?每次添加或更新安裝庫包時,Yarn 都會建立(或更新)yarn.lock
文件,這樣能夠確保全部機器安裝相同版本包,同時支持 package.json
中定義的容許版本範圍,和npm的區別在於Yarn總會自動更新 yarn.lock
,而npm須要手動更新。git
npm一般是按順序一個一個安裝依賴,而Yarn支持並行加載安裝多個三方庫包,全部其速度和效率都更快。github
使用Yarn管理包時,三方庫包存放在本地磁盤,下次安裝將直接使用本地文件而不是再次下載,這也從另外一方面使其安裝速度優於npm。web
簡而言之就是,Yarn和npm使用方式幾乎同樣,可是其版本管理更方便,安裝速度更快,更有優點,可是實際上它的全部三方庫包加載地址和npm都是統一的。shell
咱們使用Webpack打包工具做爲項目的自動化構建工具,將JavaScript,CSS,圖片等資源都看成JavaScript模塊(使用Webpack loader處理轉換)進行統一管理,關於Webpack博主以前總結過兩篇文章,能夠參考:
有了前文的鋪墊,本文就不打算展開介紹Webpack的工做原理和具體配置,而計劃從項目實踐開發和測試,打包層面思考如何更好的組織Webpack,如何使用Webpack提告項目開發,打包效率。
首先咱們在根目錄下建立webpack.config.js
配置文件:
module.exports = function () {
let env
let _DEV_ = true // 開發環境
let _PROD_ = false // 生產環境
switch (process.env.NODE_ENV) {
case 'dev':
env = 'dev'
_DEV_ = true
_PROD_ = false
break
case 'production':
env = 'prod'
_DEV_ = false
_PROD_ = true
break
default:
env = 'dev'
_DEV_ = true
_PROD_ = false
}
// 根據環境參數動態決定引入對應配置文件
return require(`./webpack/${env}.conf.js`)({
ROOTPATH: __dirname,
_DEV_,
_PROD_
})
}
複製代碼
根據process.env.NODE_ENV
環境參數動態決定加載對應配置文件:
dev
:加載webpack/env.conf.js
配置文件;prod
:加載webpack/prod.conf.js
配置文件;咱們在項目根目錄下建立了webpack
目錄,其內建立了三個配置文件:
base.conf.js
:基礎配置文件,在開發,生產環境都須要的配置;dev.conf.js
:開發環境配置文件;prod.conf.js
:生產環境打包配置文件;開發環境配置文件中定義了一些開發使用的構建配置,而後引入基礎配置文件,使用webpack-merge
三方庫,將開發環境配置合併至基礎配置對象,而後返回開發環境打包構建配置對象,做爲Webpack打包構建的參數:
const webpackMerge = require('webpack-merge')
const PUBLICPATH = '/assets/'
const PORT = '9090'
let options = { /* ... */ }
module.exports = function (args) {
options.ROOTPATH = args.ROOTPATH
options.env = args.env
return webpackMerge(require('./base.conf')(options), {
devtool: 'source-map',
devServer: {
contentBase: path.join(args.ROOTPATH, './src'),
historyApiFallback: true,
inline: true,
hot: true,
port: PORT,
proxy: {
'*': `http://localhost:${PORT}/${PUBLICPATH}/`
}
},
plugins: []
})
}
複製代碼
生產環境配置文件中定義了的是生產環境使用的構建配置,而後也是引入基礎配置文件,使用webpack-merge
三方庫,將生產環境配置合併至基礎配置,而後返回配置對象,做爲Webpack打包構建的參數:
let options = { /* ... */}
module.exports = function (args) {
options.ROOTPATH = args.ROOTPATH
options.env = args.env
return webpackMerge(require('./base.conf')(options), {
plugins: [
new webpack.DefinePlugin({
'process.env': 'production'
}),
// 生成獨立css文件
new ExtractTextPlugin({
filename: 'css/[name].css'
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
})
}
複製代碼
而後就是爲不一樣環境配置可執行指令,咱們使用npm scripts
方式,在package.json
文件中配置執行指令:
{
"scripts": {
"start": "cross-env NODE_ENV=dev webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack"
}
}
複製代碼
start
:開發環境運行指令,使用cross-env
三方庫設置process.env.NODE_ENV
爲dev
,並在本地開啓webpack開放服務器,方便開放;build
:生產環境運行指令,使用cross-env
三方庫設置process.env.NODE_ENV
爲production
,將打包輸出代碼和資源文件;最後分別執行yarn start
和yarn build
指令便可分別執行開發和生產構建打包了。
可自定義配置型的通用編譯器,須要明確指按期望babel作什麼,經過安裝**插件(plugins)或預設(presets,也就是一組插件)**來指示 Babel 去作什麼事情。
首先須要建立一個配置文件,即在項目的根路徑下建立 .babelrc
文件。而後輸入如下內容做爲開始:
{
"presets": [],
"plugins": []
}
複製代碼
以後就能夠拓展這個配置文件以指定此項目中 Babel 的功能。
咱們指望在項目中能使用更新潮的ES6版本語法,但因爲目前還有許多JavaScript環境不能很好兼容ES6,因此須要Babel將ES6代碼編譯成ES5語法代碼,保證應用的使用範圍。
執行以下命令,安裝 "es2015" Babel 預設:
yarn add --dev babel-preset-es2015
複製代碼
修改.babelrc
配置文件:
{
"presets": [
"es2015"
],
"plugins": []
}
複製代碼
另外,JavaScript還有一些提案,正在推動,不久的未來也可能成爲標準的一部分,因此目前將這些草案提出,內容更新直至最終成爲標準,添加進標準庫的過程劃分爲 5(0-4)個階段。 根據提案的狀態和內容,將其在各個階段更新(階段0至階段3),最終在階段 4代表該提案被標準正式採納,固然不被採納的提案不會進入階段4。
如下是4個不一樣階段的打包預設:
babel-preset-stage-0
babel-preset-stage-1
babel-preset-stage-2
babel-preset-stage-3
注: stage-4 預設不存在,它其實就是上文介紹的 es2015
預設。
以上每種預設都包含緊隨的後期階段預設,同時還可能包含其餘額外特性。例如,babel-preset-stage-0
包含 babel-preset-stage-1
, babel-preset-stage-2
,babel-preset-stage-3
,而 babel-preset-stage-1
則包含 babel-preset-stage-2
,babel-preset-stage-3
依次後推。
咱們次選擇支持特性最全面的預設:
yarn add --dev babel-preset-stage-0
複製代碼
在.babelrc
配置文件內添加:
{
"presets": [
"es2015",
"stage-0"
],
"plugins": []
}
複製代碼
咱們的項目指望使用React開發,因此須要拓展支持React/JSX語法,安裝預設:
yarn add --dev babel-preset-react
複製代碼
.babelrc
配置文件內添加:
{
"presets": [
"es2015",
"stage-0",
"react"
],
"plugins": []
}
複製代碼
至此,使用Babel,咱們的·項目幾乎能夠支持全部的ES6及ES7語法,可是對於新增的JavaScript API是無能爲力的,如Symbol
這種新API,並非經過語法轉換能實現的,因此咱們須要另外的方式解決。
業內提出了Polyfill(填充),以添加額外代碼的方式使得當前運行環境支持不存在的原生Api ,拓展了尚處在推動階段的API的使用範圍。
yarn add babel-polyfill
複製代碼
此處不須要添加--dev
參數。
而後在文件入口引入便可:
import "babel-polyfill";
複製代碼
前面提到的Babel經過轉換語法以支持咱們以ES6等更新的語法方式開發代碼,這時Babel會在每個處理的文件頭部注入輔助代碼,會產生不少冗餘,重複性的內容,致使代碼量暴增,因此咱們須要將這些輔助代碼抽取至一個統一環境,Babel提供的就是運行時(runtime)環境。
要實現Babel運行時環境,須要安裝 babel-plugin-transform-runtime
和 babel-runtime
:
yarn add --dev babel-plugin-transform-runtime babel-runtime
複製代碼
而後更新 .babelrc
:
{
"plugins": [
"transform-runtime",
]
}
複製代碼
不少時候,咱們開發業務並不須要自制UI,會選擇一些開源組件庫以快速開發實現產品,如antd,weui,material-ui等,咱們能夠選擇直接提早加載三方庫全部模塊,可是不少時候咱們但願能實現按需加載,減小初始代碼包的體積,這時,咱們能夠在babel配置文件中聲明按需加載該第三方庫,固然首先得安裝插件babel-plugin-import
:
yarn add --dev babel-plugin-import
複製代碼
而後在配置文件.babelrc
中添加配置:
{
"plugins": [
"import",
{
"style": "../styles", // 加載樣式解析方式,(值爲true時,多是less/Sass),此處值設爲相對libraryName具體模塊請求路徑值
"libraryDirectory": "", // 加載包的目錄,(默認是lib,即node_modules/lib/)
"libraryName": "material-ui" // 加載三方組件庫名,固然另外須要安裝該三方庫
}
]
}
複製代碼
此時,webapck loader處理css時不能添加exclude: /node_modules/
。
咱們還能夠根據項目實際需求和愛好自定義安裝插件,更多信息查看官方插件文檔。
在這裏推薦一款babel-pliugin-transform-s2015-classes
插件拓展以實現JavaScript內置class對象的extends
繼承特性,參考文檔ES2015 classes transform。
yarn add --dev babel-plugin-transform-es2015-classes
複製代碼
在.babelrc
文件內添加plugins內容:
{
"plugins": [
"transform-runtime",
"transform-es2015-classes",
[
"import",
{
"style": "css",
"libraryDirectory": "",
"libraryName": "material-ui"
}
]
]
}
複製代碼
爲了保證代碼質量,統一代碼風格是很重要的,而只靠團隊口頭約定明顯是不能盡如人意,因此一般須要在自動化構建層面進行代碼語法檢測,有不少語法檢測工具如jslint,eslint,目前使用率最高的要數eslint了,因此咱們的項目也引入eslint,首先安裝依賴:
yarn add --dev eslint
複製代碼
更多細節參考配置文檔,下文簡要介紹主要。
而後在項目根目錄下創建eslint配置文件.eslintrc
,內容是一個對象:
{}
複製代碼
另外,ESLint 默認使用Espree做爲其解析器,你能夠在配置文件中指定一個不一樣的解析器,如babel-eslint,esprima等,咱們項目使用babel-eslint:
yarn add --dev babel-eslint
複製代碼
在配置文件內添加parser
屬性:
{
"parser": "babel-eslint"
}
複製代碼
eslint還支持可選安裝插件,拓展eslint,如eslint-plugin-babel
,該插件與babel-eslint
協做,使得eslint能夠更好的與babel同時工做,更多請查看參考文檔。
yarn add --dev eslint-plugin-babel
複製代碼
在配置文件添加聲明:
{
"plugins": [
"babel"
],
}
複製代碼
eslint默認是檢測JavaScript語言語法的,而對於React/JSX這類包含其自定義語法和語法糖的框架而言,須要另外拓展安裝插件才能和eslint結合使用,因此使用eslint檢測React特定語法須要安裝eslint-plugin-react
插件:
yarn add --dev eslint-plugin-react
複製代碼
添加配置文件:
{
"plugins": [
"babel",
"react"
]
}
複製代碼
除了自定義語法檢查規則外,咱們可使用Eslint提供的集成拓展包,使用共享的語法檢測配置對象,如eslint-config-standard
和eslint-config-standard-react
:
yarn add --dev eslint-config-standard eslint-config-standard-react eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node eslint-plugin-react
複製代碼
注:這裏包含了上一小節提到的eslint-plugin-react是爲了支持eslint-config-standard-react配置包。
而後在.eslintrc
配置文件中添加拓展:
{
"extends": [
"standard",
"standard-react"
]
}
複製代碼
若不想使用這類集成語法檢測規則,能夠移除配置文件中內容並移除依賴:
yarn remove eslint-config-standard eslint-config-standard-react eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node eslint-plugin-react
複製代碼
要添加語法規則,只須要聲明在rules
屬性對象中,如:
{
"rules": {
"strict": 0,
"semi": 2, // 強制語句末尾添加符號,不然報錯
"quotes": [
1,
"single"
],
}
}
複製代碼
當聲明語法檢測規則時,須要設置規則 ID爲如下值之一:
"off"
或 0
- 關閉規則"warn"
或 1
- 開啓規則,使用警告級別的錯誤:warn
(不會致使程序退出)"error"
或 2
- 開啓規則,使用錯誤級別的錯誤:error
(當被觸發的時候,程序會退出){
"rules": {
eqeqeq: 0, // or "off"
curly: 2 // or "error"
}
}
複製代碼
某些規則還可能有額外的配置選項,可使用數組指定,如:
{
"rules": {
"eqeqeq": "off",
"curly": "error",
"quotes": ["warn", "single"] // 開啓使用單引號,若使用雙引號將發出警告
}
}
複製代碼
要執行語法檢測,只須要執行./node_modules/.bin/eslint src
(項目本地安裝eslint,而非全局安裝,則須要指定執令腳本路徑),將會遍歷檢查src
目錄下的全部源碼文件語法並輸出結果,固然咱們最終須要將指令根據npm scripts
規範插入package.json
文件:
{
"scripts": {
"lint": "eslint --cache --fix src"
}
}
複製代碼
使用npm scripts執行指令時,不管項目本地安裝仍是全局安裝,均可以省略指令腳本路徑,由於npm將自動匹配可用路徑。
一個優秀的項目固然少不了文檔,文檔能夠幫助其餘開發者快速瞭解整個項目內容及進度,也有助於bug修復時查找內容,追蹤溯源,因此文檔是有必要的,因而經過調研發現了JSdoc和documentation.js幫助自動化產出API文檔。
和JSdoc同樣,documentation也是根據代碼註釋自動構建出項目文檔,前提是咱們的代碼註釋必須按照其規範指南,詳情參考JSdoc文檔。
咱們首先安裝documentation.js:
yarn add --dev documentation
複製代碼
而後能夠執行指令:
./node_modules/.bin/documentation build src/app.js -f md > API.md
複製代碼
會發如今根目錄輸出了API.md文件。
咱們在package.json文件中配置npm scripts
執行腳本:
"scripts": {
"doc": "./node_modules/.bin/documentation build src/app.js -f md > API.md"
}
複製代碼
項目本地安裝documentation時,直接在命令行終端執行指令時須要指定./node_modules/.bin/documentation
路徑,若全局安裝則只可直接使用documentation
指令。而執行package.json中的腳步,能夠直接簡寫,npm將爲咱們自動匹配。