該項目會以 React 全家桶 (會使用 16.8 最新 API 及 hooks) 以及 mobx 數據流方案爲基礎打造的一款高質量的移動端音樂類 WebApp 。 涉及的技術棧主要有:javascript
- react v16.8 全家桶 (react,react-router) : 用於構建用戶界面的 MVVM 框架
- mobx 前端數據流方案
- immutable: Facebook 歷時三年開發出的進行持久性數據結構處理的庫
- axios: 用來請求後端 api 的數據。
這是系列文章,爲了你們閱讀方便,我會列舉出系列文章的目錄。css
!本項目的倉庫爲happy-music。其中master分支爲最新的全部代碼,每次更新文章都會對應一個tag,tag是自增的,本篇文章對應的代碼tag爲v1.0.3。html
本篇主要講述webpack 項目初始化配置。若是是webpack的大拿,就能夠跳過這片文章了。這篇文章的主要內容有:前端
囉裏八嗦的終於來到了正文部分了!!!java
先給項目取一個響亮的名字,奉行快樂優先原則,就叫happy-music吧。node
webpack4配置不細說,具體的直接看官網就能夠了,這裏只列出一些重點。建立以下文件結構,其中webpack.common.js用於抽離公用配置,webpack.dev.js和webpack.prod.js分別對應開發和線上環境。react
yarn add -D webpack webpack-cli webpack-merge
複製代碼
webpack的做用都在官網這張圖上,就是將各類模塊進行處理和打包。而loader就是處理webpack中的模塊。jquery
咱們項目主要使用react和ts編寫,babel7以後也支持對ts轉義了,以前須要使用ts-loader。 安裝以下依賴:webpack
yarn add @babel/core @babel/preset-env @babel/preset-typescript @babel/preset-react babel-loader -D
複製代碼
在項目根目錄建立.babelrc文件:ios
{
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"]
}
複製代碼
根目錄建立tsconfig.json文件
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"*": ["types/*"]
},
"target": "es5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"downlevelIteration": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true, // 爲 false 時,若是編譯器沒法根據變量的使用來判斷類型時,將用 any 類型代替。爲 true 時,進行強類型檢查,會報錯
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"checkJs": false,
"jsx": "react",
"lib": ["dom", "es2015"],
"outDir": "./dist/",
"typeRoots": ["./node_modules/@types/", "./src/@types/"]
},
"compileOnSave": false,
"exclude": ["node_modules"]
}
複製代碼
咱們項目主要使用less編寫,因此須要使用less-loader。使用的loader主要以下:
less-loader: 將less轉義成css
css-loader: 用於加載.css文件,並轉換成commonjs對象
style-loader: style-loader用於將<style>標籤插入到header中
postcss-loader: 做用有兩個,第一個就是把 CSS 解析成 JavaScript 能夠操做的抽象語法樹結構(Abstract Syntax Tree,AST),第二個就是調用插件來處理 AST 並獲得結果,用的最多的是autoprefixer插件,能夠自動添加瀏覽器前綴,保證css兼容性的寫法。
style-resources-loader: 主要用於將一些公用less,自動插入到全部less文件中。
複製代碼
咱們把lessLoader抽象成了一個函數,方便在須要的地方調用。
/* * @param lessPath 包含的路徑 * @param isModules 是否須要添加modules */
var lessLoader = function (lessPath, isModules) {
return {
test: /\.less$/,
include: lessPath,
loaders: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: isModules
? '[name]__[local]__[hash:base64:5]'
: '[name]'
}
},
},
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')({
browsers: ['last 5 versions'],
}),
],
},
},
{
loader: 'less-loader',
options: {
globalVars: globalVars,
},
},
{
loader: 'style-resources-loader',
options: {
patterns: path.resolve(
paths.srcPath,
'style',
'var',
'*.less',
),
injector: 'append',
},
},
],
};
};
複製代碼
這裏在囉嗦幾句,開啓了css-modules後,咱們寫css類異常噁心。主要缺點以下:
import { Component } from 'react';
import styles from './style.less';
export default class Container extends Component {
render() {
return (
<div className={ styles.container }> </div>
);
}
}
// style.less
.container {
border-width: 2px;
border-style: solid;
border-color: brown;
padding: 0 20px;
margin: 0 6px;
max-width: 400px;
}
複製代碼
這時咱們可使用react-css-modules來解決以上問題,這樣就舒服多了。配置babelrc.js
{
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"],
"plugins": [
[
"react-css-modules",
{
"filetypes": {
".less": {
"syntax": "postcss-less"
}
},
"webpackHotModuleReloading": true,
"generateScopedName": "[name]__[local]__[hash:base64:5]",
"exclude": "node_modules"
}
]
]
}
複製代碼
import { Component } from 'react';
import './style.less';
export default class Container extends Component {
render() {
return (
<div styleName="container">
</div>
);
}
}
// style.less
.container {
border-width: 2px;
border-style: solid;
border-color: brown;
padding: 0 20px;
margin: 0 6px;
max-width: 400px;
}
複製代碼
還有其餘使用到loader這裏就不一一列舉了,詳情請參考代碼happy-music。
html-webpack-plugin可以根據咱們提供的模板自動生成html文件,並引入打包後的內容。 首先安裝html-webpack-plugin:
yarn add html-webpack-plugin -D
複製代碼
在根目錄建立index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Happy Music</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
複製代碼
配置html-webpack-plugin:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
file: 'index.html',
template: 'index.html',
inject: "body"
})
],
}
複製代碼
在平常的開發過程當中,確定不能每修改一點東西就從新build一次,這樣開發效率會受到很大的影響。這時須要啓動一個服務,來監聽文件的變更。當文件保存時就從新打包,同時幫咱們自動刷新瀏覽器,方便咱們及時觀察到更新。
雖然webpack提供了webpack --watch的命令來動態監聽文件的改變並實時打包,輸出新bundle.js文件,這樣文件多了以後打包速度會很慢,此外這樣的打包的方式不能作到hot replace,即每次webpack編譯以後,你還須要手動刷新瀏覽器。
webpack-dev-server功能能夠克服上面的2個問題。webpack-dev-server的原理:啓動一個使用express的Http服務器。它的做用主要是用來伺服資源文件。此外這個Http服務器和client使用了websocket通信協議,原始文件做出改動後,webpack-dev-server會實時的編譯,可是最後的編譯的文件並無輸出到目標文件夾。
注意:webpack-dev-server後,在目標文件夾中是看不到編譯後的文件的,實時編譯後的文件都保存到了內存當中。 具體配置能夠直接看官方文檔
安裝webpack-dev-server:
yarn add webpack-dev-server -D
複製代碼
在webpack.development文件配置devServer:
module.exports = {
devServer: {
open: true,
inline: true,
contentBase: path.resolve(paths.appPath, 'public'),
port: config['webapck-dev-server'].port || 8080, // 咱們把這些配置抽離到 config目錄是爲了修改方便
host: config['webapck-dev-server'].host || '0.0.0.0',
proxy: {
[config.appPathname]: {
target: 'http://127.0.0.1:' + config.port,
pathRewrite: { ['^' + config.appPathname]: '' },
},
},// 代理主要用於解決跨域問題
publicPath: '',
hot: true,
disableHostCheck: true,
watchOptions: {
ignored: /node_modules/,
poll: false,
},
}
}
複製代碼
ESLint 能夠安裝在當前項目中或全局環境下,由於代碼檢查是項目的重要組成部分,因此咱們通常會將它安裝在當前項目中。能夠運行下面的腳原本安裝:
yarn add eslint -D
複製代碼
因爲 ESLint 默認使用 Espree 進行語法解析,沒法識別 TypeScript 的一些語法,故咱們須要安裝 @typescript-eslint/parser,替代掉默認的解析器,別忘了同時安裝 typescript:
yarn add typescript @typescript-eslint/parser -D
複製代碼
接下來須要安裝對應的插件 @typescript-eslint/eslint-plugin 它做爲 eslint 默認規則的補充,提供了一些額外的適用於 ts 語法的規則。
yarn add @typescript-eslint/eslint-plugin
複製代碼
根目錄建立.eslintrc.js
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
rules: {
// 定義規則
}
}
複製代碼
在編輯器中集成 ESLint 檢查,能夠在開發過程當中就發現錯誤,甚至能夠在保存時自動修復錯誤,極大的增長了開發效率。 要在 VSCode 中集成 ESLint 檢查,咱們須要先安裝 ESLint 插件。 VSCode 中的 ESLint 插件默認是不會檢查 .ts 後綴的,須要在「文件 => 首選項 => 設置 => 工做區」中(也能夠在項目根目錄下建立一個配置文件 .vscode/settings.json),添加如下配置:
{
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "typescript",
"autoFix": true
}
],
"typescript.tsdk": "node_modules/typescript/lib"
}
複製代碼
常見錯誤
module.exports = {
parserOptions: {
ecmaVersion: 6,
sourceType: "module",
ecmaFeatures: {
modules: true
}
}
}
複製代碼
Prettier 聚焦於代碼的格式化,經過語法分析,從新整理代碼的格式,讓全部人的代碼都保持一樣的風格。根目錄建立.prettierrc.js
module.exports = {
// 一行最多 100 字符
printWidth: 100,
// 使用 4 個空格縮進
tabWidth: 4,
// 不使用縮進符,而使用空格
useTabs: false,
// 行尾須要有分號
semi: true,
// 使用單引號
singleQuote: true,
// 對象的 key 僅在必要時用引號
quoteProps: 'as-needed',
// jsx 不使用單引號,而使用雙引號
jsxSingleQuote: false,
// 末尾不須要逗號
trailingComma: 'none',
// 大括號內的首尾須要空格
bracketSpacing: true,
// jsx 標籤的反尖括號須要換行
jsxBracketSameLine: false,
// 箭頭函數,只有一個參數的時候,也須要括號
arrowParens: 'always',
// 每一個文件格式化的範圍是文件的所有內容
rangeStart: 0,
rangeEnd: Infinity,
// 不須要寫文件開頭的 @prettier
requirePragma: false,
// 不須要自動在文件開頭插入 @prettier
insertPragma: false,
// 使用默認的折行標準
proseWrap: 'preserve',
// 根據顯示樣式決定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 換行符使用 lf
endOfLine: 'lf'
};
複製代碼
接下來安裝 VSCode 中的 Prettier 插件,而後修改 .vscode/settings.json:
{
"files.eol": "\n",
"editor.tabSize": 4,
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "typescript",
"autoFix": true
}
],
"typescript.tsdk": "node_modules/typescript/lib"
}
複製代碼
涉及的插件主要有: husky: 一個 Git Hook 工具 lint-staged: 用於實現每次提交只檢查本次提交所修改的文件 @commitlint/cli: commit msg 檢查 @commitlint/config-conventional: 配置commit規則
yarn add husky lint-staged @commitlint/cli @commitlint/config-conventional -D
複製代碼
根目錄建立.huskyrc文件,固然這個也能夠直接配置在package.json文件:
{
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
複製代碼
根目錄建立 .lintstagedrc文件
{
"*.tsx": ["eslint --fix", "git add"],
"*.ts": ["eslint --fix", "git add"]
}
複製代碼
根目錄建立 commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat', // 新功能
'modify', // 修改
'fix', // 修復bug
'docs', // 文檔
'style', // 格式
'refactor', // 重構
'test', // 增長測試
'chore', // 構建過程或輔助工具的變更
'revert', //回滾
'upgrade' // 第三方庫升級
],
],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
},
};
複製代碼
安裝conventional-changelog-cli插件,conventional-changelog-cli 默認推薦的 commit 標準是來自angular項目,除了 angular 標準之外,目前集成了包括 atom, codemirror, ember, eslint, express, jquery 等項目的標準,具體能夠根據本身口味來選用。
yarn add conventional-changelog-cli -D
複製代碼
在根目錄建立release.sh,這個命令主要用於須要正式發佈時,在本地運行,能夠自動生成新的版本號,已經根據commit信息生成changelog。
#!/bin/bash
# 能夠直接設置爲開發分支,origin爲遠程地址
master="dev"
origin=""
git fetch $origin
echo "Current fetch all Tags"
git pull $origin $master
echo "Current pull origin $master."
# 自動生成tag和修改版本號
npm version patch
conventional-changelog -p eslint -i CHANGELOG.md -s -r 0
git add CHANGELOG.md
git commit -m "docs: update changelog"
git push --follow-tags origin $master
echo "Git push origin $master"
echo "Release finished."
複製代碼
配置package.json,增長執行命令,在發佈前能夠在本地運行npm run beforepublish,就能夠自動修改版本號、自動打tag及生成changelog。
"scripts": {
"beforepublish": "./release.sh"
}
複製代碼
完成了上述步驟,咱們項目的初始化配置也基本告一段落了,基本能夠正常跑起來了。
!本項目的倉庫爲happy-music。其中master分支爲最新的全部代碼,每次更新文章都會對應一個tag,tag是自增的,本篇文章對應的代碼tag爲v1.0.3。
本篇文章主要講述了整個項目的初始化過程,裏面涉及的內容都很基礎,可是是搭建系統不可或缺的一部分。你們能夠關注個人微信公衆號,會按期分享前端乾貨,共同成長。
@Author WaterMan