webpack分包

  • 前语
  • 一、多进口打包
  • 二、提取公共模块
  • 三、动态导入模块
  • 四、魔法注释

前语

通过webpack完成前端项目整体模块化的优势当然很明显,可是它相同存在一些坏处,那便是咱们项目中的一切代码终究都被打包到了一同,假如咱们使用非常复杂,模块非常多的话,咱们的打包成果就会特别的大。
而事实状况是,大多数时分,咱们在使用开端工作时,并不是咱们一切的模块都需求加载进来的,可是这些模块又被全部打包到一同,咱们需求任何一个模块,都需求把整体加载往后才干使用,而咱们的使用有一般是运转在浏览器端,那就意味着咱们会糟蹋掉许多的流量和带宽。
那更合理的计划便是把咱们的打包成果按照必定的规则去别离到多个bundle中,然后依据咱们使用的运转需求,按需加载这些模块。这样咱们就能大大提高使用的响应速度与运转效率。
现在webpack完成分包的方式主要有以下两种:
第一种是依据咱们的事务去装备不同的打包进口,也便是咱们会有多个打包进口一起打包,输出多个打包成果。
第二种便是选用ESM的动态导入功能,去完成模块的按需加载,这个时分webpack会把咱们动态加载的模块独自输出到一个bundle中。

一、多进口打包

现有如下文件结构:

webpack分包

分为album页面内容、index.html页面内容、global.css公共样式、fetch.js是一个公共的供给请求api的模块,测验为这个事例创立多个打包进口。

const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
   mode:"none",
   entry:{ // 将entry装备成一个对象,来设置多个打包进口
       index:"./src/index.js",
       album:"./src/album.js"
   },
   output:{// 修正输出文件名
       filename:"[name].bundle.js" // 通过[name]这种占位符的方式动态输出文件名,[name]终究就会替换成打包进口称号
   },
   module:{
       rules:[
           {
               test:/.css$/,
               use:[
                   "style-loader",
                   "css-loader"
               ]
           }
       ]
   },
   plugins:[
       new CleanWebpackPlugin(),
       new HtmlWebpackPlugin({
           title:"Multi Entry",
           template:"./src/index.html",
           filename:"index.html"
       }),
       new HtmlWebpackPlugin({
           title:"Multi Entry",
           template:"./src/album.html",
           filename:"album.html"
       })
   ]
}

打包成果:

webpack分包

可是生成的html中会载入两个打包后的bundle.js,咱们只期望其引入本身的bundle.js
webpack分包

在HtmlWebpackPlugin通过chunks特点指定载入的bundle.js文件

new HtmlWebpackPlugin({
   title:"Multi Entry",
    template:"./src/index.html",
    filename:"index.html",
    chunks:['index']
}),
new HtmlWebpackPlugin({
    title:"Multi Entry",
    template:"./src/album.html",
    filename:"album.html",
    chunks:['album']
})

此时再打包,生成的html就只会载入本身需求的bundle.js了。

二、提取公共模块

在index.js和alubm.js中都有对公共模块的引入

import fetchApi from './fetch'
import './global.css'
import './index.css'

然后履行打包就会生成一个包括这些公共模块的js文件。可是我这没有生成,很头疼。找了很久,成果发现需求加上一个name特点。

optimization: {
    splitChunks: {
        chunks: 'all'
    }
}

这样就能成功将公共模块的js文件提取出来了,生成了一个common.bundle.js。

三、动态导入模块

假定咱们有一个单页面使用,依据需求来载入模块。

// posts模块
export default () => {
  const posts = document.createElement('div')
  posts.className = 'posts'
  posts.innerHTML = '<h2>Posts</h2>'
  return posts
}
import posts from './posts/posts'
import album from './album/album'//结构与posts一样
const render = () => {
  const hash = window.location.hash || '#posts'
  const mainElement = document.querySelector('.main')
  mainElement.innerHTML = ''
  if (hash === '#posts') {
    mainElement.appendChild(posts())
  } else if (hash === '#album') {
    mainElement.appendChild(album())
  }
}
render()
window.addEventListener('hashchange', render)

咱们在打包进口中一起导入了ablum模块和posts模块,当锚点发生变化时,依据锚点的值去决定要显示哪个组件,这里就会存在糟蹋的可能性,假如用户翻开使用后仅仅访问了其间一个页面,另外一个页面所对应的模块的加载便是糟蹋,所以选用动态导入的方式就不会有糟蹋了。

动态导入便是选用ES Module的动态导入。

const render = () => {
  const hash = window.location.hash || '#posts'
  const mainElement = document.querySelector('.main')
  mainElement.innerHTML = ''
  if (hash === '#posts') {
    import('./posts/posts').then(({ default: posts }) => {
      mainElement.appendChild(posts())
    })
  } else if (hash === '#album') {
    import('./album/album').then(({ default: album }) => {
      mainElement.appendChild(album())
    })
  }
}
render()

履行打包,打包成果:

webpack分包

假如命名一致,会打包到一个文件中,否则是多个文件。