在學習了Webpack基礎后,查看別人寫好的腳手架總是會一頭霧水,后面就上網查各種資料,一邊參考一邊修改,整出了一套簡易的[腳手架](https://github.com/pwstrick/pwu)(已上傳至GiuHub和[npm](https://www.npmjs.com/package/pwu)上),借鑒了[Create React App](https://www.html.cn/create-react-app/docs/getting-started/)(CRA)的目錄結構(如下所示),并做成了[命令行工具](https://github.com/pwstrick/pwu-cli)(已上傳至GiuHub和[npm](https://www.npmjs.com/package/pwu-cli)上)。
~~~css
├── pwu --------------------------------------- 腳手架示例
│ ├── config -------------------------------- webpack配置目錄
│ ├── ├── jest ------------------------------ Jest測試的配置目錄
│ ├── ├── webpack.base.config.js ------------ 通用配置
│ ├── ├── webpack.dev.config.js ------------- 開發環境配置
│ ├── ├── webpack.prod.config.js ------------ 生產環境配置
│ ├── bin ----------------------------------- 命令行工具
│ ├── ├── pwu.js ---------------------------- 命令文件
│ ├── dist ---------------------------------- 輸出目錄
│ ├── ├── css ------------------------------- 樣式
│ ├── ├── img ------------------------------- 圖像
│ ├── ├── js -------------------------------- 腳本
│ ├── public -------------------------------- 模板目錄
│ ├── ├── index.html ------------------------ 模板頁面
│ ├── src ----------------------------------- 源文件目錄
│ ├── ├── __tests__ ------------------------- 測試目錄
│ ├── ├── component ------------------------- 組件目錄
│ ├── ├── font ------------------------------ 字體目錄
│ ├── ├── img ------------------------------- 圖像目錄
│ ├── ├── index.js -------------------------- 入口文件
│ ├── ├── index.scss ------------------------ 全局樣式
│ ├── package.json -------------------------- 管理依賴的包
│ ├── package-lock.json --------------------- 管理包的版本號和來源
│ ├── postcss.config.js --------------------- 后處理器配置文件
│ ├── tsconfig.json ------------------------- TypeScript配置文件
│ ├── .eslintrc ----------------------------- ESLint配置文件
│ ├── .eslintignore ------------------------- ESLint忽略的文件和目錄
│ ├── .gitignore ---------------------------- Git忽略的文件和目錄
~~~
## 一、通用配置
**1)入口和出口**
  在通用配置中包含兩個環境都需要的參數,例如入口和出口,如下所示。[path](http://nodejs.cn/api/path.html)是Node.js中的路徑模塊[path.resolve()](http://nodejs.cn/api/path.html#path_path_resolve_paths)用于解析絕對路徑,[\_\_dirname](http://nodejs.cn/api/globals.html#globals_dirname)可讀取當前模塊的目錄名。
~~~
const path = require("path");
module.exports = {
entry: {
index: "./src/index.js"
},
output: {
path: path.resolve(__dirname, "../dist"),
publicPath: "/"
}
};
~~~
  [publicPath](https://webpack.docschina.org/configuration/output/#output-publicpath)指定靜態資源的基礎路徑,公式如下。
~~~
靜態資源最終路徑 = output.publicPath + 加載器或插件的配置路徑
~~~
  假設html元素的背景是一條相對路徑,那么最后生成的路徑將會是“/img/lake.png”,其中配置的輸出目錄是“img”。
~~~css
html {
background: url("../../../public/img/lake.png") no-repeat;
}
/* 生成的背景路徑 */
html {
background: url("/img/lake.png") no-repeat;
}
~~~
  在CRA的webpack.config.js配置文件中,也有對publicPath的配置,如下所示,生產和開發環境會有對應的值。
~~~
const publicPath = isEnvProduction ? paths.servedPath : isEnvDevelopment && '/';
~~~
**2)加載器**
  在加載器中,會添加腳本([babel-loader](https://webpack.docschina.org/loaders/babel-loader/))、樣式([css-loader](https://webpack.docschina.org/loaders/css-loader/)、[postcss-loader](https://webpack.docschina.org/loaders/postcss-loader/)和[sass-loader](https://webpack.docschina.org/loaders/sass-loader/))、圖像([url-loader](https://webpack.docschina.org/loaders/url-loader/))以及字體([file-loader](https://webpack.docschina.org/loaders/file-loader/))。
~~~
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/
},
{
test: /\.(sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader"
]
},
{
test: /\.(jpg|png|gif)$/,
use: {
loader: "url-loader",
options: {
name: "[name].[ext]",
outputPath: "img/",
limit: 8192
}
}
},
{
test: /\.(eot|ttf|svg|woff|woff2)$/,
use: {
loader: "file-loader",
options: {
name: "[name]_[hash].[ext]",
outputPath: "font/"
}
}
}
]
}
};
~~~
  在解析樣式的配置中,使用了四個加載器,后聲明的先執行。[Babel](https://www.babeljs.cn/repl)的配置信息寫到了package.json文件中,新建一個babel字段,useBuiltIns的值為usage,表示自動加載源碼所需的Polyfill。
~~~
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": 11,
"chrome": 49
},
"corejs": "2",
"useBuiltIns": "usage"
}
],
"@babel/preset-react"
]
}
~~~
  postcss-loader又稱為CSS后處理器,常用來提升瀏覽器兼容性,它有許多配套插件(例如[autofix](https://github.com/browserslist/browserslist#readme)),這些插件的配置被放在單獨的postcss.config.js文件中,如下所示。
~~~
module.exports = {
plugins: [require("autoprefixer")()]
};
~~~
  在執行時,postcss-loader會建議將瀏覽器的信息放在package.json中,新建一個browserslist字段,如下所示。
~~~
"browserslist": [
"last 5 version",
">1%",
"ie >=8"
]
~~~
  MiniCssExtractPlugin.loader引用的是[mini-css-extract-plugin](https://webpack.docschina.org/plugins/mini-css-extract-plugin/)插件的加載器,該插件能從JS文件中提取CSS樣式,保存到單獨的CSS文件中。
  url-loader和file-loader中的outputPath屬性用于配置輸出目錄。圖像中的limit屬性的值是8192,以字節為單位,相當于8kb,如果圖像尺寸小于該值,那就將其轉換成Base64格式,嵌入到文件中,減少HTTP請求。字體文件的名稱還會加上唯一標識的hash值,生成的名稱如下所示。
~~~
iconfont_7346d960c4ad96f1ea8d5a8834fab00f.ttf
~~~
**3)插件**
  MiniCssExtractPlugin插件的作用前面已提過,其中chunkFilename參數會在動態導入時用到。
~~~
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].[hash].css",
chunkFilename: "css/[id].[hash].css"
})
]
~~~
## 二、開發環境配置
  在開發環境中,需要引入通用配置,再利用[webpack-merge](https://webpack.docschina.org/guides/production/)合并,如下所示。[mode](https://www.webpackjs.com/concepts/mode/)字段用于告知webpack使用相應模式的優化。輸出的文件名稱也包含hash,但只會提取前8個字符。
~~~
const base = require('./webpack.base.config.js');
const merge = require('webpack-merge');
module.exports = merge(base, {
mode: "development",
output: {
filename: "js/[name].[hash:8].bundle.js"
}
});
~~~
**1)webpack-dev-server**
  開啟基于Node.js的本地服務器:[webpack-dev-server](https://webpack.docschina.org/configuration/dev-server/)。
~~~
devServer: {
contentBase: path.resolve(__dirname, "../dist"),
open: true, //自動打開瀏覽器
port: 4000, //端口號
compress: true, //啟用gzip壓縮:
useLocalIp: true, //使用本機IP
hot: true //開啟熱更新
}
~~~
**2)Source Map**
  通過Source Map追蹤錯誤或警告在源文件中的原始位置,以便調試,可配置[devtool](https://webpack.docschina.org/configuration/devtool/)實現,如下所示。
~~~
devtool: "source-map"
~~~
  再添加webpack的[HotModuleReplacementPlugin](https://webpack.docschina.org/plugins/hot-module-replacement-plugin/)插件,如下所示。
~~~
const webpack = require('webpack');
module.exports = merge(base, {
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
~~~
**3)HtmlWebpackPlugin**
  [HtmlWebpackPlugin](https://webpack.docschina.org/plugins/html-webpack-plugin/)插件能根據模板生成一個HTML文件,還能自動引入所需的bundle文件。模板文件被放置在public目錄中,如下所示。
~~~html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"/>
<title>腳手架示例</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
~~~
  具體配置如下,[inject參數](https://github.com/jantimon/html-webpack-plugin#options)用于指定腳本注入位置,例如body元素的底部。
~~~
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = merge(base, {
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
inject: "body"
})
]
});
~~~
**4)腳本命令**
  在package.js文件的scripts字段中,聲明了start命令,開啟本地服務器,并實時重載腳本。
~~~
{
"scripts": {
"start": "webpack-dev-server --config ./config/webpack.dev.config.js"
}
}
~~~
## 三、生產環境配置
  生產環境比較注重性能,因此需要做很多優化配置,例如壓縮、代碼分離等,mode采用production優化模式,如下所示。
~~~
module.exports = merge(base, {
mode: "production",
output: {
filename: 'js/[name].[chunkhash:8].bundle.js'
}
}
~~~
**1)optimization**
  首先優化的是代碼分離,也就是將穩定不變的模塊(例如react、react-dom等)抽取成一個單獨的文件,splitChunks參數的配置可參考[SplitChunksPlugin](https://webpack.docschina.org/plugins/split-chunks-plugin/)插件。
~~~
module.exports = merge(base, {
optimization: {
splitChunks: {
chunks: "all",
minSize: 30000,
maxSize: 0,
minChunks: 1,
cacheGroups: {
vendors: {
test: /node_modules/,
name: "vendor",
enforce: true
}
}
}
}
});
~~~
  cacheGroups是優化的關鍵,它是一個緩存組(屬性如下所示),vendors會篩選從node\_modules目錄下引入的模塊。
  (1)test:一個字符串、正則或函數,模塊的匹配條件。
  (2)name:拆分出的chunk(塊)的名字。
  (3)enforce:當為true時,可忽略minSize、minChunks、maxAsyncRequests和maxInitialRequests選項。
  (4)priority:打包的優先級。
  接下來優化的是壓縮,配置到minimizer選項中。[UglifyjsWebpackPlugin](https://webpack.docschina.org/plugins/uglifyjs-webpack-plugin/)插件會使用使用UglifyJS去壓縮JavaScript代碼。[OptimizeCssAssetsPlugin](https://github.com/NMFR/optimize-css-assets-webpack-plugin)插件用于壓縮CSS文件。
~~~
const UglifyjsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = merge(base, {
optimization: {
minimizer: [
new UglifyjsWebpackPlugin(),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require("cssnano"),
cssProcessorPluginOptions: {
preset: ["default", { discardComments: { removeAll: true } }]
},
canPrint: true
})
]
}
});
~~~
**2)插件**
  生產環境也需要模板插件,只不過要配置minify選項,如下所示,去除注釋和空格。
