欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在react-router4中進(jìn)行代碼拆分的方法(基于webpack)

 更新時(shí)間:2018年03月08日 10:04:25   作者:AlienZHOU  
這篇文章主要介紹了在react-router4中進(jìn)行代碼拆分的方法(基于webpack),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

前言

隨著前端項(xiàng)目的不斷擴(kuò)大,一個(gè)原本簡(jiǎn)單的網(wǎng)頁(yè)應(yīng)用所引用的js文件可能變得越來(lái)越龐大。尤其在近期流行的單頁(yè)面應(yīng)用中,越來(lái)越依賴一些打包工具(例如webpack),通過(guò)這些打包工具將需要處理、相互依賴的模塊直接打包成一個(gè)單獨(dú)的bundle文件,在頁(yè)面第一次載入時(shí),就會(huì)將所有的js全部載入。但是,往往有許多的場(chǎng)景,我們并不需要在一次性將單頁(yè)應(yīng)用的全部依賴都載下來(lái)。例如:我們現(xiàn)在有一個(gè)帶有權(quán)限的"訂單后臺(tái)管理"單頁(yè)應(yīng)用,普通管理員只能進(jìn)入"訂單管理"部分,而超級(jí)用戶則可以進(jìn)行"系統(tǒng)管理";或者,我們有一個(gè)龐大的單頁(yè)應(yīng)用,用戶在第一次打開頁(yè)面時(shí),需要等待較長(zhǎng)時(shí)間加載無(wú)關(guān)資源。這些時(shí)候,我們就可以考慮進(jìn)行一定的代碼拆分(code splitting)。

實(shí)現(xiàn)方式

簡(jiǎn)單的按需加載

代碼拆分的核心目的,就是實(shí)現(xiàn)資源的按需加載??紤]這么一個(gè)場(chǎng)景,在我們的網(wǎng)站中,右下角有一個(gè)類似聊天框的組件,當(dāng)我們點(diǎn)擊圓形按鈕時(shí),頁(yè)面展示聊天組件。

btn.addEventListener('click', function(e) {
  // 在這里加載chat組件相關(guān)資源 chat.js
});

從這個(gè)例子中我們可以看出,通過(guò)將加載chat.js的操作綁定在btn點(diǎn)擊事件上,可以實(shí)現(xiàn)點(diǎn)擊聊天按鈕后聊天組件的按需加載。而要?jiǎng)討B(tài)加載js資源的方式也非常簡(jiǎn)單(方式類似熟悉的jsonp)。通過(guò)動(dòng)態(tài)在頁(yè)面中添加<scrpt>標(biāo)簽,并將src屬性指向該資源即可。

btn.addEventListener('click', function(e) {
  // 在這里加載chat組件相關(guān)資源 chat.js
  var ele = document.createElement('script');
  ele.setAttribute('src','/static/chat.js');
  document.getElementsByTagName('head')[0].appendChild(ele);
});

代碼拆分就是為了要實(shí)現(xiàn)按需加載所做的工作。想象一下,我們使用打包工具,將所有的js全部打包到了bundle.js這個(gè)文件,這種情況下是沒(méi)有辦法做到上面所述的按需加載的,因此,我們需要講按需加載的代碼在打包的過(guò)程中拆分出來(lái),這就是代碼拆分。那么,對(duì)于這些資源,我們需要手動(dòng)拆分么?當(dāng)然不是,還是要借助打包工具。下面就來(lái)介紹webpack中的代碼拆分。

代碼拆分

這里回到應(yīng)用場(chǎng)景,介紹如何在webpack中進(jìn)行代碼拆分。在webpack有多種方式來(lái)實(shí)現(xiàn)構(gòu)建是的代碼拆分。

import()

這里的import不同于模塊引入時(shí)的import,可以理解為一個(gè)動(dòng)態(tài)加載的模塊的函數(shù)(function-like),傳入其中的參數(shù)就是相應(yīng)的模塊。例如對(duì)于原有的模塊引入import react from 'react'可以寫為import('react')。但是需要注意的是,import()會(huì)返回一個(gè)Promise對(duì)象。因此,可以通過(guò)如下方式使用:

btn.addEventListener('click', e => {
  // 在這里加載chat組件相關(guān)資源 chat.js
  import('/components/chart').then(mod => {
    someOperate(mod);
  });
});

可以看到,使用方式非常簡(jiǎn)單,和平時(shí)我們使用的Promise并沒(méi)有區(qū)別。當(dāng)然,也可以再加入一些異常處理:

