Webpack和Code Splitting

为了更好的演示,接下来我们将使用开发环境下的打包,但是我们不用调用webpack-dev-server这个命令,因为用它启动一个服务器的话,我们就看不到打包生成的内容了。所以,我们要调用webpack命令,然后配置开发环境下的配置去打包,所以我们有必要去配置一个新的命令。

image.png

然后我们去运行npm run dev-build,发现打包生成的dist文件夹,跑到了build目录下,而不是根目录lesson下,这是什么原因呢,其实是因为我们把webpack的配置项放到了build目录下,在打包的过程中,使用的一些配置项,没有进行同步的变更,这就会导致打包生成的文件就放到了build目录下。

我们该如何解决这个问题呢?
  1. 修改webpack.common.js
    我们原来webpack.common.jsoutput的配置是下边这样的,其中path表示的是打包生成的文件存放的位置,__dirname表示的是webpack.common.js这个文件的绝对路径,在这里是lesson/build,'dist'表示的是打包生成的文件存放到跟webpack.common.js这个文件同级的dist目录下
    image.png

    但是我们的目标是打包生成的文件要放到lesson目录下dist目录下,也就是webpack.common.js的上一级目录的同级别dist目录下,所以我们需要修改为下边这样
    image.png

    然后我们再运行打包命令,就会发现打包生成的文件已经存放到lesson目录下的dist目录里了
    image.png
Code Splitting 代码分隔
  • 为什么要有代码分隔呢?先来看下例子,我们把src/index.js代码改为下边这样
    image.png
  • 然后我们运行打包命令npm run dev-build,打包成功,代码正常运行
    image.png
  • 假如我们引入的第三方库 loadsh1M,而我们的业务代码很多也有1M,那么当我们打包之后生产的main.js就有2M这样会造成打包文件过大,加载时间长的问题
  • 通常情况下,第三方库代码是不会变的,而我们的业务代码却经常会变化,这样用户如果想要获得最新的内容就要重新去加载2M的内容
那么我们改怎么去避免这2个问题呢?

我们可以在src目录下,再创建一个文件lodash.js,把loadsh的引入放在这个文件里

image.png

  • 然后我们修改下webpack的入口文件,原来我们的入口文件只有一个,现在新增一个


    image.png
  • 然后再运行打包npm run dev-build,会发现dist目录下生成了 lodash.jsmain.js两个文件,并且dist目录下的index.html里也引入了这两个文件
    image.png
  • 浏览器打开index.html 也可以正常运行,通过这种方式,我们把打包生成的main.js从2M拆分成了两个1M的文件,这个时候用户访问页面,就不需要加载2M的内容了,而是加载两个1M的内容,大家知道浏览器可以并行的加载文件,大量的实践证明,同时加载2个1M的内容可能比加载一个2M的内容要稍微快一点。(不是绝对的)
  • 当我们修改了业务代码index.js ,如果第一种方式,都打包到一个main.js里的这种方式,用户访问代码生成的内容时,需要重新加载2M的内容,如果是我们拆分后的方式,因为lodash是没有变化的,用户访问的时候,直接从浏览器缓存就可以获取,用户只需要重新加载新的生成的main.js 就可以了,也就是说用户只加载了1M的内容
  • 所以第二种方式,可以有效的提升我们页面的展示速度
所以,在一些项目中,我们会通过对代码公用部分进行拆分,来提升项目的运行速度,这种代码的拆分就是Code Splitting
  • 没有Code Splitting也没有任何问题,代码也可以正常运行,但是有了Code Splitting通过对代码的拆分,就可以让我们的代行执行的性能更高一些,用户体验更好一些
在没有webpack之前,我们通过自己对代码的拆分,也可以有效的提升代码的性能,所以Code Splitting本质上是和webpack没有任何关系的,但是现在webpack也有一些插件,可以很方便的帮我们实现Code Splitting的功能。
  • 我们先配置一下webpack.common.js
    image.png
  • 然后删除我们刚才写的lodash.js文件,把lodash的引入,还放入index.js里,然后再把entry还改为一个入口文件
    image.png
image.png
  • 然后我们再打包,就可以看到dist目录下,除了main.js外,还多了一个vendors~main.js;其中main.jsindex.js的业务逻辑,但是并没有lodash;而vendors~main.js里是把 lodash单独提取出来了
    image.png
  • 也就是说,之前我们需要手动的去做分隔,而现在我们通过一个简单的webpack配置,webpack自己就知道了,当遇到这种公用的类库的时候,就会自动的帮我们把这个类库打包生成一个文件,把我们的业务逻辑再拆分成一个文件,自动的帮我们实现了 Code Splitting,这就是为什么我们经常说webpack种的Code Splitting
webpack里的代码分隔,不仅仅可以通过上边那样的配置来帮我们实现,还可以通过另外一种方式实现
  • 我们原来的index.js里的代码是这样的,先引入lodash这个库,然后再调用库里的方法,它是一个同步的执行顺序,先去加载模块,然后再接着往下执行。处理这种同步的逻辑,webpack借助刚才的配置,它会去分析,什么样的模块改给它打包生成一个单独的文件,来做代码分隔。
import _ from 'lodash';

console.log(_.join(['a', 'b', 'c'], '***'))
console.log(_.join(['a','d','e'],'***'))
  • 实际上,我们除了同步的引入一些模块之外,还可以去做异步模块的引入,我们先改下index.js文件
// 同步
// import _ from 'lodash';
// console.log(_.join(['a', 'b', 'c'], '***'))
// console.log(_.join(['a','d','e'],'***'))


// 异步
//一开始这个JS文件里并没有lodash这个库,而是通过JSONP的形式去获取lodash这个库的代码,
//然后获取完之后,then方法会执行,我们引入的lodash这个库,会被放到下划线_这个变量里
function getComponent() {
    return import('lodash').then(({default:_}) => {
        var element = document.createElement('div');
        element.innerHTML = _.join(['LEE', 'YANG'], '-');
        return element
    })
}

//上边,我们定义了一个函数getComponent,这个函数会 异步的加载lodash这个库,
//当加载成功后,它会创建一个div标签,内容是LEE-YANG,然后把div标签返回出来


//执行函数getComponent,这个函数返回的是一个import,而import返回的是一个promise,
//promise里接受的就是返回的element,获取到element之后,把element挂载到body上
getComponent().then(element => {
    document.body.appendChild(element)
})
  • 然后我们再执行打包,会发现生成的文件里,除了main.js还多出一个0.js,main.js是代码分割出的业务逻辑,0.js里就是分割出的lodash的代码
    image.png
  • 也就是说,异步加载的代码,webpack也会做代码的分割
所以,webpack的代码分割,有两种方式。
  1. 借助webpack里的配置,去编写我们的同步的代码,这个配置,结合同步代码,它会去分析我们同步代码里的内容,从而做代码分割
  optimization: {
        splitChunks: {
            chunks:'all'
        }
    },
  1. 即便我们不做optimization的配置,我们写异步载入组件代码,那么异步载入的组件,也会自动的被打包到一个单独的文件里,这也是另外一种形式的代码分割。
总结
  1. Code Splittingwebpack无关,它是一个单独的概念,用来提升整个项目的性能
  2. webpack实现代码分割两种方式;第一,同步代码,做optimization的配置实现代码分割;第二,异步代码,无需做任何配置,打包时会自动进行代码分割;

你可能感兴趣的:(Webpack和Code Splitting)