如何为库设置TypeScript编译器,以便Webpack将依赖项目中未使用的模块截断?

学科库初步说明

我很抱歉让您阅读本文而耽误您的时间。我写它是为了回答诸如“你在做什么?”之类的问题。和“你为什么要这样做?”。

该库由大量辅助函数和类组成。在这方面它类似于 lodash(检查lodash的结构),但与 lodash 不同的是,源代码是由多级目录组织的。这对开发人员来说很舒服,但对用户来说可能不舒服:要将所需的功能导入到项目中,用户必须知道它在哪里,例如:

import { 
  computeFirstItemNumberForSpecificPaginationPage
} from "@yamato-daiwa/es-extensions/Number/Pagination";

为了解决这个问题,大部分功能已经导入index.ts并从那里再次导出。现在用户可以获得所需的功能:

import { 
  computeFirstItemNumberForSpecificPaginationPage 
} from "@yamato-daiwa/es-extensions";

请注意index.ts(将由 TypeScript 编译为index.js)中的所有函数均适用于 BrowserJS 和 NodeJS。尤其是针对 BrowserJS 的功能在BrowserJS.ts,尤其是针对 NodeJS 的功能NodeJS.ts(目前几乎是空的,但重新导出方法是相同的)。

此外,在这个问题得到解决之前,我将编译后的 JavaScript 包含到库存储库(Distributable目录)中。

问题

从现在开始,@yamato-daiwa/es-extensions 是图书馆,任何依赖它的项目都是消费项目

我预计消费项目的所有未使用的函数/类都将被Webpack 优化切断。例如,在下面的情况下,我预计该isUndefined功能只会留在 Webpack 包中:

import { isUndefined } from "@yamato-daiwa/es-extensions"

const test: string | undefined = "ALPHA";
console.log(isUndefined(test));

但实际上,Webpack 离开index.js了库中的所有内容。我美化了 Webpack 构建的缩小版 JavaScript;它像是:

(() => {
    "use strict";
    var e = {
            5272: (e, t) => {
                Object.defineProperty(t, "__esModule", {
                    value: !0
                }), t.default = function(e, t) {
                    for (const [a, n] of e.entries())
                        if (t(n)) return a;
                    return null
                }
            },
            7684: (e, t) => {
                Object.defineProperty(t, "__esModule", {
                    value: !0
                }), t.default = function(e, t) {
                    const a = [];
                    return e.forEach(((e, n) => {
                        t(e) && a.push(n)
                    })), a
                }
            },
  // ...

我想每个人都明白这是不可接受的,尤其是对于每千字节计数的浏览器应用程序。

如何解决这个问题呢?理想的解决方案(如果存在)不会触及源文件组织,只需更改 TypeScript 配置即可。

再现

我创建了另一个存储库(repro),您可以在其中尝试上面的示例。

实验流程

  1. 通过 VCS 获取此存储库
  2. 像往常一样安装依赖项(npm i命令)。
  3. 检查src/index.ts. 它isUndefined从库中导入函数并使用它。
  4. npm run ProductionBuild
  5. 使用 beautifier.ioindex.js等工具美化输出。您将看到整个库都已捆绑,而您只需要inUndefined捆绑即可。

关于原因的沉思

第一个候选原因是使用reexportint模式,确切地说是Source/index.ts、Source/BrowserJS.ts和Source/ NodeJS。编译后的index.js样子:

import { isUndefined } from "@yamato-daiwa/es-extensions"

const test: string | undefined = "ALPHA";
console.log(isUndefined(test));

(检查完整文件)

如果从它的单个模块中导入每个函数,import isUndefined from "@yamato-daiwa/es-extensions/TypeGuards/isUndefined"而不是import { isUndefined } from "@yamato-daiwa/es-extensions",则不会输出冗余代码。但正如我已经说过的,这个解决方案是不可接受的,因为图书馆用户必须知道在哪里isUndefined组织了其他功能。

另一个原因可能是输出模块类型。目前它是一个CommonJS. 这是
tsconfig.json图书馆的:

(() => {
    "use strict";
    var e = {
            5272: (e, t) => {
                Object.defineProperty(t, "__esModule", {
                    value: !0
                }), t.default = function(e, t) {
                    for (const [a, n] of e.entries())
                        if (t(n)) return a;
                    return null
                }
            },
            7684: (e, t) => {
                Object.defineProperty(t, "__esModule", {
                    value: !0
                }), t.default = function(e, t) {
                    const a = [];
                    return e.forEach(((e, n) => {
                        t(e) && a.push(n)
                    })), a
                }
            },
  // ...

根据假设,根据特定的模块类型,Webpack 可以将代码捆绑到单体结构中,即使这些模块没有被使用,也无法分解和过滤掉一些模块。

现在所有这些(AMD、UMD、CommonJS)都慢慢成为历史的一部分,但我们仍然可以在旧脚本中找到它们。

javascript.info

顺便说一句,消费项目中的 TypeScript 配置也可能会影响(包含在 repro 中)。目前是:

const isStringifiedNonNegativeIntegerOfRegularNotation_1 = require("./Numbers/isStringifiedNonNegativeIntegerOfRegularNotation");
exports.isStringifiedNonNegativeIntegerOfRegularNotation = isStringifiedNonNegativeIntegerOfRegularNotation_1.default;
const separateEach3DigitsGroupWithComma_1 = require("./Numbers/separateEach3DigitsGroupWithComma");
exports.separateEach3DigitsGroupWithComma = separateEach3DigitsGroupWithComma_1.default;

以上是如何为库设置TypeScript编译器,以便Webpack将依赖项目中未使用的模块截断?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>