尝试将打字稿捆绑到单个文件会产生令人费解的垃圾

问题描述

我试图通过 webpack 将下面显示的 emitPrefixes Typescript 源代码捆绑到一个纯 javascript 文件中,但失败了。

生成的 javascript 代码将在我无法控制的上下文中进行评估,其中已经定义了emit() 函数(在 CouchBase、CouchDB、Cloudant 等基于 JS 的 map reduce 功能中)。结果源必须计算为一个函数。

相同的源代码使用 typescript transpile 成功转换为纯 javascript。但是,我需要 webpack 进行转译,以便将任何导入的模块捆绑到一个 javascript 文件中(转译叶需要完整无缺,但我相信 webpack 可以内联它们)。

但是,即使是这个基本的函数源文件(只导入类型而没有代码),我也无法让 webpack 成功转译。我的怀疑:没有对 emitPrefixes 函数的引用意味着 webpack 正在优化/treeshaking 函数不存在。

有谁知道我需要查看哪些 webpack 设置以防止它优化构建过程并因此删除我的所有代码。我尝试了很多组合,但都没有乐趣。

这是我转译的来源。在这种情况下,它没有导入的值(只有被擦除的类型)。

import type { EmitFunction } from "../../../../../lib/mapreduce";
import type { Word } from "../../types";

declare var emit: EmitFunction<string>;

function emitPrefixes(doc: Word) {
  if (doc?.type === "word") {
    emit(doc.id);
  }
}

emitPrefixes;

添加必要的规则使用ts-loader后,webpack报告prefix.ts文件编译成功。但是,它会将无意义的垃圾输出到 prefix.js 文件中,其中没有任何实际代码。下面的示例显示了编译产生的一些模块元数据。使用 tsconfig.json 中的 "module": "es2015" 甚至缺少此模块元数据,因此 webpack 生成一个空文件。

(() => {
  "use strict";
  var r = { 568: (r,t) => {} },t = {};
  !(function e(s) {
    if (t[s]) return t[s].exports;
    var o = (t[s] = { exports: {} });
    return r[s](o,o.exports,e),o.exports;
  })(568);
})();

相比之下,打字稿转译程序输出这个,它正确地评估为一个函数,这几乎正是我想要的(除了 __esModule 片段)...

Object.defineProperty(exports,"__esModule",{ value: true });
function emitPrefixes(doc) {
    if ((doc === null || doc === void 0 ? void 0 : doc.type) === "word") {
        emit(doc.id);
    }
}
emitPrefixes;

我用来编译源代码的 webpack 程序如下。谁能看到可能需要设置哪些 webpack 配置选项来阻止它优化我的所有代码,因为该函数没有被引用?

import path from "path";
import webpack from "webpack";

function promiseBundledSource(sourcePath: string): Promise<void> {
  const entry = `./${path.basename(sourcePath)}`; //webpack needs explicit relative path
  const context = path.dirname(sourcePath);
  const config = {
    entry,context,output: {
      path: context,filename: entry.replace(/\.ts$/,".js"),},module: {
      rules: [
        { test: /\.ts$/,use: "ts-loader" },{
          test: () => true,sideEffects: true,],};
  return new Promise((resolve,reject) => {
    webpack(config,(err,stats) => {
      if (err) {
        reject(err);
      } else if (stats?.hasErrors()) {
        reject(stats.compilation.errors);
      }
      resolve();
    });
  });
}

async function run() {
  try {
    await promiseBundledSource(path.resolve(
      "./test/lib/testdomain/index/map/prefix.ts"
    ));
  } catch (error) {
    console.log(error);
  }
}

run();

webpack 自动检测的 tsconfig.json 看起来像...

{
  "compilerOptions": {
    "target": "es5","strict": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true
  }
}

以下参考 typescript transpile 操作成功生成正确的代码,但根据需要保留导入的模块,没有内联它们,这就是为什么我需要让 webpack 来处理它...

import fs from "fs";
import {
  transpile,ScriptTarget,ModuleKind,ModuleResolutionKind,} from "typescript";

const sourcePath = "./test/lib/testdomain/index/map/prefix.ts";

const jsSource = transpile(fs.readFileSync(sourcePath).toString(),{
  target: ScriptTarget.ES5,module: ModuleKind.None,moduleResolution: ModuleResolutionKind.NodeJs,noImplicitUseStrict: true,esModuleInterop: false,strict: false,});

console.log(jsSource);

解决方法

我发现配置对象接受 optimisation configuration。将以下属性添加到传递给 webpack 的配置对象会导致从原始函数可读的源代码使其通过输出

它带有很多 webpack 样板文件,我现在正在研究如何删除,但它就在那里!

    optimization: {
      minimize: false,usedExports: false,},

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...