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 范围提升

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



作者:好奇男孩
链接:https://www.jianshu.com/p/37ff752d0f97
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自blog.csdn.net/sinat_17775997/article/details/89413142