webpack原理

1.webpack核心概念

entry: 一个可执行模块或库的入口文件。
chunk :多个文件组成的一个代码块,例如把一个可执行模块和它所有依赖的模块组合和一个 chunk 这体现了webpack的打包机制。
loader :文件转换器,例如把es6转换为es5,scss转换为css。
plugin :插件,用于扩展webpack的功能,在webpack构建生命周期的节点上加入扩展hook为webpack加入功能。

2.webpack构建流程

从启动webpack构建到输出结果经历了一系列过程,它们是:

2.1 解析webpack配置参数,合并从shell传入和webpack.config.js文件里配置的参数,生产最后的配置结果。

2.2 注册所有配置的插件,好让插件监听webpack构建生命周期的事件节点,以做出对应的反应。

2.3 从配置的entry入口文件开始解析文件构建AST语法树,找出每个文件所依赖的文件,递归下去。

2.4 在解析文件递归的过程中根据文件类型和loader配置找出合适的loader用来对文件进行转换。

2.5 递归完后得到每个文件的最终结果,根据entry配置生成代码块chunk。

2.6 输出所有chunk到文件系统。

3 概括

webpack是一个打包模块化js的工具,可以通过loader转换文件,通过plugin扩展功能。

4.Webpack的Code Splitting实现按需加载

4.1. 什么是Code Splitting?**

在最开始使用Webpack的时候, 都是将所有的js文件全部打包到一个build.js文件中(文件名取决与在webpack.config.js文件中output.filename), 但是在大型项目中, build.js可能过大, 导致页面加载时间过长. 这个时候就需要code splitting, code splitting就是将文件分割成块(chunk), 我们可以定义一些分割点(split point), 根据这些分割点对文件进行分块, 并实现按需加载.

4.2 Code Splitting的作用?**

  1. 第三方类库单独打包:
    由于第三方类库的内容基本不会改变, 可以将其与业务代码分离出来, 这样就可以最大化的利用浏览器的缓存机制, 减少请求.
  2. 按需加载:
    Webpack支持定义分割点, 通过require.ensure进行按需加载.

4.3 如何进行Code Splitting?**

下面的代码是基于vue-cliwebpack-simple模板生成的演示文档

//cmd
vue init webpack-simple code_spliting_demo

(一) 第三方类库单独打包

我们假设项目中引入了jquery.jsrespond.js, 那么我们可以在webpack.config.js中配置多入口来进行将这两个第三方类库单独打包.

  • webpack.config.js进行配置

    //webpack.config.js
    
    //在entry中添加相应第三方类库
    entry: {
        bundle: './src/main.js',
        vendor: ['./src/lib/jquery-1.10.2.min.js', './src/lib/respond.min.js']
    }
    
     //在plugins中添加CommonChunkPlugin
    plugins:[
        new webpack.optimize.CommonsChunkPlugin({ 
            name: 'vendor',  
            filename: 'vendor.bundle.js'  
        })
    ]
    
    
  • 执行npm run build, 此时dist目录下生成了两个文件, 分别是build.jsvendor.bundle.js

    npm run build后的生成文件
  • index.html中引入, 注意: vendor.bundle.js优先于build.js引入

    //index.html
    
    <script src="/dist/vendor.bundle.js"></script>
    <script src="/dist/build.js"></script>
    
    

(二) 按需加载

我们可以在router中进行配置, 实现组件的按需加载, 在一些单个组件文件较大的时候, 采用按需加载能够减少build.js的体积, 优化加载速度(如果组件的体积较小, 那么采用按需加载会增加额外的http请求, 反倒增加了加载时间)

  • 这里, 我们增加3个组件,分别是A.vue, B.vue, C.vue

    //A.vue
    <template>
        <h1>这里是A.vue组件</h1>
    </template>
    
    //B.vue
    <template>
        <h1>这里是B.vue组件</h1>
    </template>
    
    //C.vue
    <template>
        <h1>这里是C.vue组件</h1>
    </template>
    
    
  • 在路由中进行配置 (注意:这里是为了方便, 是在app.js中添加的路由, 在实际的项目中, 路由应该单独抽取出来)

    //app.js
    
    import Vue from 'vue'
    import App from './App.vue'
    import VueRouter from 'vue-router'
    Vue.use(VueRouter)
    
    //AMD规范的异步载入
    const ComA = resolve => require(['./components/A.vue' ], resolve);
    const ComB = resolve => require(['./components/B.vue' ], resolve);
    const ComC = resolve => require(['./components/C.vue' ], resolve);
    
    const router = new VueRouter({
      routes: [
        {
          name: 'component-A',
          path: '/a',
          component: ComA
        },
        {
          name: 'component-B',
          path: '/b',
          component: ComB
        },
        {
          name: 'component-C',
          path: '/c',
          component: ComC
        }
      ]
    })
    
    new Vue({
      el: '#app',
      router: router,
      render: h => h(App)
    })
    
    
  • webpack.config.js中进行配置output.chunkFilename,

//webpack.config.js

output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'build.js',
    //添加chundkFilename
    chunkFilename: '[name].[chunkhash:5].chunk.js'
}

  • 执行npm run build, 此时dist目录下生成了5个文件, 多出的3个文件,就是对应的A.vue, B.vue, C.vue这三个组件

    npm run build后生成的文件

CMD规范的异步载入

刚才在路由引入的时候, 使用的是AMD规范的异步载入. webpack提供了require.ensure()这个方法实现CMD规范的异步载入. 这同样也是webpack推荐的载入方式.想深入了解ensure, 请点击《webpack代码分离 ensure 看了还不懂,你打我》

  • 下面的代码是使用require.ensure()方法对路由进行配置
//app.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

//AMD风格的异步加载
// const ComA = resolve => require(['./components/A.vue' ], resolve);
// const ComB = resolve => require(['./components/B.vue' ], resolve);
// const ComC = resolve => require(['./components/C.vue' ], resolve);

//CMD风格的异步加载
const ComA = resolve => require.ensure([], () => resolve(require('./components/A.vue')));
const ComB = resolve => require.ensure([], () => resolve(require('./components/B.vue')));
const ComC = resolve => require.ensure([], () => resolve(require('./components/C.vue')));

const router = new VueRouter({
  routes: [
    {
      name: 'component-A',
      path: '/a',
      component: ComA
    },
    {
      name: 'component-B',
      path: '/b',
      component: ComB
    },
    {
      name: 'component-C',
      path: '/c',
      component: ComC
    }
  ]
})

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

  • 执行npm run build后, dist目录下同样生成5个文件

    npm run build后生成的文件

webpack Tree Shaking

随着缩小和树摇动,我们的捆绑现在变小了几个字节!虽然在这个人为的例子中看起来似乎并不多,但是当处理具有复杂依赖树的较大应用程序时,树抖动会导致束大小显着减少。清除无用代码,减少文件体积。

webpack scope hoisting 范围提升

为了检测这些导入链可以在哪里展平并转换为一个内联函数,而不会影响我们的代码。我们不仅保存了额外的函数调用,还访问了模块数组,因此我们的代码运行速度比以前更快。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容

  • 幼儿绘本《小老鼠亚历山大》内容简介: 《小老鼠亚历山大》讲的是一只小老鼠的故事。又是影子!冰箱的影子、葱的影子、长...
    修修宝妈阅读 881评论 0 0
  • 回家过年,亲自带了九几天,结果小家伙就粘上我了,睡觉必须我陪,反正你在他身边他就听话,离开就闹。今天第一天开工,跟...
    鱼塘小八阅读 145评论 0 0
  • 今天,结合上一篇文章的抽奖小游戏,用canvas来写一个小游戏——刮刮乐。首先,用canvas做一个画布,宽高各为...
    单纯的色狼阅读 1,139评论 6 16
  • (2) 很小的时候,她就已经失去了完整的家。在还没有记忆的时候,父亲就用棍子打断了他们之间所有的联系。对于父亲这个...
    彩色的肥皂泡阅读 187评论 0 0