~~~
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
inject: "body",
minify: {
removeComments: true,
collapseWhitespace: true
}
})
~~~
  [CleanWebpackPlugin](https://github.com/johnagan/clean-webpack-plugin)插件可清除輸出目錄中的文件。
~~~
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = merge(base, {
plugins: [
new CleanWebpackPlugin()
]
});
~~~
  偶爾會出現圖45中的錯誤,目前還沒找出原因。
:-: 
圖 45
**3)腳本命令**
  在package.js文件的scripts字段中,新增build命令,可在本地構建項目。
~~~
{
"scripts": {
"start": "webpack-dev-server --config ./config/webpack.dev.config.js",
"build": "webpack --config ./config/webpack.prod.config.js"
}
}
~~~
## 四、TypeScript
  若要支持[TypeScript](https://webpack.docschina.org/guides/typescript/),那么必須安裝相應的模塊以及加載器,命令如下。
~~~
npm install --save-dev typescript ts-loader
~~~
  在webpack的通用配置中,添加如下字段,[resolve](https://webpack.docschina.org/configuration/resolve/)的extensions屬性能夠在引入模塊時不帶擴展。
~~~
module.exports = {
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
module: {
rules: [
{
test: /\.tsx?$/,
use: [ 'ts-loader' ],
exclude: /node_modules/
}
]
}
};
~~~
  還得要添加tsconfig.json配置文件,如下所示,具體的字段說明可以[參考官方文檔](https://www.tslang.cn/docs/handbook/compiler-options.html)。
~~~
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true
}
}
~~~
  由于要使用react和react-dom,因此還需要安裝它們的聲明文件:[@types/react](https://www.npmjs.com/package/@types/react)和[@types/react-dom](https://www.npmjs.com/package/@types/react-dom)。并且使用了html-webpack-plugin插件,它的聲明文件([@types/html-webpack-plugin](https://www.npmjs.com/package/@types/html-webpack-plugin))也得安裝。
  都安裝好后,就能在tsx文件中使用JSX語法了,如下所示。
~~~
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './component/app/app';
function init() {
ReactDOM.render(React.createElement(App, null), document.getElementById('root'));
}
init();
~~~
  在webpack中的通用配置中,可添加新的入口文件,如下所示。
~~~
module.exports = {
entry: {
index: "./src/index.ts",
index2: "./src/index.tsx"
}
}
~~~
## 五、ESLint
  [ESLint](https://cn.eslint.org/)是目前流行的靜態代碼檢測工具,它能建立一套代碼規范,保證代碼的一致性,并且還能避免不必要的錯誤。
**1)基礎配置**
  首先需要安裝[ESLint](https://www.npmjs.com/package/eslint)和ESLint的[加載器](https://www.npmjs.com/package/eslint-loader),命令如下所示。
~~~
npm install --save-dev eslint eslint-loader
~~~
  然后在通用配置中添加eslint-loader,如下所示。
~~~
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: [ 'babel-loader', 'eslint-loader'] ,
exclude: /node_modules/
},
{
test: /\.tsx?$/,
use: [ 'ts-loader', 'eslint-loader' ],
exclude: /node_modules/
}
]
}
};
~~~
  接著在根目錄中創建.eslintrc配置文件,如下所示,rules字段中可記錄各種規則。
