关于代码分割

省略废话。

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)
  });

  实测可行。今天先到这里。


 

  

  

  

原文地址:https://www.cnblogs.com/alan2kat/p/7298933.html