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

相关文章
相关标签/搜索