~~~
{
"rules": {
}
}
~~~
**2)規則**
  現在運行腳手架會報錯(如下所示),因為ESLint不能識別ES6語法。
~~~
1:1 error Parsing error: The keyword 'import' is reserved
~~~
  為了避免該錯誤,需要安裝[babel-eslint](https://www.npmjs.com/package/babel-eslint),并且修改.eslintrc文件。
~~~
{
"parser": "babel-eslint",
"rules": {
}
}
~~~
  下面添加一條簡單的[max-len](https://cn.eslint.org/docs/rules/max-len)規則(其它規則可參考[官方文檔](https://cn.eslint.org/docs/rules/)),一行最長200,4個Tab字符的寬度,忽略尾部注釋和行內注釋。
~~~
{
"rules": {
"max-len": ["warn", 200, 4, { "ignoreComments": true }]
}
}
~~~
  當超過該限制時,會顯示下面的警告。
~~~
7:1 warning This line has a length of 292. Maximum allowed is 200 max-len
~~~
  由于使用了React,因此還可以添加React的規則,安裝[eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react),并修改.eslintrc文件。
~~~
{
"plugins": [
"react"
]
}
~~~
  如果不想自己定義規則,那么可以直接使用網上開源的規則,例如[Airbnb](https://www.npmjs.com/package/eslint-config-airbnb)的[JavaScript編碼規范](https://juejin.im/entry/56e8c0c1816dfa0051376758)。注意,Airbnb的標準包會依賴[eslint-plugin-import](https://www.npmjs.com/package/eslint-plugin-import)、eslint-plugin-react和[eslint-plugin-jsx-a11y](https://www.npmjs.com/package/eslint-plugin-jsx-a11y)等插件。安裝成功后,再次修改.eslintrc文件。
~~~
{
"extends": "airbnb"
}
~~~
  重新運行腳手架,馬上就會出現一大堆錯誤和警告,修改加載器(如下所示),使用--fix參數可以將它們減少很多。
~~~
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: [
'babel-loader',
{loader: 'eslint-loader', options: {fix: true}}
],
exclude: /node_modules/
},
{
test: /\.tsx?$/,
use: [
'ts-loader',
{loader: 'eslint-loader', options: {fix: true}}
],
exclude: /node_modules/
}
]
}
};
~~~
**3)pre-commit**
  如果使用的版本控制系統是Git,那么可以在每次提交前檢測ESLint的規則。當檢測失敗時,就能阻止提交。
  [husky](https://www.npmjs.com/package/husky)是一個Git鉤子工具,可以防止不良的git commit、git push等操作。[lint-staged](https://www.npmjs.com/package/lint-staged)可對暫存的Git文件執行指定的任務。注意,husky對Node和Git的版本有要求,前者要大于10,后者要大于2.13。
  接下來修改package.json文件,添加husky和lint-staged字段,在lint-staged中配置ESLint檢測以及需要檢測的文件后綴。當檢測失敗時,會得到圖46中的提示。
~~~
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint"
]
}
~~~
:-: 
圖 46
## 六、Jest
  Jest是Facebook開源的一個測試框架,曾經寫過一篇[入門的教程](http://www.hmoore.net/pwstrick/fe-questions/1414223)。要將Jest集成到[Webpack](https://doc.ebichu.cc/jest/docs/zh-Hans/webpack.html)中,首先得安裝[Jest](https://www.npmjs.com/package/jest),安裝完成后在package.json文件中添加一條腳本命令(如下所示),執行Jest并打印測試覆蓋率。注意,生成的測試覆蓋率信息默認會保存到coverage目錄中。
~~~
"scripts": {
"test": "jest --coverage"
}
~~~
  現在執行“npm test”,不會有任何結果,因為還沒寫測試腳本。Jest默認會測試\_\_tests\_\_目錄和名稱中包含spec或test的腳本文件(包括TypeScript文件),并且默認還會忽略node\_modules目錄中的文件,配置項如下所示。
~~~
testMatch: [ '**/__tests__/**/*.js?(x)', '**/?(*.)(spec|test).js?(x)' ]
testPathIgnorePatterns: ["node_modules"]
~~~
  在src目錄中新增\_\_tests\_\_目錄,并新建app.js,其代碼如下所示,添加了一個用于演示的測試用例。
~~~
describe("my test case", () => {
test("one plus one is two", () => {
expect(1 + 1).toBe(2);
});
});
~~~
  當在測試用例中使用ES6語法時(例如像下面這樣引入組件),會提示錯誤,此時需要引入[babel-jest](https://www.npmjs.com/package/babel-jest)。而babel-jest在安裝Jest時已經自動下載,因此不必再單獨安裝。
~~~
import { App } from '../component/app/app';
~~~
  在package.json文件定義jest字段,并聲明[transform](https://doc.ebichu.cc/jest/docs/zh-Hans/configuration.html#transform-object-string-string)選項,添加下面這條規則,就能避免報錯。
~~~
"jest": {
"transform": {
"^.+\\.js$": "babel-jest"
}
}
~~~
  Jest還有一些其它配置,在測試時能發揮重大作用。例如在使用樣式對象時,將所有的className原樣返回(例如styles.container === 'container'),這會便于快照測試。要實現這個功能,得安裝[identity-obj-proxy](https://www.npmjs.com/package/identity-obj-proxy),并修改moduleNameMapper選項,如下所示。
~~~
"jest": {
"moduleNameMapper": {
"\\.(css|scss)$": "identity-obj-proxy"
}
}
~~~
  當moduleNameMapper不能滿足需求時,可以使用transform選項設定轉換規則,如下所示。
~~~
"jest": {
"transform": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)$": "<rootDir>/config/jest/fileTransformer.js"
}
}
~~~
  fileTransformer.js文件位于配置目錄的jest目錄中,其作用就是返回文件的名稱(如下代碼所示),例如require('avatar.png')返回“avatar.png”。
~~~
const path = require('path');
module.exports = {
process(src, filename, config, options) {
return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
}
};
~~~
  注意,之前使用了ESLint檢測代碼,因此測試用例也會被檢測。如果不想執行ESLint,那么可以添加.eslintignore文件,內容如下所示,其中配置目錄也被忽略了。
~~~
src/__tests__
config
~~~
## 七、命令行工具
  之前曾寫過一篇命令行工具的[簡易教程](http://www.hmoore.net/pwstrick/fe-questions/1627451)。目前的設想是將命令行工具從腳手架中分離出來,通過命令下載腳手架。
  首先安裝[ora](https://github.com/sindresorhus/ora)、[chalk](https://github.com/chalk/chalk)、[commander](https://github.com/tj/commander.js)和[download-git-repo](https://gitlab.com/flippidippi/download-git-repo)四個包,安裝命令如下所示。
~~~
npm install --save ora chalk commander download-git-repo
~~~
  ora是一個優雅的終端旋轉器,chalk可為終端中的文字添加顏色,commander是一個編輯命令的工具,download-git-repo可下載GitHub上的倉庫代碼。下面是具體的命令,命令([pwu-cli](https://www.npmjs.com/package/pwu-cli))已上傳到npm中,安裝成功后,可以執行“pwu create demo”創建demo目錄(如圖47所示),并自動下載[pwu](https://github.com/pwstrick/pwu)倉庫中的腳手架代碼。
~~~
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const ora = require('ora');
const chalk = require('chalk');
const program = require('commander');
const download = require('download-git-repo');
program
.version('1.0.0', '-v, --version', '版本');
program
.command('create <name>')
.description('create a repository')
.action(name => {
const spinner = ora('開始下載腳手架');
spinner.start();
const destination = path.join(process.cwd(), name);
if(fs.existsSync(destination)) {
console.log(chalk.red('腳手架已存在'));
return;
}
download('github:pwstrick/pwu', destination, (err) => {
spinner.stop();
console.log(chalk.green('腳手架下載成功'));
});
});
program.parse(process.argv)
~~~
:-: 
圖 47
  在發布到npm時,npm可根據.gitignore文件中的內容進行過濾,這樣就能避免上傳依賴的模塊。
*****
> 原文出處:
[博客園-前端利器躬行記](https://www.cnblogs.com/strick/category/1472499.html)
[知乎專欄-前端利器躬行記](https://zhuanlan.zhihu.com/pwtool)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020