typescript 如何在打印脚本库包中导入lodash?

iugsix8n  于 2023-02-05  发布在  TypeScript
关注(0)|答案(1)|浏览(130)

我想把我最常用的通用函数(typescript)集中在一个Util包中,这样我就可以在我的项目中重用它。结果比预期的要困难。这个包不会被发布,所以我真的只对ESM感兴趣。
我可以用一个普通的js-package来完成这个任务,但是现在我把它转换成TS,我遇到了一些问题。
我的问题是,如何从一个外部包导入?我使用各种Lodash函数。但Rollup抱怨它们不存在,和/或必须导出以及。
我已经包含了我放入这个库中的第一个函数,我对TS很陌生,所以不要太在意。-)

[!] RollupError: "now" is not exported by "../../node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/lodash.js", imported by "out-tsc/src/createUid.js".
https://rollupjs.org/troubleshooting/#error-name-is-not-exported-by-module
out-tsc/src/createUid.js (1:9)
1: import { now, random, padStart } from "lodash";
            ^

这是我最新的设置,经历了许多许多变化:

  • 配置 *
    • 包. json**
{
  "name": "@vexna/util",
  "version": "1.0.0",
  "description": "Generic utilities, uses lodash",
  "private": true,
  "type": "module",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "sideEffects": false,
  "scripts": {
    "build": "rimraf dist && tsc && rollup -c rollup.config.js",
    "test": "node test/spec",
    "pretest": "npm run build"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.20.12",
    "@babel/preset-env": "^7.20.2",
    "@open-wc/building-rollup": "^2.2.1",
    "@rollup/plugin-babel": "^6.0.3",
    "@rollup/plugin-node-resolve": "^15.0.1",
    "@types/lodash": "^4.14.191",
    "deepmerge": "^4.3.0",
    "lodash": "^4.17.21",
    "rimraf": "^4.1.2",
    "rollup": "^3.12.1",
    "typescript": "^4.9.5"
  },
  "peerDependencies": {
    "lodash": "^4.17.21"
  },
  "files": [
    "dist"
  ]
}
    • 系统配置json**
{
    "compilerOptions": {
      "target": "es2018",
      "module": "esnext",
      "moduleResolution": "node",
      "noEmitOnError": true,
      "lib": ["es2017"],
      "strict": true,  
      "esModuleInterop": false,
      "outDir": "out-tsc",
      "rootDir": "./",
      "skipLibCheck": true,
      "declaration": true,
      "allowSyntheticDefaultImports": true
    },
    "include": ["./src/**/*.ts"]
}
    • 汇总配置js**
import merge from 'deepmerge';
import { createBasicConfig } from '@open-wc/building-rollup';

const baseConfig = createBasicConfig();
export default merge(baseConfig, {
    input: ['./out-tsc/src/index.js'],
    output: {
        format: "esm",
        exports: "named",
        dir: 'dist',
    },
    external: ['loadash'],
});
  • .巴伯尔中心*
{
    "presets": [["@babel/env", { "modules": false }]]
}
  • 密码 *

我将代码组织如下:

/src
/src/index.ts
/src/createUid.ts

createUid是我放入这个库中的第一个函数,我想把每个函数都放到它自己的文件中(但是如果它们必须都放在一个文件中,那也可以)。

    • 创建用户ID. ts**
import { now, random, padStart } from "lodash"

/**
 * Return a 16-digit unique integer based on the current time (ms) appended
 * with a three-digit random or provided number ("counter").
 * 
 * The id is an integer and consists of two parts:
 *   1) The number of miliseconds is a 13-digit number
 *   2) Appended with a three digit number, that is either:
 *      a) a left-padded number, if provided to the function
 *      b) a random numer
 * 
 * 1675246953915    February 1st, 2023 (today)
 * 9999999999999    November 20th, 2286
 * 9007199254740    June 5th, 2255
 * 9007199254740991 Max. safe integer
 *
 * Note:
 *  - This function won't work after November, 2286.
 *    If it is still in use then consider adding two instead of three digits,
 *    or use a bigint.
 * 
 */