btn.addEventListener('click', e => {
  import('/components/chart').then(mod => {
    someOperate(mod);
  }).catch(err => {
    console.log('failed');
  });
});

當(dāng)然,由于import()會(huì)返回一個(gè)Promise對(duì)象,因此要注意一些兼容性問(wèn)題。解決這個(gè)問(wèn)題也不困難,可以使用一些Promise的polyfill來(lái)實(shí)現(xiàn)兼容??梢钥吹剑瑒?dòng)態(tài)import()的方式不論在語(yǔ)意上還是語(yǔ)法使用上都是比較清晰簡(jiǎn)潔的。

require.ensure()

在webpack 2的官網(wǎng)上寫了這么一句話:

require.ensure() is specific to webpack and superseded by import().

所以,在webpack 2里面應(yīng)該是不建議使用require.ensure()這個(gè)方法的。但是目前該方法仍然有效,所以可以簡(jiǎn)單介紹一下。包括在webpack 1中也是可以使用。下面是require.ensure()的語(yǔ)法:

復(fù)制代碼 代碼如下:

require.ensure(dependencies: String[], callback: function(require), errorCallback: function(error), chunkName: String)

require.ensure()接受三個(gè)參數(shù):

  1. 第一個(gè)參數(shù)dependencies是一個(gè)數(shù)組,代表了當(dāng)前require進(jìn)來(lái)的模塊的一些依賴;
  2. 第二個(gè)參數(shù)callback就是一個(gè)回調(diào)函數(shù)。其中需要注意的是,這個(gè)回調(diào)函數(shù)有一個(gè)參數(shù)require,通過(guò)這個(gè)require就可以在回調(diào)函數(shù)內(nèi)動(dòng)態(tài)引入其他模塊。值得注意的是,雖然這個(gè)require是回調(diào)函數(shù)的參數(shù),理論上可以換其他名稱,但是實(shí)際上是不能換的,否則webpack就無(wú)法靜態(tài)分析的時(shí)候處理它;
  3. 第三個(gè)參數(shù)errorCallback比較好理解,就是處理error的回調(diào);
  4. 第四個(gè)參數(shù)chunkName則是指定打包的chunk名稱。

因此,require.ensure()具體的用法如下:

btn.addEventListener('click', e => {
  require.ensure([], require => {
    let chat = require('/components/chart');
    someOperate(chat);
  }, error => {
    console.log('failed');
  }, 'mychat');
});

Bundle Loader

除了使用上述兩種方法,還可以使用webpack的一些組件。例如使用Bundle Loader:

npm i --save bundle-loader

使用require("bundle-loader!./file.js")來(lái)進(jìn)行相應(yīng)chunk的加載。該方法會(huì)返回一個(gè)function,這個(gè)function接受一個(gè)回調(diào)函數(shù)作為參數(shù)。

let chatChunk = require("bundle-loader?lazy!./components/chat");
chatChunk(function(file) {
  someOperate(file);
});

和其他loader類似,Bundle Loader也需要在webpack的配置文件中進(jìn)行相應(yīng)配置。Bundle-Loader的代碼也很簡(jiǎn)短,如果閱讀一下可以發(fā)現(xiàn),其實(shí)際上也是使用require.ensure()來(lái)實(shí)現(xiàn)的,通過(guò)給Bundle-Loader返回的函數(shù)中傳入相應(yīng)的模塊處理回調(diào)函數(shù)即可在require.ensure()的中處理,代碼最后也列出了相應(yīng)的輸出格式:

/*
Output format:
  var cbs = [],
    data;
  module.exports = function(cb) {
    if(cbs) cbs.push(cb);
      else cb(data);
  }
  require.ensure([], function(require) {
    data = require("xxx");
    var callbacks = cbs;
    cbs = null;
    for(var i = 0, l = callbacks.length; i < l; i++) {
      callbacks[i](data);
    }
  });
*/

react-router v4 中的代碼拆分

最后,回到實(shí)際的工作中,基于webpack,在react-router4中實(shí)現(xiàn)代碼拆分。react-router 4相較于react-router 3有了較大的變動(dòng)。其中,在代碼拆分方面,react-router 4的使用方式也與react-router 3有了較大的差別。

在react-router 3中,可以使用Route組件中g(shù)etComponent這個(gè)API來(lái)進(jìn)行代碼拆分。getComponent是異步的,只有在路由匹配時(shí)才會(huì)調(diào)用。但是,在react-router 4中并沒(méi)有找到這個(gè)API,那么如何來(lái)進(jìn)行代碼拆分呢?

react-router 4官網(wǎng)上有一個(gè)代碼拆分的例子。其中,應(yīng)用了Bundle Loader來(lái)進(jìn)行按需加載與動(dòng)態(tài)引入

import loadSomething from 'bundle-loader?lazy!./Something'

然而,在項(xiàng)目中使用類似的方式后,出現(xiàn)了這樣的警告:

Unexpected '!' in 'bundle-loader?lazy!./component/chat'. Do not use import syntax to configure webpack loaders import/no-webpack-loader-syntax
Search for the keywords to learn more about each error.

在webpack 2中已經(jīng)不能使用import這樣的方式來(lái)引入loader了(no-webpack-loader-syntax

Webpack allows specifying the loaders to use in the import source string using a special syntax like this:

var moduleWithOneLoader = require("my-loader!./my-awesome-module");

This syntax is non-standard, so it couples the code to Webpack. The recommended way to specify Webpack loader configuration is in a Webpack configuration file.

我的應(yīng)用使用了create-react-app作為腳手架,屏蔽了webpack的一些配置。當(dāng)然,也可以通過(guò)運(yùn)行npm run eject使其暴露webpack等配置文件。然而,是否可以用其他方法呢?當(dāng)然。

這里就可以使用之前說(shuō)到的兩種方式來(lái)處理:import()或require.ensure()。

和官方實(shí)例類似,我們首先需要一個(gè)異步加載的包裝組件Bundle。Bundle的主要功能就是接收一個(gè)組件異步加載的方法,并返回相應(yīng)的react組件:

export default class Bundle extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mod: null
    };
  }

  componentWillMount() {
    this.load(this.props)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.load !== this.props.load) {
      this.load(nextProps)
    }
  }

  load(props) {
    this.setState({
      mod: null
    });
    props.load((mod) => {
      this.setState({
        mod: mod.default ? mod.default : mod
      });
    });
  }

  render() {
    return this.state.mod ? this.props.children(this.state.mod) : null;
  }
}

在原有的例子中,通過(guò)Bundle Loader來(lái)引入模塊:

import loadSomething from 'bundle-loader?lazy!./About'

const About = (props) => (
  <Bundle load={loadAbout}>
    {(About) => <About {...props}/>}
  </Bundle>
)

由于不再使用Bundle Loader,我們可以使用import()對(duì)該段代碼進(jìn)行改寫:

const Chat = (props) => (
  <Bundle load={() => import('./component/chat')}>
    {(Chat) => <Chat {...props}/>}
  </Bundle>
);

需要注意的是,由于import()會(huì)返回一個(gè)Promise對(duì)象,因此Bundle組件中的代碼也需要相應(yīng)進(jìn)行調(diào)整

export default class Bundle extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mod: null
    };
  }

  componentWillMount() {
    this.load(this.props)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.load !== this.props.load) {
      this.load(nextProps)
    }
  }

  load(props) {
    this.setState({
      mod: null
    });
    //注意這里,使用Promise對(duì)象; mod.default導(dǎo)出默認(rèn)
    props.load().then((mod) => {
      this.setState({
        mod: mod.default ? mod.default : mod
      });
    });
  }

  render() {
    return this.state.mod ? this.props.children(this.state.mod) : null;
  }
}

路由部分沒(méi)有變化

<Route path="/chat" component={Chat}/>

這時(shí)候,執(zhí)行npm run start,可以看到在載入最初的頁(yè)面時(shí)加載的資源如下


而當(dāng)點(diǎn)擊觸發(fā)到/chat路徑時(shí),可以看到

動(dòng)態(tài)加載了2.chunk.js這個(gè)js文件,如果打開這個(gè)文件查看,就可以發(fā)現(xiàn)這個(gè)就是我們剛才動(dòng)態(tài)import()進(jìn)來(lái)的模塊。

當(dāng)然,除了使用import()仍然可以使用require.ensure()來(lái)進(jìn)行模塊的異步加載。相關(guān)示例代碼如下:

