该项目会以 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