因为如今的博客是使用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将为咱们自动匹配。