📌 提示:css
版本問題html
本文基於
webpack 2.x
版本。webpack 2.x
相比webpack 1.x
有重大改變。因此,若是你的項目中已使用了 webpack 1.x ,本教程的示例將不適用,請慎重。react若是鐵了心要升級 webpack ,請參考 webpack 官方文檔 - 從 v1 遷移到 v2webpack
閱讀建議git
閱讀本文前,建議先閱讀 Webpack 概念 。github
代碼分離是 webpack 中最引人注目的特性之一。web
你能夠把你的代碼分離到不一樣的 bundle 中,而後你就能夠去按需加載這些文件。npm
總的來講, webpack
分離能夠分爲兩類:瀏覽器
對第三方庫(vendor) 和 CSS 進行代碼分離,這些方式有助於實現緩存和並行加載。緩存
你可能也想將你的樣式代碼分離到單獨的 bundle 中,以此使其獨立於應用程序邏輯。這增強了樣式的可緩存性,而且使得瀏覽器可以並行加載應用程序代碼中的樣式文件,避免 FOUC 問題 (無樣式內容形成的閃爍)。
安裝 ExtractTextWebpackPlugin
以下
$ npm install --save-dev extract-text-webpack-plugin
webpack.config.js 中須要按下面進行配置:
const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { // 關於模塊配置 module: { // 模塊規則(配置 loader、解析器等選項) rules: [ { // css 加載 test: /\.css$/, use: ExtractTextPlugin.extract({ use: "css-loader" }) } ] }, // 附加插件列表 plugins: [ // 將樣式文件獨立打包 new ExtractTextPlugin("styles.css") ] };
一個典型的應用程序,因爲框架/功能性需求,會依賴於許多第三方庫的代碼。不一樣於應用程序代碼,這些第三方庫代碼不會頻繁修改。
若是咱們將這些庫(library)中的代碼,保留在與應用程序代碼相獨立的 bundle 中,咱們就能夠利用瀏覽器緩存機制,把這些文件長時間地緩存在用戶機器上。
爲了完成這個目標,無論應用程序代碼如何變化,vendor 文件名中的 hash
部分必須保持不變。學習如何使用 CommonsChunkPlugin
分離 vendor/library 代碼。
webpack.config.js
const webpack = require('webpack'); module.exports = { // 這裏應用程序開始執行 // webpack 開始打包 // 本例中 entry 爲多入口 entry: { main: "./app/index", vendor: "react" }, // webpack 如何輸出結果的相關選項 output: { // 全部輸出文件的目標路徑 // 必須是絕對路徑(使用 Node.js 的 path 模塊) path: path.resolve(__dirname, "dist"), // 「入口分塊(entry chunk)」的文件名模板(出口分塊?) // filename: "bundle.min.js", // filename: "[name].js", // 用於多個入口點(entry point)(出口點?) // filename: "[chunkhash].js", // 用於長效緩存 filename: "[name].[chunkhash:8].js", // 用於長效緩存 }, // 附加插件列表 plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "vendor" // 指定公共 bundle 的名字。 }) ] };
在上面的配置中,
entry
屬性中,將 react 指定爲一個獨立的入口 vendor;output
屬性中,將 filename 指定爲 [name].[chunkhash:8].js,這表示輸出文件的文件名樣式。plugins
列表中引入 CommonsChunkPlugin 插件,用來指定 bundle 。執行 webpack 命令後,webpack 會生成 2 個 bundle 文件,形式如:
main.bef8f974.js vendor.2f1bd4c8.js
雖然前面幾類資源分離,須要用戶預先在配置中指定分離模塊,但也能夠在應用程序代碼中建立動態分離模塊。
這能夠用於更細粒度的代碼塊,例如,根據咱們的應用程序路由,或根據用戶行爲預測。這可使用戶按照實際須要加載非必要資源。
前一節,咱們瞭解了 webpack 能夠將資源拆分爲bundle。接下來,咱們要學習如何異步加載。例如,這容許首先提供最低限度的引導 bundle,並在稍後再異步地加載其餘功能。
webpack 支持兩種類似的技術實現此目的:使用 import()
(推薦,ECMAScript 提案) 和 require.ensure()
(遺留,webpack 特定)。本文只介紹官方推薦的 import()
方式。
ES2015 loader 規範定義了 import()
做爲一種在運行時(runtime)動態載入 ES2015 模塊的方法。
webpack 把 import()
做爲一個分離點(split-point),並把引入的模塊做爲一個單獨的 chunk。 import()
將模塊名字做爲參數並返回一個 Promoise
對象,即 import(name) -> Promise
若是你想要在 Babel 中使用 import
,可是因爲 import() 仍是屬於 Stage 3 的特性,因此你須要安裝/添加 syntax-dynamic-import
插件來避免 parser 報錯。在草案正式成爲規範後,就再也不須要這個插件了。
例:
咱們來定義一個 Clock 組件,動態引入 moment 庫。
首先,安裝 moment 庫。
$ npm install --save-dev moment
JavaScript 代碼:
class Clock extends React.Component { constructor(props) { super(props); this.state = { date: new Date().toLocaleDateString() }; this.click = this.click.bind(this); } click() { // 動態引入import() import('moment') .then(moment => moment().format("MMMM Do YYYY, h:mm:ss a")) .then(str => this.setState({date:str})) .catch(err => console.log("Failed to load moment", err)); } render() { return ( <div> <h2>It is {this.state.date}.</h2> <p onClick={this.click}>Click here to changing the time.</p> </div> ); } }
webpack.config.js
// 關於模塊配置 module: { // 模塊規則(配置 loader、解析器等選項) rules: [ { // 語義解釋器,將 js/jsx 文件中的 es2015/react 語法自動轉爲瀏覽器可識別的 Javascript 語法 test: /\.jsx?$/, include: path.resolve(__dirname, "app"), // 應該應用的 loader,它相對上下文解析 // 爲了更清晰,`-loader` 後綴在 webpack 2 中再也不是可選的 // 查看 webpack 1 升級指南。 loader: "babel-loader", // loader 的可選項 options: { presets: ["es2015", "react"], plugins: ['syntax-dynamic-import'] }, }, ] },
歡迎閱讀其它內容: