關於代碼分割


省略廢話。

1.ES6之前兩個比較流行的模塊機制CommonJS和AMD。CommonJS模塊就是對象,加載模塊時加載的是拷貝;而ES6加載的是對export的變量的引用。

2.ES6模塊不是對象,使用可出現在模塊頂層任何位置的export顯式指定輸出的代碼(變量、函數、class):

export:

  export var name='microsoft'; 

---another example 推薦在底部用{}輸出需要的代碼

  var  value_x='microsoft';    

  export { value_x,value_y ,method_y};

     如果想給export的變量改名字,可以使用as

  export { value_x,value_y  as  alias_name ,method_y};

  export function fn_name(){};

      *export的變量是動態綁定其所在模塊的。比如setTimeout后改變value_x的值,接收者得到的value_x也會定時改變。

import:

  import { value_x,mothed_y } from strUrl;

  value_x,mothed_y的名稱必須與 strUr 中export的名稱相同。如果想給import的變量改名字,可以使用as

  import { value_x as value_z,mothed_y } from strUrl;

  *import具有提升效果。

  *import會執行所加載的模塊。

  *import命令中接收的變量名要在{}中

整體加載:

  可以用*指定一個對象,所有import的東西都加載到這對象上:

  import * as mod from strUrl;

  var x=mod.value_x;

  也可以用module命令:

  module mod from strUrl;

  var x=mod.value_x;

export default:

  上面說了import命令中加載的變量名稱要和export輸出的名稱一致,我們也可以在輸出模塊中用export default指定默認輸出:

    export default function(){};  --比如一個匿名函數或對象

  然后自己在加載的時候給接收的函數/對象命名:

    import customName from strUrl;

    *import后不用加{}。因為export default在模塊中只能使用一次,只輸出一個變量/方法/class。

    *無論export default輸出的是不是匿名,都視為匿名。

    *除了默認輸出外還想加載其他變量:

    import customName,{value_x,method_x} from strUrl;

    *export * from strOtherMod 命令,先加載strOtherMod 再將其輸出,*會忽略strOtherMod 的默認輸出。

-------------------------------------------------------------分割線----------------------------------------------------------------

在實際生產中常用到webpack。webpack有code-spliting功能,允許我們分割代碼,實現模塊靜態/動態加載。

webpack有三種代碼分離方法:

1.打包時在entry部署要打包幾個chunk。

2.使用CommonsChunkPlugin插件去重和分離chunk。

3.Dynamic Imports:通過模塊的內聯函數動態導入代碼(重點)。

 import:

  webpack使用import語法來實現模塊的動態導入,這里import會生成一個promise對象:import('path/to/module') -> Promise,以下是官方例子:

    if ( module.hot ) {
      import('lodash').then(_ => {
      // Do something with lodash (a.k.a '_')...
      })
    }    --記住,then()中return的變量會作為后續then(param)的參數prama

  在這里,import()會被webpack當作一個代碼分割點(split point),所要import的文件會被另外打包成一個chunk,等需要時再加載。

  使用時報錯:

    Module build failed: SyntaxError: D:/te/src/js/third.js: 'import' and 'export' may only appear at the top level (251:1)

 

    根據webpack官網案例,案例中能成功,這里的報錯有說是webpack並沒有按正確的語法來對待import,有網友說需要插件如:syntax-dynamic-import,

  也有說babel的presets要加latest和es2015,我的babel配置和presets是沒問題的,估計是插件,這里留下這個問題。

  lazy-loading(需要時加載):  

    button.onclick = e => import(/* webpackChunkName: "print" */ './print')

              .then(module => {
                var print = module.default;
                 print();
           });

    官網例子很淺顯,觸發某個事件的時候再import模塊,就像圖片廊等用戶滾動的時候再加載更多圖片一個道理。

CommonJS:

  webpack也支持commonjs,commonjs模塊主要分為三塊:模塊引用require、模塊定義exports、模塊標志module(即模塊本身)。

  在服務器端,require(strUrl)是同步的,由於服務器在本地硬盤讀取文件,速度很快,故而沒問題,但瀏覽器端必須使用異步方法,因而有了AMD/CMD。

    webpack實現的commonjs有:

  1.require(strUrl);   --同步

  2.require.resolve(strUrl)  --檢索(或者說返回)strUrl模塊的id。

  3.require.cache(module.id)  

    --模塊被require后只執行一次,也只返回一個exports對象。官網表示,在某些極端情況會需要多次require同一個模塊,也即重復執行某個require(獲取module並執行回調);

    因而可以執行那面的代碼:

      delete require.cache[require.resolve("dependency")];

    大意是刪除原本加載完的模塊的id,讓js可以再次加載模塊並執行回調。

  4.require.ensure([dependencies],callback(require),chunkName_str);

  --這是webpack的require api里唯一一個可以實現異步加載的函數。

    第一個參數是模塊依賴的名稱數組(這些依賴是執行callback需要的);

    第二個是回調,qi,其形參require允許我們執行進一步的require.ensure;

    第三個是chunk名稱,require.ensure的代碼會被打包到另一個chunk伺機加載,該參數就是這個chunk的名稱。同名的chunk會被打包在一起。

//------------------------------------------------------------------------分割線---------------------------------------------------------------------------------------------------------------

 

使用vue的異步組件:

  vue定義全局組件的方式是:

    Vue.component('name',optionObj);

  文檔說,“Vue.js 允許將組件定義為一個工廠函數,動態地解析組件的定義”:

--------------------------------------引用-------------------------------------------

    Vue.component('async-example', function (resolve, reject) {
      setTimeout(function () {
          // Pass the component definition to the resolve callback
          resolve({
          template: '<div>I am async!</div>'
          })
        }, 1000)
      })

  工廠函數接收一個 resolve 回調,在收到從服務器下載的組件定義時調用。也可以調用 reject(reason) 指示加載失敗。

  這里 setTimeout 只是為了演示。怎么獲取組件完全由你決定。

---------------------------------------------------------------------------------------------

  所以確定第一點:vue中異步組件的實現,是把 Vue.component('name',optionObj)中optionObj替換為一個函數,

  這個函數執行異步任務,獲取組件的定義並執行回調。

  第二點是:當需要用到異步組件的時候,往往是模塊已經足夠大,這時候往往是使用.vue單文件組件,自包含template、css和其他options。

  我個人對文檔中的方法不太能理解:  

     Vue.component('async-webpack-example', function (resolve) {
      // 這個特殊的 require 語法告訴 webpack
      // 自動將編譯后的代碼分割成不同的塊,
      // 這些塊將通過 Ajax 請求自動下載。
      require(['./my-async-component'], resolve)
    })

    后來有人解釋說;這總方式是可以的,但省略了一些生產上的具體代碼,實際上應該這樣寫:

        

  <script>
    import Vue from 'vue'

    const name_ = Vue.component('name', function (resolve) {
      require(['./service-search.vue'], resolve)
    })

    export default{
      data(){
      return {}
      },
      methods: {},
      components: {
      name: name_       //也可以更簡便地將function (resolve){}替換這里的name_
      }
    }
</script>

vue路由:

  另外,我也在學習vue路由時使用異步組件,用的是github上同行的寫法:

  import Vue from 'vue'
  import App from './App.vue'
  import VueRouter from 'vue-router'
  import VueResource from 'vue-resource'
  import Vuex from 'vuex'

  const setting = resolve => require.ensure([], () => resolve(require('./components/setting.vue')), 'setting'); 

  Vue.use(VueRouter);
  Vue.use(VueResource);
  Vue.use(Vuex);

  const routes=[
    {path:'/setting',component:setting},
  ];
  const router = new VueRouter({
    mode: 'history',
    base: __dirname,
    routes
  })

  new Vue({
    router,
    store,
    el: '#app',
    render: h => h(App)
  });

  實測可行。今天先到這里。


 

  

  

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM