美文网首页
15 JS代码分离 Code Splitting

15 JS代码分离 Code Splitting

作者: 辣瓜瓜 | 来源:发表于2019-12-24 00:38 被阅读0次

js代码分离

SPA单页面应用的最大一个问题就是首屏加载的非常慢,原因就是webpack打包后生成的是一个boundle.js,一个boundle.js的好处是减少了网络请求,但是规模较大的项目一个boundle.js文件甚至几十上百M,从而造成请求非常慢。

Code Splitting就主要解决这个问题。

Code Splitting是webpack打包时用到的==重要的优化特性之一==,此特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。

有三种常用的代码分离方法:
  • 入口起点(entry points):使用entry配置手动地分离代码。
  • 防止重复(prevent duplication):使用 SplitChunksPlugin去重和分离 chunk。
  • 动态导入(dynamic imports):通过模块的内联函数调用来分离代码。

单页面中第一种几乎不会用到,第二种也几乎不会用。

手动配置多入口

  1. 在webpack配置文件中配置多个入口

    entry: {
      main: './src/main.js',
      other: './src/other.js'
    },
    output: {
      // path.resolve() : 解析当前相对路径的绝对路径
      // path: path.resolve('./dist/'),
      // path: path.resolve(__dirname, './dist/'),
      path: path.join(__dirname, '..', './dist/'),
      // filename: 'bundle.js',
      filename: '[name].bundle.js',
      publicPath: '/'
    },
    
  2. 在main.js和other.js中都引入同一个模块,并使用其功能

    main.js

    import $ from 'jquery'
    
    $(function() {
      $('<div></div>').html('main').appendTo('body')
    })
    

    other.js

    import $ from 'jquery'
    
    $(function() {
      $('<div></div>').html('other').appendTo('body')
    })
    
  3. 修改package.json的脚本,添加一个使用dev配置文件进行打包的脚本(目的是不压缩代码检查打包的bundle时更方便)

    "scripts": {
        "build": "webpack --config ./build/webpack.prod.js",
        "dev-build": "webpack --config ./build/webpack.dev.js"
    }
    
  4. 运行npm run dev-build,进行打包

  5. 查看打包后的结果,发现other.bundle.js和main.bundle.js都同时打包了jQuery源文件

这种方法存在一些问题:

  • 如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中。
  • 这种方法不够灵活,并且不能将核心应用程序逻辑进行动态拆分代码。

代码分割 抽取公共代码

Webpack v4以上使用的插件为SplitChunksPlugin,以前使用的CommonsChunkPlugin已经被移除了,最新版的webpack只需要在配置文件中的optimization节点下添加一个splitChunks属性即可进行相关配置

  1. 修改webpack配置文件

    optimization: {
        splitChunks: {
          chunks: 'all'
        }
    },
    
  2. 运行npm run dev-build重新打包

  3. 查看dist目录

    main.boundle.js
    other.boundle.js
    cvendors~main~other.boundle.js
    
  4. 查看vendors~main~other.bundle.js,其实就是把都用到的jQuery打包到了一个单独的js中

动态导入 (懒加载)

webpack4默认是允许import语法动态导入的,但是需要babel的插件支持;
最新版babel的插件包为:@babel/plugin-syntax-dynamic-import,以前老版本不是@babel开头,已经无法使用,需注意;

动态导入最大的好处是实现了懒加载,用到哪个模块才会加载哪个模块,(比如点击时使用到了jq才会去加载),可以提高SPA应用程序的首屏加载速度,Vue、React、Angular框架的路由懒加载原理一样。

  1. 安装babel插件

    npm install -D @babel/plugin-syntax-dynamic-import

  2. 修改.babelrc配置文件,添加@babel/plugin-syntax-dynamic-import插件

    {
      "presets": ["@babel/env"],
      "plugins": [
        "@babel/plugin-proposal-class-properties",
        "@babel/plugin-transform-runtime",
        "@babel/plugin-syntax-dynamic-import"
      ]
    }
    
  3. 将jQuery模块进行动态导入
    相当于promise是一个异步的操作,返回的是promised对象,import可以写在条件判断中

    function getComponent() {
      return import('jquery').then(({ default: $ }) => {
        return $('<div></div>').html('main')
      })
    }
    
  4. 给某个按钮添加点击事件,点击后调用getComponent函数创建元素并添加到页面

    window.onload = function () {
      document.getElementById('btn').onclick = function () {
        getComponent().then(item => {
          item.appendTo('body')
        })
      }
    }
    

静态导入 vs 动态导入

  • 静态导入: 写在顶级作用域的import export
  • 动态导入: require 或者动态导入 (懒加载)

静态导入的问题:
在单页面应用中,大部分是模块化开发,当用户访问首页的时候,会加载全部的打包好的文件,使得首屏速度很慢,很影响性能;

从性能优化的角度考虑,上面的代码,如果在点击或其他操作时候才去加载jq的相关文件,而不是一开始就全部加载,性能会提高很多,首屏打开速度大大提升。











相关文章

网友评论

      本文标题:15 JS代码分离 Code Splitting

      本文链接:https://www.haomeiwen.com/subject/fljkdctx.html