Skip to content

入口和出口

入口

入口通过 entry 字段来配置,入口真正配置的是 chunk,一个 key 就表示一个 chunk。

js
module.exports = {
    entry: {
        // key值将作为chunk的名称,value值作为入口模块的路径
        main: './src/index.js', // 默认情况
        a: './src/a.js',
        bc: ['./src/b.js', './src/c.js'] // 会按顺序执行每一项,并将它们合并为一个文件
    }
}

出口

出口通过 output 字段来配置,主要针对资源列表的文件名和文件路径进行配置。常用配置如下:

ouptut.path

path必须配置一个绝对路径,表示 bundle 输出的位置。

output.filename

filename 决定了每个输出bundle的名称。这些 bundle 将写入到output.path选项指定的目录下。

对于单个入口起点,filename 会是一个静态名称。

js
filename: 'js/bundle.js' // 表示输出到${ouput.path}/js/bundle.js

然而,当通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个 bundle,应该使用以下一种替换方式,来赋予每个 bundle 一个唯一的名称。

使用内部 chunk id:

不推荐使用,因为 id 在开发环境和生产环境中不同

js
filename: '[id].bundle.js'

使用 chunk 名称 + 总 hash 的前五位命名:

js
filename: '[name].[hash:5].bundle.js'

使用 chunk 名称 + chunkhash:

使用 chunkhash 的好处是,只改动一个文件时,不会导致其他文件再次打包。

js
filename: '[name].[chunkhash:5].bundle.js'

ouput 的完整配置如下:

js
const path = require('path');

module.exports = {
    output: {
        path: path.resolve(__dirname, './dist'), // 默认情况
        filename: '[name].[chunkhash:5].bundle.js'
    }
}

最佳实践

下面是一些经典场景:

一个页面一个JS

image-20220706162753362

目录结构:

:::vue

|—— src | |—— pageA 页面A的代码目录 | |—— index.js 页面A的启动模块 | |—— ... | |—— pageB 页面B的代码目录 | |—— index.js 页面B的启动模块 | |—— ... | |—— pageC 页面C的代码目录 | |—— main1.js 页面C的启动模块1 例如:主功能 | |—— main2.js 页面C的启动模块2 例如:实现访问统计的额外功能 | |—— ... | |—— common 公共代码目录 | |—— ...

:::

webpack 配置:

js
module.exports = {
    entry:{
        pageA: "./src/pageA/index.js",
        pageB: "./src/pageB/index.js",
        pageC: ["./src/pageC/main1.js", "./src/pageC/main2.js"]
    },
    output:{
        filename:"[name].[chunkhash:5].js"
    }
}

这种方式适用于页面之间的功能差异巨大、公共代码较少的情况,这种情况下打包出来的最终代码不会有太多重复。

但是如果公共代码过多,会导致项目的打包文件体积过大。

举个🌰:pageA 文件10kb,common 文件5kb,pageA文件依赖于 common 文件,那么 pageA 文件最终打包出来的体积就是10 + 5 = 15kb。

如果有大量的页面文件依赖于 common 文件,可以看出最后打包出来的每个文件中都有大量相同的代码,并且项目的构建包体积巨大。

那为什么不把公共代码单独抽离成一个 chunk 呢?

不可行,因为最终打包出来的文件都是相互独立的,不再具有依赖关系,这样的话,打包出来的 pageA 文件就无法使用公共代码了。

一个页面多个JS

image-20220706163350552

目录结构:

:::vue

|—— src | |—— pageA 页面A的代码目录 | |—— index.js 页面A的启动模块 | |—— ... | |—— pageB 页面B的代码目录 | |—— index.js 页面B的启动模块 | |—— ... | |—— statistics 用于统计访问人数功能目录 | |—— index.js 启动模块 | |—— ... | |—— common 公共代码目录 | |—— ...

:::

webpack 配置:

js
module.exports = {
    entry:{
        pageA: "./src/pageA/index.js",
        pageB: "./src/pageB/index.js",
        statistics: "./src/statistics/index.js"
    },
    output:{
        filename:"[name].[chunkhash:5].js"
    }
}

这种方式适用于页面之间有一些独立、相同的功能,专门使用一个 chunk 抽离这部分 JS,有利于浏览器更好的缓存这部分内容。

为什么不使用多模块入口起点?

js
module.exports = {
    entry:{
        pageA: ["./src/statistics/index.js", "./src/pageA/index.js"],
        pageB: ["./src/statistics/index.js", "./src/pageB/index.js"],
    },
    output:{
        filename:"[name].[chunkhash:5].js"
    }
}

首先这个方法是可行的,但是为什么不使用呢?这是因为多模块入口起点最终会将数组中的每一项都打包成一个文件,让公共代码与其他文件合并到一起,使得这些公共代码难以得到缓存。同时当公共代码量增加时,也会使得项目打包体积剧增。

单页面应用

所谓单页应用,是指整个网站(或网站的某一个功能块)只有一个页面,页面中的内容全部靠 JS 创建和控制。 vue 和 react 都是实现单页应用的利器。

image-20220706163647336

目录结构:

:::vue

|—— src | |—— subFunc1 子功能目录 | |—— ... | |—— subFunc2 子功能目录 | |—— ... | |—— common 公共代码目录 | |—— ... | |—— index.js

:::

webpack 配置

js
module.exports = {
    entry: "./src/index.js",
    output:{
        filename:"index.[hash:5].js"
    }
}