const createUid = (counter?: number): (number|undefined) => {
    let p1 = now() // ms
    let p2 = ""
    
    if (counter == undefined) {
        p2 = padStart(random(0,999).toString(), 3, '0')
    } else if (isNaN(counter)) {
        p2 = padStart(random(0,999).toString(), 3, '0')
    } else {
        let carry = 0
        if (counter > 999) {
            counter = counter % 1000
            carry = Math.trunc(counter / 1000)
        }
        p2 = padStart(counter.toString(),3,'0')
        if (carry > 0) {
            p1 += carry
        }
    }

    // Create the integer
    const retVal = parseInt(`${p1}${p2}`)

    // Check if safe
    if (!Number.isSafeInteger(retVal)) {
        console.error(`Generated id is larger than safe integer ${Number.MAX_SAFE_INTEGER}.`)
        return
    }

    return retVal
}

export { createUid }
    • 索引. ts**
export { createUid } from './createUid'
j8ag8udp

j8ag8udp1#

我发现了两个三个可能的工作场景:
1.使用TSdx,用于TypeScript包开发的零配置CLI。https://tsdx.io/
1.使用lodash-es代替(但是注意链在lodash-es中不起作用!)。解释如下。但是当这个库导入到另一个库中并在那里测试时,仍然会产生Jest错误。
1.使用vitest代替。Vitest与Jest api很大程度上兼容。安装Vitest后,一切都很简单,无需任何配置。唯一要做的是将import { assert, expect, test } from 'vitest'添加到您的测试中。如果您刚刚开始,并且只有简单的测试,它们可以在没有任何更改的情况下工作(YMMV)。此外,**lodash和lodash-es都工作正常。
一个更好的答案是使用"普通" lodash的场景,或者解释为什么lodash-es实际上是一个好东西。从我在各种帖子中读到的,lodash-es有几个缺点(导致更大的捆绑包大小,链不起作用)。
这是一个工作设置(我认为)合理的默认值。这个库是供内部使用的,我运行节点18,所以我在这里使用一个高目标版本。

    • 包. json**
{
  "name": "@vexna/util",
  "version": "1.0.0",
  "description": "Generic utilities, uses lodash",
  "private": true,
  "type": "module",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "sideEffects": false,
  "scripts": {
    "build": "rimraf dist && tsc && rollup -c rollup.config.js",
    "test": "node test/spec",
    "pretest": "npm run build"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@rollup/plugin-typescript": "^11.0.0",
    "@types/lodash-es": "^4.17.6",
    "lodash-es": "^4.17.21",
    "rimraf": "^4.1.2",
    "rollup": "^3.12.1",
    "typescript": "^4.9.5"
  },
  "files": [
    "dist"
  ],
  "peerDependencies": {
    "lodash": "^4.17.21"
  }
}
    • ts配置ts**
{
    "compilerOptions": {
      "module": "es2022",
      "moduleResolution": "node",
      "outDir": "dist",
      "declaration": true,
      "sourceMap": true,
      "esModuleInterop": true,
      "allowSyntheticDefaultImports": true,
      "forceConsistentCasingInFileNames": true,
      "lib": ["es2022", "DOM", "DOM.Iterable"],
      "target": "es2022",
      "skipLibCheck": true,
      "strict": true,
      "exactOptionalPropertyTypes": true,
      "noImplicitAny": true,
      "noImplicitThis": true,
      "checkJs": true
    },
    "include": ["./src/**/*.ts"]
}
    • 汇总配置js**
import typescript from '@rollup/plugin-typescript'
const input = ["src/index.ts"]

export default [
    {
        input,
        plugins: [
            typescript()],
        output: [
            {
                dir: "dist",
                sourcemap: true,
            }
        ],
        external: ['lodash-es'],
    }
]

输出已经完全外部化了lodash,所以非常小的包!作为预防措施,我添加了"lodash":"^4.17.21"到"peerDependencies"。这有点奇怪,因为它与devDependencies(使用-es)不匹配,但这看起来很好。YMMV。
在库代码中,可以导入lodash函数,如下所示:

import { now, random, padStart } from "lodash-es"

使用此库的项目必须具有lodash,并且可以按如下方式导入:

import { createUid } from '@vexna/util'

相关问题