由于現(xiàn)在的博客是使用wordpress搭建,自己得經(jīng)常修改過一些代碼,但是修改第三方源碼真的比較痛苦,于是決定計劃開始使用React + Node.js / Python開發(fā)新博客項目,最終替換當前博客代碼,方便以后博客的維護和更新,也能實現(xiàn)自我開發(fā)技術(shù),架構(gòu)設計,解決問題能力的提升,同時記錄下整個開發(fā)歷程,總結(jié),分享,希望能與讀者們一起進步。本篇介紹如何使用Webpack和Babel,Eslint,documentation.js等搭建項目開發(fā)環(huán)境和生產(chǎn)環(huán)境,也算項目的準備工作,下一期計劃介紹項目的架構(gòu)設計和技術(shù)棧選擇。
成都創(chuàng)新互聯(lián)公司專注于渭城網(wǎng)站建設服務及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供渭城營銷型網(wǎng)站建設,渭城網(wǎng)站制作、渭城網(wǎng)頁設計、渭城網(wǎng)站官網(wǎng)定制、重慶小程序開發(fā)服務,打造渭城網(wǎng)絡公司原創(chuàng)品牌,更為您提供渭城網(wǎng)站排名全網(wǎng)營銷落地服務。
npm VS Yarn
在本項目我們使用Yarn管理項目三方依賴,不過放心,Yarn和NPM不沖突,也不是要替代NPM,使用方式基本一致,只需要簡單了解以下幾點。
三方庫版本管理
npm 和 Yarn 都使用 package.json 來跟蹤項目的依賴,版本號并非一直準確,因為你可以定義版本號范圍,npm的不同更新范圍,可能導致在擁有相同 package.json 文件的機器上安裝不同版本包,這可能導致一些差異的異常和沖突。
那npm有解決方式嘛?npm中可以使用 npm shrinkwrap生成一個版本鎖文件npm-shrinkwrap.json,在 npm install 時會在讀取 package.json 前先讀取這個文件,但是當更新包版本時,版本鎖文件并不會自動更新,我們得手動再次執(zhí)行npm shrinkwrap命令更新它。
那么Yarn有什么優(yōu)勢呢?每次添加或更新安裝庫包時,Yarn 都會創(chuàng)建(或更新)yarn.lock 文件,這樣可以確保所有機器安裝相同版本包,同時支持 package.json 中定義的允許版本范圍,和npm的區(qū)別在于Yarn總會自動更新 yarn.lock,而npm需要手動更新。
并發(fā)安裝
npm通常是按順序一個一個安裝依賴,而Yarn支持并行加載安裝多個三方庫包,所有其速度和效率都更快。
離線緩存
使用Yarn管理包時,三方庫包存放在本地磁盤,下次安裝將直接使用本地文件而不是再次下載,這也從另一方面使其安裝速度優(yōu)于npm。
簡而言之就是,Yarn和npm使用方式幾乎一樣,但是其版本管理更方便,安裝速度更快,更有優(yōu)勢,但是實際上它的所有三方庫包加載地址和npm都是統(tǒng)一的。
Webpack
我們使用Webpack打包工具作為項目的自動化構(gòu)建工具,將JavaScript,CSS,圖片等資源都當作JavaScript模塊(使用Webpack loader處理轉(zhuǎn)換)進行統(tǒng)一管理,關(guān)于Webpack博主之前總結(jié)過兩篇文章,可以參考:
有了前文的鋪墊,本文就不打算展開介紹Webpack的工作原理和具體配置,而計劃從項目實踐開發(fā)和測試,打包層面思考如何更好的組織Webpack,如何使用Webpack提告項目開發(fā),打包效率。
Webpack配置文件
首先我們在根目錄下創(chuàng)建webpack.config.js
配置文件:
module.exports = function () { let env let _DEV_ = true // 開發(fā)環(huán)境 let _PROD_ = false // 生產(chǎn)環(huán)境 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 } // 根據(jù)環(huán)境參數(shù)動態(tài)決定引入對應配置文件 return require(`./webpack/${env}.conf.js`)({ ROOTPATH: __dirname, _DEV_, _PROD_ }) }
根據(jù)process.env.NODE_ENV環(huán)境參數(shù)動態(tài)決定加載對應配置文件:
我們在項目根目錄下創(chuàng)建了webpack目錄,其內(nèi)創(chuàng)建了三個配置文件:
開發(fā)環(huán)境配置
開發(fā)環(huán)境配置文件中定義了一些開發(fā)使用的構(gòu)建配置,然后引入基礎配置文件,使用webpack-merge三方庫,將開發(fā)環(huán)境配置合并至基礎配置對象,然后返回開發(fā)環(huán)境打包構(gòu)建配置對象,作為Webpack打包構(gòu)建的參數(shù):
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: [] }) }
生產(chǎn)環(huán)境配置
生產(chǎn)環(huán)境配置文件中定義了的是生產(chǎn)環(huán)境使用的構(gòu)建配置,然后也是引入基礎配置文件,使用webpack-merge三方庫,將生產(chǎn)環(huán)境配置合并至基礎配置,然后返回配置對象,作為Webpack打包構(gòu)建的參數(shù):
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 } }) ] }) }
指令
然后就是為不同環(huán)境配置可執(zhí)行指令,我們使用npm scripts方式,在package.json文件中配置執(zhí)行指令:
{ "scripts": { "start": "cross-env NODE_ENV=dev webpack-dev-server", "build": "cross-env NODE_ENV=production webpack" } }
start:開發(fā)環(huán)境運行指令,使用cross-env三方庫設置process.env.NODE_ENV為dev,并在本地開啟webpack開放服務器,方便開放;
build:生產(chǎn)環(huán)境運行指令,使用cross-env三方庫設置process.env.NODE_ENV為production,將打包輸出代碼和資源文件;
最后分別執(zhí)行yarn start和yarn build指令即可分別執(zhí)行開發(fā)和生產(chǎn)構(gòu)建打包了。
Babel
可自定義配置型的通用編譯器,需要明確指定期望babel做什么,通過安裝插件(plugins)或預設(presets,也就是一組插件)來指示 Babel 去做什么事情。
配置文件
首先需要創(chuàng)建一個配置文件,即在項目的根路徑下創(chuàng)建 .babelrc 文件。然后輸入以下內(nèi)容作為開始:
{ "presets": [], "plugins": [] }
之后就可以拓展這個配置文件以指定此項目中 Babel 的功能。
babel-preset-es2015
我們期望在項目中能使用更新潮的ES6版本語法,但由于目前還有許多JavaScript環(huán)境不能很好兼容ES6,所以需要Babel將ES6代碼編譯成ES5語法代碼,保證應用的使用范圍。
執(zhí)行如下命令,安裝 “es2015” Babel 預設:
yarn add --dev babel-preset-es2015
修改.babelrc配置文件:
{ "presets": [ "es2015" ], "plugins": [] }
babel-preset-stage-num
另外,JavaScript還有一些提案,正在推進,不久的將來也可能成為標準的一部分,所以目前將這些草案提出,內(nèi)容更新直至最終成為標準,添加進標準庫的過程劃分為 5(0-4)個階段。 根據(jù)提案的狀態(tài)和內(nèi)容,將其在各個階段更新(階段0至階段3),最終在階段 4表明該提案被標準正式采納,當然不被采納的提案不會進入階段4。
以下是4個不同階段的打包預設:
注: 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依次后推。
點此查看關(guān)于各階段預設的詳細特性內(nèi)容文檔
我們次選擇支持特性最全面的預設:
yarn add --dev babel-preset-stage-0
在.babelrc 配置文件內(nèi)添加:
{ "presets": [ "es2015", "stage-0" ], "plugins": [] }
babel-preset-react
我們的項目期望使用React開發(fā),所以需要拓展支持React/JSX語法,安裝預設:
yarn add --dev babel-preset-react
.babelrc 配置文件內(nèi)添加:
{ "presets": [ "es2015", "stage-0", "react" ], "plugins": [] }
babel-polyfill
至此,使用Babel,我們的·項目幾乎可以支持所有的ES6及ES7語法,但是對于新增的JavaScript API是無能為力的,如Symbol這種新API,并不是通過語法轉(zhuǎn)換能實現(xiàn)的,所以我們需要另外的方式解決。
業(yè)內(nèi)提出了Polyfill(填充),以添加額外代碼的方式使得當前運行環(huán)境支持不存在的原生Api ,拓展了尚處在推進階段的API的使用范圍。
yarn add babel-polyfill
此處不需要添加--dev參數(shù)。
然后在文件入口引入即可:
import "babel-polyfill";
babel-runtime
前面提到的Babel通過轉(zhuǎn)換語法以支持我們以ES6等更新的語法方式開發(fā)代碼,這時Babel會在每一個處理的文件頭部注入輔助代碼,會產(chǎn)生很多冗余,重復性的內(nèi)容,導致代碼量暴增,所以我們需要將這些輔助代碼抽取至一個統(tǒng)一環(huán)境,Babel提供的就是運行時(runtime)環(huán)境。
要實現(xiàn)Babel運行時環(huán)境,需要安裝 babel-plugin-transform-runtime 和 babel-runtime
:
yarn add --dev babel-plugin-transform-runtime babel-runtime
然后更新 .babelrc:
{ "plugins": [ "transform-runtime", ] }
按需加載(babel-plugin-import)
很多時候,我們開發(fā)業(yè)務并不需要自制UI,會選擇一些開源組件庫以快速開發(fā)實現(xiàn)產(chǎn)品,如antd,weui,material-ui等,我們可以選擇直接提前加載三方庫所有模塊,但是很多時候我們希望能實現(xiàn)按需加載,減少初始代碼包的體積,這時,我們可以在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/。
其他插件
我們還可以根據(jù)項目實際需求和愛好自定義安裝插件,更多信息查看官方插件文檔。
在這里推薦一款babel-pliugin-transform-s2015-classes插件拓展以實現(xiàn)JavaScript內(nèi)置class對象的extends繼承特性,參考文檔ES2015 classes transform。
yarn add --dev babel-plugin-transform-es2015-classes
在.babelrc文件內(nèi)添加plugins內(nèi)容:
{ "plugins": [ "transform-runtime", "transform-es2015-classes", [ "import", { "style": "css", "libraryDirectory": "", "libraryName": "material-ui" } ] ] }
語法檢測(Eslint)
為了保證代碼質(zhì)量,統(tǒng)一代碼風格是很重要的,而只靠團隊口頭約定明顯是不能盡如人意,所以通常需要在自動化構(gòu)建層面進行代碼語法檢測,有很多語法檢測工具如jslint,eslint,目前使用率最高的要數(shù)eslint了,所以我們的項目也引入eslint,首先安裝依賴:
yarn add --dev eslint
更多細節(jié)參考配置文檔,下文簡要介紹主要。
配置文件
然后在項目根目錄下建立eslint配置文件.eslintrc,內(nèi)容是一個對象:
{}
解析器(parser)
另外,ESLint 默認使用Espree作為其解析器,你可以在配置文件中指定一個不同的解析器,如babel-eslint,esprima等,我們項目使用babel-eslint:
yarn add --dev babel-eslint
在配置文件內(nèi)添加parser屬性:
{ "parser": "babel-eslint" }
eslint-plugin-babel
eslint還支持可選安裝插件,拓展eslint,如eslint-plugin-babel,該插件與babel-eslint協(xié)作,使得eslint可以更好的與babel同時工作,更多請查看參考文檔。
yarn add --dev eslint-plugin-babel
在配置文件添加聲明:
{ "plugins": [ "babel" ], }
aslant-plugin-react
eslint默認是檢測JavaScript語言語法的,而對于React/JSX這類包含其自定義語法和語法糖的框架而言,需要另外拓展安裝插件才能和eslint結(jié)合使用,所以使用eslint檢測React特定語法需要安裝eslint-plugin-react插件:
yarn add --dev eslint-plugin-react
添加配置文件:
{ "plugins": [ "babel", "react" ] }
拓展(extends)
除了自定義語法檢查規(guī)則外,我們可以使用Eslint提供的集成拓展包,使用共享的語法檢測配置對象,如eslint-config-standard和eslint-config-standard-react:
注:這里包含了上一小節(jié)提到的eslint-plugin-react是為了支持eslint-config-standard-react配置包。
然后在.eslintrc配置文件中添加拓展:
{ "extends": [ "standard", "standard-react" ] }
若不想使用這類集成語法檢測規(guī)則,可以移除配置文件中內(nèi)容并移除依賴:
語法規(guī)則(rules)
要添加語法規(guī)則,只需要聲明在rules屬性對象中,如:
{ "rules": { "strict": 0, "semi": 2, // 強制語句末尾添加符號,否則報錯 "quotes": [ 1, "single" ], } }
規(guī)則結(jié)構(gòu)
當聲明語法檢測規(guī)則時,需要設置規(guī)則 ID為以下值之一:
{ "rules": { eqeqeq: 0, // or "off" curly: 2 // or "error" } }
某些規(guī)則還可能有額外的配置選項,可以使用數(shù)組指定,如:
{ "rules": { "eqeqeq": "off", "curly": "error", "quotes": ["warn", "single"] // 開啟使用單引號,若使用雙引號將發(fā)出警告 } }
指令
要執(zhí)行語法檢測,只需要執(zhí)行./node_modules/.bin/eslint src(項目本地安裝eslint,而非全局安裝,則需要指定執(zhí)令腳本路徑),將會遍歷檢查src目錄下的所有源碼文件語法并輸出結(jié)果,當然我們最終需要將指令根據(jù)npm scripts規(guī)范插入package.json文件:
{ "scripts": { "lint": "eslint --cache --fix src" } }
使用npm scripts執(zhí)行指令時,無論項目本地安裝還是全局安裝,都可以省略指令腳本路徑,因為npm將自動匹配可用路徑。
文檔
一個優(yōu)秀的項目當然少不了文檔,文檔可以幫助其他開發(fā)者快速了解整個項目內(nèi)容及進度,也有助于bug修復時查找內(nèi)容,追蹤溯源,所以文檔是有必要的,于是通過調(diào)研發(fā)現(xiàn)了JSdoc和documentation.js幫助自動化產(chǎn)出API文檔。
documentation
和JSdoc一樣,documentation也是根據(jù)代碼注釋自動構(gòu)建出項目文檔,前提是我們的代碼注釋必須按照其規(guī)范指南,詳情參考JSdoc文檔。
我們首先安裝documentation.js:
yarn add --dev documentation
指令
然后可以執(zhí)行指令:
./node_modules/.bin/documentation build src/app.js -f md > API.md
會發(fā)現(xiàn)在根目錄輸出了API.md文件。
我們在package.json文件中配置npm scripts執(zhí)行腳本:
"scripts": { "doc": "./node_modules/.bin/documentation build src/app.js -f md > API.md" }
項目本地安裝documentation時,直接在命令行終端執(zhí)行指令時需要指定./node_modules/.bin/documentation路徑,若全局安裝則只可直接使用documentation指令。而執(zhí)行package.json中的腳步,可以直接簡寫,npm將為我們自動匹配。
點此查看項目源碼地址
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。