React hooks + Mobx + typescript + EggJs從0到1打造一款仿網易雲音樂APP(二)

引言

該項目會以 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的大拿,就能夠跳過這片文章了。這篇文章的主要內容有:前端

  • webpack4構建項目(建議新手不要輕易使用create-react-app等腳手架,前端進階,webpack基本是繞不開的);
  • babel7轉譯es六、react語法;
  • 配置eslint;
  • 配置commit-lint,約束提交的信息
  • 配置changelog-cli自動生成可讀性高的changelog

囉裏八嗦的終於來到了正文部分了!!!java

項目配置

先給項目取一個響亮的名字,奉行快樂優先原則,就叫happy-music吧。node

webpack4配置不細說,具體的直接看官網就能夠了,這裏只列出一些重點。建立以下文件結構,其中webpack.common.js用於抽離公用配置,webpack.dev.js和webpack.prod.js分別對應開發和線上環境。react

安裝webpack依賴,其中webpack-merge就是用來合併配置的

yarn add -D webpack webpack-cli webpack-merge
複製代碼

loader

webpack的做用都在官網這張圖上,就是將各類模塊進行處理和打包。而loader就是處理webpack中的模塊。jquery

配置babel-loader

咱們項目主要使用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-loader

咱們項目主要使用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類異常噁心。主要缺點以下:

  • 必須使用駝峯法來命名css類名
  • 當引入到 className 中時必需要使用 styles 對象
  • CSS modules 和 全局css類混合在一塊兒會很難管理
  • 引用沒用定義的CSS modules不會出現警告
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

插件plugin

html-webpack-plugin

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"
        })
    ],
}

複製代碼

webpack-dev-server啓動本地開發服務

在平常的開發過程當中,確定不能每修改一點東西就從新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

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: {
        // 定義規則
    }
}
複製代碼

vscode 集成 ESLint 檢查

在編輯器中集成 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"
}
複製代碼

常見錯誤

這時須要在.eslintrc.js配置sourceType,參考以下:

module.exports = {
    parserOptions: {
        ecmaVersion: 6,
        sourceType: "module",
        ecmaFeatures: {
            modules: true
        }
    }
}
複製代碼

使用prettier格式化代碼

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"
}
複製代碼

提交前自動 eslint 校驗和 commit 信息的規範校驗

涉及的插件主要有: 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'],
    },
};

複製代碼

自動changelog生成

安裝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

相關文章
相關標籤/搜索