這裏有一份簡潔的前端知識體系等待你查收,看看吧,會有驚喜哦~若是以爲不錯,麻煩star哈~css
webpack 是當下最好用的前端模塊打包工具,前端開發人員平常都要跟腳手架打交道,而手腳架就是基於webpack構建的,深刻理解webpack,對咱們平常工做意義重大。html
本文將系統講解webpack,老規矩,從應用維度跟設計維度展開,因爲做者能力有限,有些部分暫時整理不出來,若是你有所補充,歡迎push~前端
從技術的應用維度看,首先考慮的是要解決什麼問題,這是技術產生的緣由。問題這層,用來回答「幹什麼用」。node
隨着前端的演變,網頁已經至關於一個功能豐富的應用,前端面臨諸多挑戰:react
因爲前端界存在種種問題,webpack應運而生。jquery
webpack官方定義就是一個模塊打包工具。webpack不只支持 ES module 的語法,也支持 CommonJS 的語法。webpack
webpack 不只能夠打包JS,也能夠打包其餘格式的文件, 好比css、image等。git
技術被研發出來,人們怎麼用它才能解決問題呢?這就要看技術規範,能夠理解爲技術使用說明書。技術規範,回答「怎麼用」的問題,反映你對該技術使用方法的理解深度。github
這裏要重點講解webpack的配置。web
webpack 配置文件須要指定 mode,默認是production,打包後的文件會被壓縮。能夠指定成 development。不設置mode,會有警告
module.exports = {
// ……
mode: 'production',
}
複製代碼
entry 支持配置多項,每一項的key是文件名,當entry配置多個入口文件時,output的filename不能寫死,否則會報錯,能夠寫成 filename: [name].js
。
output 還能夠配置publicPath,從而設置導出JS文件的前綴,經過這個配置,能夠設置CDN地址。
module.exports = {
entry: {
main: './src/index.js',
sub: './src/index.js'
},
output: {
filename: '[name].js', // 設置成 index.js 會報錯
chunkFilename: '[name].chunk.js',
publicPath: 'http://cdn.com',
path: path.resolve(__dirname, '../dist')
}
}
複製代碼
loader就是打包方案。
好比,打包jpg圖片時,可使用 file-loader 進行打包,也可使用url-loader,url-loader包含了 file-loader 全部的功能,並且,他默認會將圖片轉成base64格式。若是不但願轉成base64位,能夠設置 limit,這樣的話,當圖片大於設置值的時候,就不會轉成base64。
// webpack.config.js
module.exports = {
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
}]
}
}
複製代碼
又好比,打包css文件時,須要同時引入兩個loader:css-loader跟style-loader。css-loader會分析css文件的引用關係,最後把css文件合併成一段css。而style-loader的做用是把這段css放到head下的style標籤下。
若是是scss文件,還須要引入 scss-loader。若是須要css自動添加瀏覽器產商前綴,則須要引入postcss-loader。
因爲css中還能夠引用其餘的css,爲了不出錯,須要在css-loader 中設置importLoaders。
爲了防止css全局污染,咱們須要引入css modules的概念,也就是css模塊化。一樣須要在css-loader 中設置 modules 爲true。引入時可使用相似的方式: import style from './index.css'
若是css中引用了字體文件,還須要對 字體文件的格式設置loader,使用 file-loader 便可。
module.exports = {
module: {
rules: [{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
},
'postcss-loader'
]
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}]
},
}
複製代碼
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
複製代碼
若是有多個loader時,會從後往前執行。
使用plugins讓打包更便捷。
plugin 很像生命週期函數,能夠在webpack 運行到某一個時刻,幫你處理一些事情。
htmlWebpackPlugin 會在打包結束後,自動生成一個HTML文件,並把打包生成的JS自動引入到HTML中。
cleanWebpackPlugin 會在打包以前,刪除某一個文件夾(好比dist文件夾)
module.exports = {
// ……
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../')
})
]
}
複製代碼
sourceMap 是一個映射關係,當咱們打包的文件報錯時,它能提示咱們是源文件的出錯位置,而不是打包後文件的出錯位置,這樣就利於調試。
使用方式,就是在 webpack 中配置 devtool: 'source-map'
development 環境,推薦使用 devtool: 'cheap-module-eval-source-map'
production 環境,推薦使用 devtool: 'cheap-module-source-map'
module.exports = {
// ……
mode: 'development',
devtool: 'cheap-module-eval-source-map',
}
複製代碼
每次修改代碼都要從新打包,這是很是繁瑣的,咱們能夠修改npm scripts成webpack --watch
。
但若是咱們想實現更酷炫的效果,好比自動打開瀏覽器、自動刷新瀏覽器等,這個操做就作不到。此時,能夠藉助webpackDevServer 來實現。
webpack支持 devServer , 能夠幫咱們啓動了一個服務器。咱們在平常開發中,常常須要發ajax請求,這大大提升了咱們的開發效率。此外,devServer打包後的文件,其實保存在內存中,這樣打包的速度更快。
以前 devServer 還不夠完善,因此不少腳手架工具會本身實現一個devServer,如今webpack的devServer已經很是完善了。
更多請參考官網
module.exports = {
devServer: {
contentBase: './dist', // 服務器的根目錄
open: true, // 自動打開瀏覽器
port: 8080,
hot: true,
proxy: { // 設置代理,訪問/api,直接轉發到3000端口
"/api": "http://localhost:3000"
}
},
}
複製代碼
咱們也能夠手寫一個 devServer,新建server.js,增長 npm scripts : node server.js
。
const express = require('express);
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config.js');
const complier = webpack(config)
const app = express(); // 啓動一個http服務器
app.use(webpackDevMiddleware(complier, {}))
app.listen(3000, ()=>{
console.log("server is running");
})
複製代碼
經過這個例子,也能夠看到webpack有兩種使用方式,一種是在命令行中使用,一種是在node中直接使用webpack。
在命令行使用webpack,能夠參考官網資料
在node中使用webpack,能夠參考官網資料
咱們每一次修改代碼,devServer都會幫咱們刷新頁面,但咱們只但願顯示修改的內容,而不刷新頁面,此時就要用到熱更新。
const webpack = require('webpack');
module.exports = {
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true, // 可選,即使hot功能不生效,瀏覽器也不刷新
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
}
複製代碼
有些瀏覽器還不支持ES6的語法,此時就須要用babel轉義,將ES6語法轉成ES5。
babel提供了詳細的使用指南,在官網setup頁面選擇webpack選項就能夠看到。
babel的使用分爲三步:
npm install --save-dev babel-loader @babel/core
複製代碼
babel-loader @babel/core 是 babel 跟 webpack 之間的橋樑
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
複製代碼
npm install @babel/preset-env --save-dev
複製代碼
// .babelrc
{
"presets": ["@babel/preset-env"]
}
複製代碼
@babel/preset-env 將ES6的語法轉義成ES5語法,好比let轉成var
@babel/polyfill 爲低級瀏覽器注入了ES6的對象或方法,好比promise
引入 @babel/polyfill 會讓咱們的文件變得很是大,能夠配置 useBuiltIns 作到按需加載
babel 內容很是多,建議直接看官網。
module.exports = {
// ……
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [["@babel/preset-env", {
targets: {
chrome: '67', // 告訴 babel 目標瀏覽器,babel能夠根據目標瀏覽器決定是否作轉化,這樣就能夠減小最終輸出文件的大小
},
useBuiltIns: 'usage // 提升性能:用到的才引用
}]]
}
// use: [{
// loader: 'babel-loader'
// }, {
// loader: 'imports-loader?this=>window'
// }]
}]
},
}
複製代碼
babel-loader 中 options 的內容會很是多,能夠把 options 的內容放到 .babelrc 中
咱們引入一個模塊,只會引入該模塊中的部分方法,tree shaking會幫咱們把不須要的方法過濾掉,這樣打包後的文件將顯著變小。
tree shaking 只支持 ES Module 的引用方式。
development 模式下,默認是不支持 tree shaking,咱們須要配置 optimization 的 usedExports 爲true。
咱們還須要給 package.json 增長一項配置 "sideEffects": ["@babel/polyfill", "*.css"]
,這樣打包時 tree shaking 對 @babel/polyfill就不會有做用。這是由於咱們引用@babel/polyfill時,是import @babel/polyfill
,tree shaking 會認爲 @babel/polyfill 不須要引用任何東西,從而把它忽略掉。同理,咱們可使用 import "index.css"
,咱們一樣不但願tree shaking生效,咱們能夠在sideEffects中增長 *.css 的配置。
若是設置"sideEffects": false
,表示對全部模塊都作 tree shaking。
development 模式下,爲了調試方便,雖然設置了 tree shaking,但打包出來的文件同樣包含沒有引用的模塊。當咱們上線時,會設置 mode 爲 production,此時 tree shaking 就會把不須要模塊的代碼過濾掉。
module.exports = {
// ……
mode: 'development',
optimization: {
usedExports: true,
},
}
複製代碼
因爲 development 和 production 模式下的配置是不同的,咱們能夠抽離出公共的 webpack.common.js,以及Dev下的 webpack.dev.js 和 production下的webpack.prod.js。最後使用 webpack.merge 合併。
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const devConfig = {
// ……
}
module.exports = merge(commonConfig, devConfig);
複製代碼
webpack代碼分割底層使用了 splitChunksPlugin 插件。官網資料地址。
module.exports = {
splitChunks: {
chunks: "async", // 可選:all。async 只代碼分割異步代碼,all同時支持同步跟異步的方式
minSize: 30000, // 小於 30KB 不作代碼分割,大於 30KB,還要根據cacheGroups的規則決定是否作代碼分割
maxSize: 20000, // 大於 20KB 嘗試作代碼分割,但因爲基礎庫是不容許分割的,因此通常不生效
minChunks: 1, // 引用超過1次,會作代碼分割。
maxAsyncRequests: 5, // 遇到的前5個庫,會作代碼分割,超過5個的不作代碼分割
maxInitialRequests: 3, // 入口文件最多隻能作三次代碼分割
automaticNameDelimiter: '~', // 文件鏈接符
name: true, // 爲true時,cacheGroups的filename纔會生效
cacheGroups: { // 緩存組,知足以上要求的文件,會根據緩存組中的要求,加入緩存組,最終打包成文件。這樣的好處是能夠把多個庫,輸出成一個文件。此外,若是配置了上面的參數卻沒有代碼分割,極可能就是緩存組的配置不知足
vendors: {
test: /[\\/]node_modules[\\/]/, // node_modules目錄下的文件會被匹配
priority: -10, // 優先級,值越大優先級越大
// filename: 'vendors.js'
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true // 若是一個模塊已經被打包了,則再打包時會忽略該模塊
}
}
},
}
複製代碼
小技巧:splitChunks 若是不配置,默認值就是上面的這些選項。簡便寫法是:
module.exports = {
// ……
splitChunks: {
chunks: "all", // 咱們要對同步跟異步代碼都作代碼分割,因此改爲all
},
}
複製代碼
咱們也能夠爲css進行代碼分割,使用到的插件是MiniCssExtractPlugin,只須要用MiniCssExtractPlugin提供的loader 代替 style-loader 便可,具體內容看官網。
最佳實踐回答「怎麼能用好」的問題,反映你實踐經驗的豐富程度。
webpack 不建議全局安裝,由於每一個項目依賴的webpack版本可能不一樣,全局安裝可能致使項目依賴的webpack版本不對而沒法運行,建議局部安裝,也就是 npm i webpack webpack-cli -D
。
局部安裝完webpack後,若是要查看webpack的版本,執行 webpack -v
是得不到預期的結果,由於webpack並沒全局安裝,此時要執行 npx webpack -v
,npx是npm提供的命令,它會在咱們當前目錄下的node_modules文件下尋找安裝過的依賴。
若是咱們是在package.json文件中配置 npm scripts,則不須要npx這個指令,由於 npm scripts 默認會在當前目錄下的 node_modules 尋找依賴。
安裝webpack時,能夠指定webpack的版本號,若是不清楚webpack有什麼版本,可使用npm info webpack
查看
webpack-cli 容許咱們在命令裏使用webpack這個命令。
若是把全部的代碼都打包到一個文件裏,會帶來兩個問題:
code splitting 是代碼分割,沒有webpack咱們也能夠手動作代碼分割,從而提高性能。webpack能幫咱們自動完成代碼分割。
webpack 中實現代碼分割有兩種方式:
module.exports = {
// ……
optimization: {
splitChunks: {
chunks: 'all',
}
},
}
複製代碼
咱們可使用webpack提供的analyse工具進行打包分析.
咱們在打包時,須要增長命令webpack --profile --json > stats.json
,也就是 webpack --profile --json > stats.json --config ./build/webpack.dev.js
打包完的文件中,就會出現stats.json的文件。
咱們打開連接,上次stats.json,就會出現打包的分析報告。
webpack官方提供的分析工具,除了analyse,還有這些:
webpack 建議咱們寫異步加載代碼,也就是異步import。當代碼執行時,纔會去加載相應的代碼,這樣首屏的代碼利用率就能夠提升。相似:
document.addEventListener('click', () => {
import('./click.js').then(({ default: func }) => {
func()
})
})
複製代碼
咱們能夠用Chrome的coverage工具看代碼的利用率。
但咱們不必定要等到用戶操做時,纔去加載相應的代碼,而是在網絡空閒時就去加載。咱們能夠在webpack中進行配置。具體作法以下:
// 關注下魔法註釋,js的新特性
document.addEventListener('click', () => {
import(/* webpackPrefetch: true */ './click.js').then(({ default: func }) => {
func()
})
})
複製代碼
Prefetching/Preloading 是有區別的:
因此Prefetching會更合適。
咱們打包的文件,瀏覽器是會緩存的,當咱們修改了內容,用戶刷新頁面,此時加載的仍是緩存中的文件。爲了解決這個問題,咱們須要修改production模式下的配置文件。
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: 'production',
devtool: 'cheap-module-source-map',
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
},
optimization: {
runtimeChunk: {
name: 'runtime' // 舊版本必須配置此項,不然即使文件內容沒有發生改變,hash值也會改變
},
}
}
module.exports = merge(commonConfig, prodConfig);
複製代碼
contenthash 會根據文件內容生成hash值,當咱們文件內容改變時,contenthash就會改變,從而通知瀏覽器從新向服務器請求文件。
之因此在舊版webpack下,文件代碼沒變,生成文件的hash值也會改變的緣由是:
咱們業務邏輯的代碼打包到main.js裏,依賴庫的代碼打包到vendors.js裏,但main.js跟vendors.js是有依賴關係的,這些依賴關係的代碼會保存在manifest文件裏。manifest文件既存在於main.js,也存在vendors.js裏。而在舊版webpack每次打包manifest可能會有差別,這個差別致使vendors.js的hash值也會改變。設置runtimeChunk後,manifest相關的代碼會被抽離出來,放到runtime文件裏去,這樣就能解決這個問題。
jQuery時代,咱們須要先引入jQuery,再引入其餘依賴jQuery的類庫,好比jQuery.ui.js。這在webpack中就有問題。好比這樣:
// a.js
import $ from 'jquery'
import 'jquery.ui'
複製代碼
這樣引用,jquery.ui.js會報錯:找不到只能在a.js裏引用,jquery.ui.js是引用不到$的,而jquery.ui.js是第三方庫,咱們又不能去修改jquery.ui.js的代碼,怎麼辦呢?
咱們能夠添加ProvidePlugin插件。在ProvidePlugin裏咱們設置了,在當前又沒引用指向jquery。
關於ProvidePlugin,能夠到官網看資料
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
_join: ['lodash', 'join']
}),
],
performance: false, // 額外補充:設置爲false,打包時不會警告性能方面的問題
}
複製代碼
關於墊片機制,還有其餘用法。好比咱們在一個模塊中全局打印this,發現this指向的是模塊自己,而不是window對象,若是想要讓this指向window,能夠這樣:
module.exports = {
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader'
}, {
loader: 'imports-loader?this=>window'
}]
}]
},
}
複製代碼
咱們須要安裝imports-loader,設置this指向window。
關於shimming,能夠看官網資料
咱們寫的庫,要支持多種方式的引用,諸如:
// library.js
export function math (){
console.log(1);
}
複製代碼
import library from './library' // ES module
const library = require('library'); // commonjs
require(['library'], function(){}) // AMD
複製代碼
咱們能夠配置libraryTarget:
module.exports = {
mode: 'production',
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
libraryTarget: 'umd' // umd 是通用的意思。配置了umd,就能夠支持不一樣的引用方式
}
}
複製代碼
若是你還想經過script標籤引用,好比<script src="./library.js"></script>
,那還須要配置
module.exports = {
mode: 'production',
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
library: 'library', // 打包好的代碼,掛載到頁面library這個全局變量上
libraryTarget: 'umd' // umd 是通用的意思。配置了umd,就能夠支持不一樣的引用方式
}
}
複製代碼
打包後到瀏覽器控制檯輸入library,就會打印出全局變量
這裏要重點講下 library 跟 libraryTarget 的關係。library的含義是要生成一個全局變量, libraryTarget 的含義是這個全局變量掛載到哪裏。若是libraryTarget設置爲umd,則二者關係不大。若是咱們把libraryTarget 設置成this,則打包出來的文件不支持ES module、commonjs等的引用,他表示全局變量掛載到全局的this上。此時咱們在瀏覽器控制檯,輸入this.library
,就能夠找到該全局變量。libraryTarget 還設置成 window、global。
此外,咱們在打包時,還會出現一種狀況:
// library.js
import _ from lodash;
// 其餘代碼
複製代碼
// a.js
import _ from lodash;
import library from './library';
複製代碼
這就形成lodash被打包了兩次,咱們但願library.js打包時,不要把lodash打包進去,能夠這樣配置:
module.exports = {
externals: ['lodash] // 打包時,遇到lodash,自動忽略
}
複製代碼
咱們把生成的文件放到線上,用戶就能夠訪問,若是服務器掛了,頁面就會顯示異常。這種時候,咱們但願即使服務器掛了,用戶仍是能夠看到以前訪問的頁面,而這就是PWA。
要作到PWA很簡單,首先配置webpack。
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
module.exports = {
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
}),
]
}
複製代碼
而後在業務代碼中,使用 serviceWorker。
if('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('service-worker register')
}).catch(error => {
console.log('service-worker register error')
})
})
}
複製代碼
咱們在開發時,常常會遇到跨域的問題,devServer 能夠幫助咱們實現請求轉發,具體看官網資料
咱們只須要在webpack進行以下配置:
module.exports = {
devServer: {
proxy: {
'/react/api': {
target: 'https://baidu.com/',
secure: false, // false 時才能夠對https請求的轉發
pathRewrite: {
'header.json': 'demo.json'
}
}
}
},
}
複製代碼
devServer 中的proxy容許咱們作請求轉發。當咱們請求'/react/api'就會被轉發到http://baidu.com/
的域名下。此外,咱們在平常開發中,可能須要用到header.json這個API時,該API還沒開發完,咱們須要先訪問demo.json進行開發,此時就能夠設置pathRewrite達到效果。
webpack的proxy內容很是多,底層使用的是http-proxy-middleware,能夠上GitHub看相應的資料
咱們在寫react應用時,須要用到react-router-dom實現路由,可是咱們會發現,當咱們訪問/list時,預期是要訪問到/list路由,但瀏覽器會發送請求到/list,從而頁面顯示出錯。
要解決這個問題,就要用到devServer的historyApiFallback這個API了。
當咱們在devServer裏配置historyApiFallback:true
後,咱們無論訪問什麼url,都會執行根目錄(也就是/)下的代碼,從而解決了單頁路由的問題。
更多內容,看官網
eslint 跟 webpack關係不大,不少編輯器是能夠支持eslint插件,但可能咱們爲了調試方便,但願eslint的錯誤顯示在瀏覽器上,這樣即使咱們編輯器沒有eslint插件,也能夠看到問題。
操做起來也很簡單,咱們先在本身的工程裏安裝eslint跟eslint-loader.
module.exports = {
devServer: {
overlay: true // 必須配置
},
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader", "eslint-loader"], // 使用 eslint-loader
},
]
}
複製代碼
關於eslint-loader,能夠看官網資料
跟上技術迭代
webpack運行於node,node版本更新,天然會提升webpack的打包效率,npm跟yarn等包管理工具也是同理。
在儘量少的模塊上應用loader:
爲loader配置exclude,例如: exclude: /node_moudles/
爲loader配置include,例如:include: path.resolve(__dirname, '../src')
plugin 儘量精簡併確保可靠
好比開發環境下,不須要對代碼進行壓縮,這樣就不須要在webpack.dev.js裏引入相關的plugin
合理配置resolve
當咱們沒有寫js後綴時,webpack默認會幫咱們補上,若是咱們的jsx文件也不但願寫上後綴,但願webpack會幫咱們默認補上,能夠設置resolve。
module.exports = {
resolve: {
extensions: ['.js', '.jsx'],
mainFiles: ['index', 'child'] // 當咱們引用的是某個路徑,webpack默認會幫咱們讀取index文件,若是咱們設置了['index', 'child'],webpack會逐一幫咱們查找index.js index.jsx child.js child.jsx
}
}
複製代碼
隨着技術生態的發展,和應用問題的變遷,技術的應用場景和流行趨勢會受到影響。這層回答「誰用,用在哪」的問題,反映你對技術應用領域的認識寬度。
爲了解決用戶的問題,技術自己要達成什麼目標。這層定義「作到什麼」。
webpack就是個模塊打包工具,咱們須要使用webpack打包不限於JS、CSS、image等文件。
不一樣的文件,打包策略是不一樣的,因此咱們須要配置loader。
打包過程當中,咱們可能還須要作一些額外的操做,因此咱們須要配置 plugin。
因此學習webpack的重點,就是理解與掌握loader跟plugin。
webpack 默認會讀取 webpack.config.js文件,咱們也能夠更改默認的文件名npx webpack --config webpack.xxx.js
注:webpack開發團隊爲了提升開發體驗,一直在豐富webpack的默認配置,因此咱們雖然沒有指定JS的打包策略,但同樣能夠打包成功。
爲了達到設計目標,該技術採用了什麼原理和機制。實現原理層回答「怎麼作到」的問題。把實現原理弄懂,而且講清楚,是技術人員的基本功。
每種技術實現,都有其侷限性,在某些條件下能最大化的發揮效能,缺乏了某些條件則暴露出其缺陷。優劣侷限層回答「作得怎麼樣」的問題。對技術優劣侷限的把握,更有利於應用時總結最佳實踐,是分析各類「坑」的基礎。
技術是在迭代改進和不斷淘汰的。瞭解技術的前生後世,分清技術不變的本質,和變化的脈絡,以及與其餘技術的共生關係,能體現你對技術發展趨勢的關注和思考。這層體現「將來如何」。