Gur*_*ofu 11 javascript node.js typescript webpack
我很抱歉让您阅读本文而耽误您的时间。我写它是为了回答诸如“你在做什么?”之类的问题。和“你为什么要这样做?”。
该库由大量辅助函数和类组成。在这方面它类似于 lodash(检查lodash的结构),但与 lodash 不同的是,源代码是由多级目录组织的。这对开发人员来说很舒服,但对用户来说可能不舒服:要将所需的功能导入到项目中,用户必须知道它在哪里,例如:
import {
computeFirstItemNumberForSpecificPaginationPage
} from "@yamato-daiwa/es-extensions/Number/Pagination";
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,大部分功能已经导入index.ts并从那里再次导出。现在用户可以获得所需的功能:
import {
computeFirstItemNumberForSpecificPaginationPage
} from "@yamato-daiwa/es-extensions";
Run Code Online (Sandbox Code Playgroud)
请注意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));
Run Code Online (Sandbox Code Playgroud)
但实际上,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
}
},
// ...
Run Code Online (Sandbox Code Playgroud)
我想每个人都明白这是不可接受的,尤其是对于每千字节计数的浏览器应用程序。
如何解决这个问题呢?理想的解决方案(如果存在)不会触及源文件组织,只需更改 TypeScript 配置即可。
我创建了另一个存储库(repro),您可以在其中尝试上面的示例。
npm i命令)。src/index.ts. 它isUndefined从库中导入函数并使用它。npm run ProductionBuildindex.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));
Run Code Online (Sandbox Code Playgroud)
(检查完整文件)
如果从它的单个模块中导入每个函数,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
}
},
// ...
Run Code Online (Sandbox Code Playgroud)
根据假设,根据特定的模块类型,Webpack 可以将代码捆绑到单体结构中,即使这些模块没有被使用,也无法分解和过滤掉一些模块。
现在所有这些(AMD、UMD、CommonJS)都慢慢成为历史的一部分,但我们仍然可以在旧脚本中找到它们。
顺便说一句,消费项目中的 TypeScript 配置也可能会影响(包含在 repro 中)。目前是:
const isStringifiedNonNegativeIntegerOfRegularNotation_1 = require("./Numbers/isStringifiedNonNegativeIntegerOfRegularNotation");
exports.isStringifiedNonNegativeIntegerOfRegularNotation = isStringifiedNonNegativeIntegerOfRegularNotation_1.default;
const separateEach3DigitsGroupWithComma_1 = require("./Numbers/separateEach3DigitsGroupWithComma");
exports.separateEach3DigitsGroupWithComma = separateEach3DigitsGroupWithComma_1.default;
Run Code Online (Sandbox Code Playgroud)
我相信你至少需要设置module以便输出ES6或以上版本。可能的值包括
"es6""es2020""esnext"Tree Shaking 是 JavaScript 上下文中常用的术语,用于消除死代码。它依赖于ES2015模块语法的静态结构,即导入和导出。该名称和概念已通过 ES2015 模块捆绑器汇总而普及。
*注:moduleResolution:可以保留为"node"
然而,正确的module:设置不一定是足够的,或者甚至可能不是所期望的。请参阅以下部分:
webpack 2 版本内置了对 ES2015 模块(别名 Harmony 模块)的支持以及未使用的模块导出检测。新的 webpack 4 版本扩展了此功能,通过“sideEffects”package.json 属性向编译器提供提示,以指示项目中的哪些文件是“纯粹的”,因此如果未使用,可以安全地修剪。
sideEffects:实际上,如果 NOT 指定,默认值似乎是false,所以你不必担心这一点,除非你的 ES6 代码/模块有某些副作用,因此它不应该被摇树。
事实上,sideEffects:false顶层的设置package.json对于在项目中启用 tree-shaking 至关重要,如下所示。
(在不同的项目中lodash,依赖于 ,sideEffects并不重要。这可能是因为库目录结构 和 的差异index.js)。
举个例子,regularloadash不会被 tree shake,因为它不是 es6。要在 lodash 中启用 tree shake,您必须添加这些包并明确使用 es6 版本:
npm i lodash-es
npm i @types/lodash-es
Run Code Online (Sandbox Code Playgroud)
并更改您的导入语句
import * as _ from "lodash"
Run Code Online (Sandbox Code Playgroud)
到
import * as _ from "lodash-es"
Run Code Online (Sandbox Code Playgroud)
请参阅此SE 答案进行讨论。
babel文档关于它自己的“模块”设置说
模块
“AMD”| “嗯”| “systemjs”| “commonjs”| “cjs”| “自动”| false,默认为“自动”。
允许将 ES 模块语法转换为另一种模块类型。请注意,cjs 只是 commonjs 的别名。
将其设置为 false 将保留 ES 模块。仅当您打算将本机 ES 模块发送到浏览器时才使用此选项。如果您使用带有 Babel 的捆绑器,则默认模块:“auto”始终是首选。模块:“自动”
默认情况下,@babel/preset-env 使用调用者数据来确定是否应该转换 ES 模块和模块功能(例如 import())。通常,调用者数据将在捆绑器插件中指定(例如 babel-loader、@rollup/plugin-babel),因此不建议您自己传递调用者数据——传递的调用者可能会覆盖捆绑器插件中的调用者数据,并且在将来如果捆绑程序支持新的模块功能,您可能会得到次优的结果。
所以我想如果你真的需要 babel (并且你可能不需要 webpack4)那么你应该确保“caller”确实指定“false”,这样 ES6 保持为“ES6”。在我成功缩小的设置中,我没有使用“babel”。
"module":"ESNext"编辑:运行作者在 Gihub 上提供的实验编译,但根据标准输出诊断,与“CommonJS”相比,使用没有差异。难道是下面的模块@yamato-daiwa/没有预编译成es6吗?
package.json
{
"private": true,
"scripts": {
"ProductionBuild": "webpack --mode production"
},
"sideEffects":false,
"devDependencies": {
"ts-loader": "9.2.3",
"typescript": "4.3.2",
"webpack": "5.38.1",
"webpack-cli": "4.7.0",
"webpack-node-externals": "3.0.0",
"@yamato-daiwa/es-extensions": "file:../yamato_daiwa-es_extensions/Distributable/"
}
}
Run Code Online (Sandbox Code Playgroud)
"sideEffects":false,已添加。
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"strict": true,
"module": "es2020",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"@SourceFilesRoot/*": ["./src/*"]
}
}
}
Run Code Online (Sandbox Code Playgroud)
模块更改为"module": "es2020",
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "es2020",
"moduleResolution": "Node",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"removeComments": true,
"outDir": "Distributable/",
"declaration": true
},
"include": [ "Source/**/*" ],
}
Run Code Online (Sandbox Code Playgroud)
模块更改为"module": "es2020",
使用原始index.ts文件,不做任何修改
index.js通过上述设置,我得到大小为 39 字节的输出:
(()=>{"use strict";console.log(!1)})();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
251 次 |
| 最近记录: |