摘要:安裝配置加載器配置配置文件配置支持自定義的預(yù)設(shè)或插件只有配置了這兩個(gè)才能讓生效,多帶帶的安裝是無(wú)意義的。
想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你!
最新React全家桶實(shí)戰(zhàn)使用配置指南這篇文檔 是呂小明老師結(jié)合以往的項(xiàng)目經(jīng)驗(yàn) 加上自己本身對(duì)react webpack redux理解寫(xiě)下的總結(jié)文檔,總共耗時(shí)一周總結(jié)下來(lái)的,希望能對(duì)讀者能夠有收獲, 我是在這基礎(chǔ)多些加工!
目錄1.版本說(shuō)明
2.目錄結(jié)構(gòu)
3.初始化項(xiàng)目
4.webpack
5.react
6.配置loader(sass,jsx))
7.引入babel
8.使用HtmlWebpackPlugin
9.redux
10.使用webpack-dev-server
11.多入口頁(yè)面配置
12.如何理解entry point(bundle),chunk,module
13.多入口頁(yè)面html配置
14.模塊熱替換(Hot Module Replacement)
15.使用ESLint
16.使用react-router
17.使用redux-thunk
18.使用axios和async/await
19.Code Splitting
20.使用CommonsChunkPlugin
版本說(shuō)明由于構(gòu)建相關(guān)例如webpack,babel等更新的較快,所以本教程以下面各種模塊的版本號(hào)為主,切勿輕易修改或更新版本。
"dependencies": { "babel-core": "^6.26.3", "babel-eslint": "^8.2.3", "babel-loader": "^7.1.4", "babel-plugin-transform-async-to-generator": "^6.24.1", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "babel-preset-stage-0": "^6.24.1", "babel-preset-stage-3": "^6.24.1", "css-loader": "^0.28.11", "eslint": "^4.19.1", "eslint-loader": "^2.0.0", "eslint-plugin-react": "^7.9.1", "file-loader": "^1.1.11", "history": "^4.7.2", "html-webpack-plugin": "^3.2.0", "react": "^16.4.0", "react-dom": "^16.4.0", "react-hot-loader": "^4.0.0", "react-redux": "^5.0.7", "react-router-dom": "^4.3.1", "react-router-redux": "^5.0.0-alpha.9", "redux": "^4.0.0", "sass-loader": "^7.0.3", "style-loader": "^0.21.0", "url-loader": "^1.0.1", "webpack": "^4.12.0", "webpack-cli": "^3.0.3", "webpack-dev-server": "^3.1.1" }目錄結(jié)構(gòu)
開(kāi)發(fā)和發(fā)布版本的配置文件是分開(kāi)的,多入口頁(yè)面的目錄結(jié)構(gòu)。
react-family/ | |──dist/ * 發(fā)布版本構(gòu)建輸出路徑 | |──dev/ * 調(diào)試版本構(gòu)建輸出路徑 | |──src/ * 工具函數(shù) | | | |—— component/ * 各頁(yè)面公用組件 | | | |—— page/ * 頁(yè)面代碼 | | |—— index/ * 頁(yè)面代碼 | | | |—— Main/ * 組件代碼 | | | | |—— Main.jsx * 組件jsx | | | | |—— Main.scss * 組件css | | | | | |—— detail/ * 頁(yè)面代碼 | | | |—— static/ * 靜態(tài)文件js,css | | |──webpack.config.build.js * 發(fā)布版本使用的webpack配置文件 |──webpack.config.dev.js * 調(diào)試版本使用的webpack配置文件 |──.eslint * eslint配置文件 |__.babelrc * babel配置文件初始化項(xiàng)目
1.創(chuàng)建文件夾
mkdir react-family-bucket
2.初始化npm
cd react-family-bucket npm init
如果有特殊需要,可以填入自己的配置,一路回車下來(lái),會(huì)生成一個(gè)package.json,里面是你項(xiàng)目的基本信息,后面的npm依賴安裝也會(huì)配置在這里。
webpack1.安裝webpack
npm install webpack@4.12.0 --save or npm install webpack@4.12.0 --g
--save 是將當(dāng)前webpack安裝到react-family-bucket下的/node_modules。
--g 是將當(dāng)前webpack安裝到全局下面,可以在node的安裝目錄下找到全局的/node_modules。
2.配置webopack配置文件
touch webpack.config.dev.js
3.新建一個(gè)app.js
touch app.js
寫(xiě)入基本的webpack配置,可以參考這里:
const path = require("path"); const srcRoot = "./src"; module.exports = { // 輸入配置 entry: [ "./app.js" ],, // 輸出配置 output: { path: path.resolve(__dirname, "./dev"), filename: "bundle.min.js" }, };
3.執(zhí)行webpack命令
如果是全局安裝:
webpack --config webpack.config.dev.js
如果是當(dāng)前目錄安裝:
./node_modules/.bin/webpack --config webpack.config.dev.js
為了方便我們使用,可以在package.json中 scripts 添加執(zhí)行命令:
"scripts": { "dev": "./node_modules/.bin/webpack --config webpack.config.dev.js", },
執(zhí)行npm run dev命令之后,會(huì)發(fā)現(xiàn)需要安裝webpack-cli,(webpack4之后需要安裝這個(gè))
npm install webpack-cli --save
安裝后,執(zhí)行 npm run dev 會(huì)發(fā)現(xiàn)控制臺(tái)有個(gè)警告 WARNING in configuration ,去除WARNING in configuration 警告,在webpack.config.dev.js 增加一個(gè)配置即可:
... mode: "development" ...
成功之后會(huì)在dev下面生成bundle.min.js代表正常。
如果想要?jiǎng)討B(tài)監(jiān)聽(tīng)文件變化需要在命令后面添加 --watch。
react1.安裝react
npm install react react-dom --save
2.創(chuàng)建page目錄和index頁(yè)面文件:
mkdir src mkdir page cd page
3.創(chuàng)建index
mkdir index cd index & touch index.js & touch index.html
index.js
import ReactDom from "react-dom"; import Main from "./Main/Main.jsx"; ReactDom.render(, document.getElementById("root"));
index.html
index
4.創(chuàng)建Main組件
import React from "react"; class Main extends React.Component { constructor(props) { super(props); } render() { return (Main); } } export default Main;
5.修改webpack配置入口文件
entry: [ path.resolve(srcRoot,"./page/index/index.js") ],配置loader
1.處理樣式文件需要這些loader:
css-loader
sass-loader
style-loader
npm install css-loader sass-loader style-loader file-loader --save
配置:
module: { // 加載器配置 rules: [ { test: /.css$/, use: ["style-loader", "css-loader"], include: path.resolve(srcRoot)}, { test: /.scss$/, use: ["style-loader", "css-loader", "sass-loader"], include: path.resolve(srcRoot)} ] },
2.url-loader 處理處理靜態(tài)文件
npm install url-loader --save
配置:
module: { // 加載器配置 rules: [ { test: /.(png|jpg|jpeg)$/, use: "url-loader?limit=8192&name=images/[name].[hash].[ext]", include: path.resolve(srcRoot)} ] },
limit:表示超過(guò)多少就使用base64來(lái)代替,單位是byte
name:可以設(shè)置圖片的路徑,名稱和是否使用hash 具體參考這里
引入babelbebel是用來(lái)解析es6語(yǔ)法或者是es7語(yǔ)法分解析器,讓開(kāi)發(fā)者能夠使用新的es語(yǔ)法,同時(shí)支持jsx,vue等多種框架。
1.安裝babel
babel-core
babel-loader
npm install babel-core babel-loader --save
配置:
module: { // 加載器配置 rules: [ { test: /.(js|jsx)$/, use: [{loader:"babel-loader"}] ,include: path.resolve(srcRoot)}, ] },
2.babel配置文件:.babelrc
touch .babelrc
配置:
{ "presets": [ "es2015", "react", "stage-0" ], "plugins": [] }
babel支持自定義的預(yù)設(shè)(presets)或插件(plugins),只有配置了這兩個(gè)才能讓babel生效,多帶帶的安裝babel是無(wú)意義的。
presets:代表babel支持那種語(yǔ)法(就是你用那種語(yǔ)法寫(xiě)),優(yōu)先級(jí)是從下往上,state-0|1|2|..代表有很多沒(méi)有列入標(biāo)準(zhǔn)的語(yǔ)法回已state-x表示,參考這里
plugins:代表babel解析的時(shí)候使用哪些插件,作用和presets類似,優(yōu)先級(jí)是從上往下。
依次安裝:
babel-preset-es2015
babel-preset-react
babel-preset-stage-0
npm install babel-preset-es2015 babel-preset-react babel-preset-stage-0 --save
3.babel-polyfill是什么?
我們之前使用的babel,babel-loader 默認(rèn)只轉(zhuǎn)換新的 JavaScript 語(yǔ)法,而不轉(zhuǎn)換新的 API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局對(duì)象,以及一些定義在全局對(duì)象上的方法(比如 Object.assign)都不會(huì)轉(zhuǎn)譯。如果想使用這些新的對(duì)象和方法,必須使用 babel-polyfill,為當(dāng)前環(huán)境提供一個(gè)墊片。
npm install --save babel-polyfill
4.transform-runtime 有什么區(qū)別?
當(dāng)使用babel-polyfill時(shí)有一些問(wèn)題:
默認(rèn)會(huì)引入所有babel支持的新語(yǔ)法,這樣就會(huì)導(dǎo)致你的文件代碼非常龐大。
通過(guò)向全局對(duì)象和內(nèi)置對(duì)象的prototype上添加方法來(lái)達(dá)成目的,造成全局變量污染。
這時(shí)就需要transform-runtime來(lái)幫我們有選擇性的引入:
npm install --save babel-plugin-transform-runtime
配置文件:
{ "plugins": [ ["transform-runtime", { "helpers": false, "polyfill": false, "regenerator": true, "moduleName": "babel-runtime" }] ] }使用HtmlWebpackPlugin
記得我們之前新建的index.html么 我們執(zhí)行構(gòu)建命令之后并沒(méi)有將index.html打包到dev目錄下 我們需要HtmlWebpackPlugin來(lái)將我們output的js和html結(jié)合起來(lái):
npm install html-webpack-plugin --save
配置:
const HtmlWebpackPlugin = require("html-webpack-plugin"); ... plugins: [ new HtmlWebpackPlugin({ filename: path.resolve(devPath, "index.html"), template: path.resolve(srcRoot, "./page/index/index.html"), }) ]
filename:可以設(shè)置html輸出的路徑和文件名
template:可以設(shè)置已哪個(gè)html文件為模版
更多參數(shù)配置可以參考這里
redux關(guān)于redux的使用可以參考阮一峰老師的入門(mén)教程
1.安裝redux
redux
react-redux
npm install redux react-redux --save
1.新建reducers,actions目錄和文件
|—— index/ |—— Main/ * 組件代碼 | |—— Main.jsx * 組件jsx | |—— Main.scss * 組件css | |—— actions/ | |—— actionTypes.js * action常量 | |—— todoAction.js * action | |—— reducers/ | |—— todoReducer.js * reducer | |—— store.js | |—— index.js
2.修改代碼,引入redux,這里以一個(gè)redux todo為demo例子:
index.js
import ReactDom from "react-dom"; import React from "react"; import Main from "./Main/Main.jsx"; import store from "./store.js"; import { Provider } from "react-redux"; ReactDom.render(, document.getElementById("root"));
store.js
import { createStore } from "redux"; import todoReducer from "./reducers/todoReducer.js"; const store = createStore(todoReducer); export default store;
tabReducer.js
import { ADD_TODO } from "../actions/actionTypes.js"; const initialState = { todoList: [] }; const addTodo = (state, action) => { return { ...state, todoList: state.todoList.concat(action.obj) } } const todoReducer = (state = initialState, action) => { switch(action.type) { case ADD_TODO: return addTodo(state, action); default: return state; } }; export default todoReducer;
Main.jsx
import React from "react"; import { connect } from "react-redux"; import { addTodo } from "../actions/todoAction.js"; class Main extends React.Component { onClick(){ let text = this.refs.input; this.props.dispatch(addTodo({ text: text.value })) } render() { return (); } } export default connect( state => ({ todoList: state.todoList }) )(Main);{this.props.todoList.map((item, index)=>{ return
- {item.text}
})}
todoAction.js
import { ADD_TODO } from "./actionTypes.js"; export const addTodo = (obj) => { return { type: ADD_TODO, obj: obj }; };使用webpack-dev-server
webpack-dev-server是一個(gè)小型的Node.js Express服務(wù)器,它使用webpack-dev-middleware來(lái)服務(wù)于webpack的包。
1.安裝
npm install webpack-dev-server --save
修改在package.json中添加的執(zhí)行命令:
"scripts": { "dev": "./node_modules/.bin/webpack-dev-server --config webpack.config.dev.js", },
2.配置webpack配置文件:
devServer: { "contentBase": devPath, "compress": true, },
contentBase: 表示server文件的根目錄
compress: 表示開(kāi)啟gzip
更多的配置文檔參考這里
webpack-dev-server默認(rèn)情況下會(huì)將output的內(nèi)容放在內(nèi)存中,是看不到物理的文件的,如果想要看到物理的dev下面的文件可以安裝write-file-webpack-plugin這個(gè)插件。
webpack-dev-server默認(rèn)會(huì)開(kāi)啟livereload功能
3.devtool功能:
具體來(lái)說(shuō)添加了devtool: "inline-source-map"之后,利用source-map你在chrome控制臺(tái)看到的source源碼都是真正的源碼,未壓縮,未編譯前的代碼,沒(méi)有添加,你看到的代碼是真實(shí)的壓縮過(guò),編譯過(guò)的代碼,更多devtool的配置可以參考這里。
多入口文件配置在之前的配置中,都是基于單入口頁(yè)面配置的,entry和output只有一個(gè)文件,但是實(shí)際項(xiàng)目很多情況下是多頁(yè)面的,在配置多頁(yè)面時(shí),有2中方法可以選擇:
1.在entry入口配置時(shí),傳入對(duì)象而不是多帶帶數(shù)組,output時(shí)利用[name]關(guān)鍵字來(lái)區(qū)分輸出文件例如:
entry: { index: [path.resolve(srcRoot,"./page/index/index1.js"),path.resolve(srcRoot,"./page/index/index2.js")], detail: path.resolve(srcRoot,"./page/detail/detail.js"), home: path.resolve(srcRoot,"./page/home/home.js"), }, output: { path: path.resolve(__dirname, "./dev"), filename: "[name].min.js" },
2.通過(guò)node動(dòng)態(tài)遍歷需要entry point的目錄,來(lái)動(dòng)態(tài)生成entry:
const pageDir = path.resolve(srcRoot, "page"); function getEntry() { let entryMap = {}; fs.readdirSync(pageDir).forEach((pathname)=>{ let fullPathName = path.resolve(pageDir, pathname); let stat = fs.statSync(fullPathName); let fileName = path.resolve(fullPathName, "index.js"); if (stat.isDirectory() && fs.existsSync(fileName)) { entryMap[pathname] = fileName; } }); return entryMap; } { ... entry: getEntry() ... }
本demo采用的是第二中寫(xiě)法,能夠更加靈活。
如何理解entry point(bundle),chunk,module在webpack中,如何理解entry point(bundle),chunk,module?
根據(jù)圖上的表述,我這里簡(jiǎn)單說(shuō)一下便于理解的結(jié)論:
配置中每個(gè)文件例如index1.js,index2.js,detail.js,home.js都屬于entry point.
entry這個(gè)配置中,每個(gè)key值,index,detail,home都相當(dāng)于chunk。
我們?cè)诖a中的require或者import的都屬于module,這點(diǎn)很好理解。
chunk的分類比較特別,有entry chunk,initial chunk,normal chunk,參考這個(gè)文章
正常情況下,一個(gè)chunk對(duì)應(yīng)一個(gè)output,在使用了CommonsChunkPlugin或者require.ensure之后,chunk就變成了initial chunk,normal chunk,這時(shí),一個(gè)chunk對(duì)應(yīng)多個(gè)output。
理解這些概念對(duì)于后續(xù)使用webpack插件有很大的幫助。
多入口頁(yè)面html配置之前我們配置HtmlWebpackPlugin時(shí),同樣采用的是但頁(yè)面的配置,這里我們將進(jìn)行多頁(yè)面改造,entryMap是上一步得到的entry:
function htmlAarray(entryMap) { let htmlAarray = []; Object.keys(entryMap).forEach(function(key){ let fullPathName = path.resolve(pageDir, key); let fileName = path.resolve(fullPathName, key + ".html") if (fs.existsSync(fileName)) { htmlAarray.push(new HtmlWebpackPlugin({ chunks: key, // 注意這里的key就是chunk filename: key + ".html", template: fileName, inlineSource: ".(js|css)" })) } }); return htmlAarray; }
修改plugin配置:plugins: [ ... ].concat(htmlMap)模塊熱替換(Hot Module Replacement)
模塊熱替換 (Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允許在運(yùn)行時(shí)更新各種模塊,而無(wú)需進(jìn)行完全刷新,很高大上有木有!
下面說(shuō)一下配置方法,它需要結(jié)合devServer使用:
devServer: { hot: true // 開(kāi)啟HMR },
開(kāi)啟plugin:
const webpack = require("webpack"); plugins: [ new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin(), ].concat(htmlMap)
結(jié)合React一起使用:
1.安裝react-hot-loader
npm install react-hot-loader --save
并新建一個(gè)Container.jsx:
import React from "react"; import Main from "./Main.jsx"; import { hot } from "react-hot-loader" class Container extends React.Component { render() { return } } export default hot(module)(Container);
結(jié)合redux:如果項(xiàng)目沒(méi)有使用redux,可以無(wú)需配置后面2步
2.修改store.js新增下面代碼,為了讓reducer也能實(shí)時(shí)熱替換
if (module.hot) { module.hot.accept("./reducers/todoReducer.js", () => { const nextRootReducer = require("./reducers/todoReducer.js").default; store.replaceReducer(nextRootReducer); }); }
3.修改index.js
import ReactDom from "react-dom"; import React from "react"; import Container from "./Main/Container.jsx"; import store from "./store.js"; import { Provider } from "react-redux"; ReactDom.render(, document.getElementById("root"));
當(dāng)控制臺(tái)看到[WDS] Hot Module Replacement enabled.代表開(kāi)啟成功
使用ESLintESLint 是眾多 Javascript Linter 中的其中一種,其他比較常見(jiàn)的還有 JSLint 跟 JSHint,之所以用 ESLint 是因?yàn)樗梢宰杂蛇x擇要使用哪些規(guī)則,也有很多現(xiàn)成的 plugin 可以使用,另外他對(duì) ES6 還有 JSX 的支持程度跟其他 linter 相比之下也是最高的。
1.安裝ESLint
npm install eslint eslint-loader babel-eslint --save
其中eslint-loader是將webpack和eslint結(jié)合起來(lái)在webpack的配置文件中新增一個(gè)eslint-loader種,修改如下:
{ test: /.(js|jsx)$/, use: [{loader:"babel-loader"},{loader:"eslint-loader"}] ,include: path.resolve(srcRoot)},
2.新建.eslintrc配置文件,將parser配置成babel-eslint
{ "extends": ["eslint:recommended"], "parser": "babel-eslint", "globals": { }, "rules": { } }
3.安裝eslint-plugin-react:
npm install eslint-plugin-react --save
說(shuō)明一下,正常情況下每個(gè)eslint規(guī)則都是需要在rule下面配置,如果什么都不配置,其實(shí)本身eslint是不生效的。
eslint本身有很多默認(rèn)的規(guī)則模版,可以通過(guò)extends來(lái)配置,默認(rèn)可以使用eslint:recommended。
在使用react開(kāi)發(fā)時(shí)可以安裝eslint-plugin-react來(lái)告知使用react專用的規(guī)則來(lái)lint。
修改.eslintrc配置文件,增加rules,更多rules配置可以參考這里
{ "extends": ["eslint:recommended","plugin:react/recommended"], "parser": "babel-eslint", "globals": { "window": true, "document": true, "module": true, "require": true }, "rules": { "react/prop-types" : "off", "no-console" : "off" } }使用react-router
react-router強(qiáng)大指出在于方便代碼管理,結(jié)合redux使用更加強(qiáng)大,同時(shí)支持web,native更多參考這里
1.安裝react-router-dom
npm install react-router-dom --save
2.如果項(xiàng)目中用了redux,可以安裝react-router-redux
npm install react-router-redux@next history --save
3.修改代碼:
index.js
import ReactDom from "react-dom"; import React from "react"; import Container from "./Main/Container.jsx"; import { store, history } from "./store.js"; import { Provider } from "react-redux"; import createHistory from "history/createHashHistory"; import { ConnectedRouter } from "react-router-redux"; const history = createHistory(); ReactDom.render(, document.getElementById("root"));
結(jié)合history,react-router一共有3中不同的router:
BrowserRouter通過(guò)history/createBrowserHistory引入:當(dāng)切換時(shí),url會(huì)動(dòng)態(tài)更新,底層使用的時(shí)html5的pushState。
HashRouter通過(guò)history/createHashHistory引入:當(dāng)切換時(shí),動(dòng)態(tài)修改hash,利用hashchange事件。
MemoryRouter 通過(guò)history/createMemoryHistory引入:將路徑,路由相關(guān)數(shù)據(jù)存入內(nèi)存中,不涉及url相關(guān)更新,兼容性好。
更多配置可以參考這里
4.如果想要在代碼邏輯中獲取當(dāng)前的route路徑需要引入router-reducer:
新建main.js:
import { combineReducers } from "redux"; import { routerReducer } from "react-router-redux"; import todoReducer from "./todoReducer.js"; const reducers = combineReducers({ todoReducer, router: routerReducer }); export default reducers;
修改store.js:
import { createStore } from "redux"; import mainReducer from "./reducers/main.js"; const store = createStore(mainReducer); export default store;
然后就可以在this.props.router里面獲取單相關(guān)的路徑信息
5.如果需要自己通過(guò)action來(lái)觸發(fā)router的跳轉(zhuǎn),需要引入routerMiddleware:
import { createStore,applyMiddleware } from "redux"; import { routerMiddleware } from "react-router-redux"; const middleware = routerMiddleware(history); const store = createStore(mainReducer,applyMiddleware(middleware));
6.使用Route和Link和withRouter:
先說(shuō)說(shuō)都是干嘛的:
export default withRouter(connect( state => ({ todoList: state.todoReducer.todoList }) )(Main));
如果你在使用hash時(shí)遇到Warning: Hash history cannot PUSH the same path; a new entry will not be added to the history stack錯(cuò)誤,可以將push改為replace即:
切換到2號(hào)
7.設(shè)置初始化路由:
BrowserRouter和HashRouter:
const history = createHistory(); history.push("2");
MemoryRouter:
const history = createMemoryHistory({ initialEntries: ["/2"] });使用redux-thunk
redux-thunk 是一個(gè)比較流行的 redux 異步 action 中間件,比如 action 中有 setTimeout 或者通過(guò) fetch通用遠(yuǎn)程 API 這些場(chǎng)景,那么久應(yīng)該使用 redux-thunk 了。redux-thunk 幫助你統(tǒng)一了異步和同步 action 的調(diào)用方式,把異步過(guò)程放在 action 級(jí)別解決,對(duì) component 沒(méi)有影響。
1.安裝redux-thunk:
npm install redux-thunk --save
2.修改store.js:
import { createStore,applyMiddleware } from "redux"; import thunk from "redux-thunk"; import mainReducer from "./reducers/main"; ... const store = createStore(mainReducer, applyMiddleware(thunk)); ... export default store;
3.在action.js使用redux-thunk:
export const getData = (obj) => (dispatch, getState) => { setTimeout(()=>{ dispatch({ type: GET_DATA, obj: obj }); },1000); };使用axios和async/await
axios 是一個(gè)基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶端:
從瀏覽器中創(chuàng)建 XMLHttpRequest
從 node.js 發(fā)出 http 請(qǐng)求
支持 Promise API
自動(dòng)轉(zhuǎn)換JSON數(shù)據(jù)
1.安裝axios:
npm install axios --save
2.在action中使用axios:
import axios from "axios"; export const getData = (obj) => (dispatch, getState) => { axios.get("/json/comments.json").then((resp)=>{ dispatch({ type: GET_DATA, obj: resp }); }); };
async/await:
Javascript的回調(diào)地獄,相信很多人都知道,尤其是在node端,近些年比較流行的是Promise的解決方案,但是隨著 Node 7 的發(fā)布,編程終級(jí)解決方案的 async/await應(yīng)聲而出。
function resolveAfter2Seconds() { return new Promise(resolve => { setTimeout(() => { resolve("resolved"); }, 2000); }); } async function asyncCall() { var result = await resolveAfter2Seconds(); } asyncCall();
async/await的用途是簡(jiǎn)化使用 promises 異步調(diào)用的操作,并對(duì)一組 Promises執(zhí)行某些操作。await前提是方法返回的是一個(gè)Promise對(duì)象,正如Promises類似于結(jié)構(gòu)化回調(diào),async/await類似于組合生成器和 promises。
1.async/await需要安裝babel-plugin-transform-async-to-generator。
npm install babel-plugin-transform-async-to-generator --save
2.在.babelrc中增加配置:
"plugins": [ "transform-async-to-generator" ]
這樣做僅僅是將async轉(zhuǎn)換generator,如果你當(dāng)前的瀏覽器不支持generator,你將會(huì)收到一個(gè)Uncaught ReferenceError: regeneratorRuntime is not defined的錯(cuò)誤,你需要:
3.安裝babel-plugin-transform-runtime:
npm install babel-plugin-transform-async-to-generator --save
4.修改.babelrc中的配置(可以去掉之前配置的transform-async-to-generator):
"plugins": [ "transform-runtime" ]
5.如果不想引入所有的polyfill(參考上面對(duì)babel的解釋),可以增加配置:
"plugins": [ "transform-runtime", { "polyfill": false, "regenerator": true, } ]
6.結(jié)合axios使用
import axios from "axios"; export const getData = (obj) => async (dispatch, getState) => { let resp = axios.get("/json/comments.json"); dispatch({ type: GET_DATA, obj: resp }); };Code Splitting
1.對(duì)于webpack1,2之前,你可以使用require.ensure來(lái)控制一個(gè)組件的懶加載:
require.ensure([], _require => { let Component = _require("./Component.jsx"); },"lazyname")
2.在webpack4中,官方已經(jīng)不再推薦使用require.ensure來(lái)使用懶加載功能Dynamic Imports,取而代之的是ES6的import()方法:
import( /* webpackChunkName: "my-chunk-name" */ /* webpackMode: "lazy" */ "module" );
不小小看注釋里的代碼,webpack在打包時(shí)會(huì)動(dòng)態(tài)識(shí)別這里的代碼來(lái)做相關(guān)的配置,例如chunk name等等。
3.Prefetching/Preloading modules:
webpack 4.6.0+支持了Prefetching/Preloading的寫(xiě)法:
import(/* webpackPreload: true */ "ChartingLibrary");
3.結(jié)合React-Router使用:
react-loadable對(duì)上述的功能做了封裝,豐富了一些功能,結(jié)合React-Router起來(lái)使用更加方便。
npm install react-loadable --save
在react-router里使用:
function Loading() { return使用CommonsChunkPluginLoading...; } let Div2 = Loadable({ loader: () => import("./Div2"), loading: Loading, });
CommonsChunkPlugin 插件,是一個(gè)可選的用于建立一個(gè)獨(dú)立文件(又稱作 chunk)的功能,這個(gè)文件包括多個(gè)入口 chunk 的公共模塊。通過(guò)將公共模塊拆出來(lái),最終合成的文件能夠在最開(kāi)始的時(shí)候加載一次,便存起來(lái)到緩存中供后續(xù)使用。
1.在webpack4之前的用法:
new webpack.optimize.CommonsChunkPlugin({ name: "common", chunks: ["page1","page2"], minChunks: 3 })
name: string: 提出出的名稱
chunks: string[]: webpack會(huì)從傳入的chunk里面提取公共代碼,默認(rèn)從所有entry里提取
minChunks: number|infinity|function(module,count)->boolean: 如果傳入數(shù)字或infinity(默認(rèn)值為3),就是告訴webpack,只有當(dāng)模塊重復(fù)的次數(shù)大于等于該數(shù)字時(shí),這個(gè)模塊才會(huì)被提取出來(lái)。當(dāng)傳入為函數(shù)時(shí),所有符合條件的chunk中的模塊都會(huì)被傳入該函數(shù)做計(jì)算,返回true的模塊會(huì)被提取到目標(biāo)chunk。
更多的參數(shù)配置,可以參考這里
2.在webpack4之后的用法:
module.exports = { //... optimization: { splitChunks: { chunks: "async", minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: "~", name: true, cacheGroups: { vendors: { test: /[/]node_modules[/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } } };
splitChunks: 配置一個(gè)分離chunk(代替老版本的CommonsChunkPlugin)
cacheGroups: 自定義配置主要使用它來(lái)決定生成的文件:
test: 限制范圍
name: 生成文件名
priority: 優(yōu)先級(jí)
minSize: number: 最小尺寸必須大于此值,默認(rèn)30000B
minChunks: 其他entry引用次數(shù)大于此值,默認(rèn)1
maxInitialRequests: entry文件請(qǐng)求的chunks不應(yīng)該超過(guò)此值(請(qǐng)求過(guò)多,耗時(shí))
maxAsyncRequests: 異步請(qǐng)求的chunks不應(yīng)該超過(guò)此值
automaticNameDelimiter: 自動(dòng)命名連接符
chunks: 值為”initial”, “async”(默認(rèn)) 或 “all”:
initial: 入口chunk,對(duì)于異步導(dǎo)入的文件不處理
async: 異步chunk,只對(duì)異步導(dǎo)入的文件處理
all: 全部chunk
你的點(diǎn)贊是我持續(xù)分享好東西的動(dòng)力,歡迎點(diǎn)贊!
交流干貨系列文章匯總?cè)缦?,覺(jué)得不錯(cuò)點(diǎn)個(gè)Star,歡迎 加群 互相學(xué)習(xí)。
https://github.com/qq44924588...
我是小智,公眾號(hào)「大遷世界」作者,對(duì)前端技術(shù)保持學(xué)習(xí)愛(ài)好者。我會(huì)經(jīng)常分享自己所學(xué)所看的干貨,在進(jìn)階的路上,共勉!
關(guān)注公眾號(hào),后臺(tái)回復(fù)福利,即可看到福利,你懂的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/108654.html
摘要:哪吒別人的看法都是狗屁,你是誰(shuí)只有你自己說(shuō)了才算,這是爹教我的道理。哪吒去他個(gè)鳥(niǎo)命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰(shuí)和你做朋友太乙真人人是否能夠改變命運(yùn),我不曉得。我只曉得,不認(rèn)命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...
摘要:前言本文基于,主要涉及基本概念基本配置和實(shí)際項(xiàng)目打包優(yōu)化。關(guān)于概念方面參考官網(wǎng),常用配置來(lái)自于網(wǎng)絡(luò)資源,在文末有相關(guān)參考鏈接,實(shí)踐部分基于自己的項(xiàng)目進(jìn)行優(yōu)化配置。同一文件中,修改某個(gè)影響其他。 前言:本文基于weboack4.x,主要涉及webpack4 基本概念、基本配置和實(shí)際項(xiàng)目打包優(yōu)化。關(guān)于概念方面參考官網(wǎng),常用配置來(lái)自于網(wǎng)絡(luò)資源,在文末有相關(guān)參考鏈接,實(shí)踐部分基于自己的項(xiàng)目進(jìn)行...
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門(mén),久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門(mén),久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
閱讀 2661·2021-10-19 11:41
閱讀 2486·2021-09-01 10:32
閱讀 3433·2019-08-29 15:21
閱讀 1879·2019-08-29 12:20
閱讀 1221·2019-08-29 12:13
閱讀 688·2019-08-26 12:24
閱讀 2596·2019-08-26 10:26
閱讀 910·2019-08-23 18:40