const Chat = (props) => (
  <Bundle load={(cb) => {
    require.ensure([], require => {
      cb(require('./component/chat'));
    });
  }}>
  {(Chat) => <Chat {...props}/>}
 </Bundle>
);
export default class Bundle extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mod: null
    };
  }

  load = props => {
    this.setState({
      mod: null
    });
    props.load(mod => {
      this.setState({
        mod: mod ? mod : null
      });
    });
  }

  componentWillMount() {
    this.load(this.props);
  }

  render() {
    return this.state.mod ? this.props.children(this.state.mod) : null
  }
}

此外,如果是直接使用webpack config的話,也可以進(jìn)行如下配置

output: {
  // The build folder.
  path: paths.appBuild,
  // There will be one main bundle, and one file per asynchronous chunk.
  filename: 'static/js/[name].[chunkhash:8].js',
  chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
 },

結(jié)束

代碼拆分在單頁(yè)應(yīng)用中非常常見,對(duì)于提高單頁(yè)應(yīng)用的性能與體驗(yàn)具有一定的幫助。我們通過(guò)將第一次訪問(wèn)應(yīng)用時(shí),并不需要的模塊拆分出來(lái),通過(guò)scipt標(biāo)簽動(dòng)態(tài)加載的原理,可以實(shí)現(xiàn)有效的代碼拆分。在實(shí)際項(xiàng)目中,使用webpack中的import()、require.ensure()或者一些loader(例如Bundle Loader)來(lái)做代碼拆分與組件按需加載。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • React+TypeScript項(xiàng)目中使用CodeMirror的步驟

    React+TypeScript項(xiàng)目中使用CodeMirror的步驟

    CodeMirror被廣泛應(yīng)用于許多Web應(yīng)用程序和開發(fā)工具,之前做需求用到過(guò)codeMirror這個(gè)工具,覺得還不錯(cuò),功能很強(qiáng)大,所以記錄一下改工具的基礎(chǔ)用法,對(duì)React+TypeScript項(xiàng)目中使用CodeMirror的步驟感興趣的朋友跟隨小編一起看看吧
    2023-07-07
  • react.js組件實(shí)現(xiàn)拖拽復(fù)制和可排序的示例代碼

    react.js組件實(shí)現(xiàn)拖拽復(fù)制和可排序的示例代碼

    這篇文章主要介紹了react.js組件實(shí)現(xiàn)拖拽復(fù)制和可排序的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • React實(shí)現(xiàn)二級(jí)聯(lián)動(dòng)(左右聯(lián)動(dòng))

    React實(shí)現(xiàn)二級(jí)聯(lián)動(dòng)(左右聯(lián)動(dòng))

    這篇文章主要為大家詳細(xì)介紹了React實(shí)現(xiàn)二級(jí)聯(lián)動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • React中路由的參數(shù)傳遞路由的配置文件詳解

    React中路由的參數(shù)傳遞路由的配置文件詳解

    路由的配置文件目前我們所有的路由定義都是直接使用Route組件,并且添加屬性來(lái)完成的,路由的參數(shù)傳遞有二種方式這,兩種方式在Router6.x中都是提供的hook函數(shù)的API,?類組件需要通過(guò)高階組件的方式使用,本文通過(guò)示例代碼詳解講解,需要的朋友參考下吧
    2022-11-11
  • react+tsx中使用better-scroll詳解

    react+tsx中使用better-scroll詳解

    這篇文章主要介紹了react+tsx中使用better-scroll,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • React中父子組件通信詳解

    React中父子組件通信詳解

    這篇文章主要介紹了React中父子組件通信詳解,在父組件中,為子組件添加屬性數(shù)據(jù),即可實(shí)現(xiàn)父組件向子組件通信,文章通過(guò)圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08
  • 淺談使用React.setState需要注意的三點(diǎn)

    淺談使用React.setState需要注意的三點(diǎn)

    本篇文章主要介紹了淺談使用React.setState需要注意的三點(diǎn),提出了三點(diǎn)對(duì) React 新手來(lái)說(shuō)是很容易忽略的地方,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • styled-components?性能詳解

    styled-components?性能詳解

    這篇文章主要為大家介紹了styled-components?的性能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • ReactJS中不同類型的狀態(tài)詳解

    ReactJS中不同類型的狀態(tài)詳解

    這篇文章主要為大家介紹了ReactJS中不同類型的狀態(tài)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 減少react組件不必要的重新渲染實(shí)現(xiàn)方法

    減少react組件不必要的重新渲染實(shí)現(xiàn)方法

    這篇文章主要為大家介紹了減少react組件不必要的重新渲染實(shí)現(xiàn)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01

最新評(píng)論