feat(cli): generate js binding to avoid dynamic require logic
This commit is contained in:
parent
b7a98d2c7a
commit
179f20a7c5
9 changed files with 325 additions and 70 deletions
|
@ -1,12 +1,13 @@
|
|||
import { execSync } from 'child_process'
|
||||
import { join, parse, sep } from 'path'
|
||||
|
||||
import chalk from 'chalk'
|
||||
import { Instance } from 'chalk'
|
||||
import { Command, Option } from 'clipanion'
|
||||
import toml from 'toml'
|
||||
|
||||
import { getNapiConfig } from './consts'
|
||||
import { debugFactory } from './debug'
|
||||
import { createJsBinding } from './js-binding-template'
|
||||
import { getDefaultTargetTriple, parseTriple } from './parse-triple'
|
||||
import {
|
||||
copyFileAsync,
|
||||
|
@ -18,6 +19,7 @@ import {
|
|||
} from './utils'
|
||||
|
||||
const debug = debugFactory('build')
|
||||
const chalk = new Instance({ level: 1 })
|
||||
|
||||
export class BuildCommand extends Command {
|
||||
static usage = Command.Usage({
|
||||
|
@ -26,23 +28,57 @@ export class BuildCommand extends Command {
|
|||
|
||||
static paths = [['build']]
|
||||
|
||||
appendPlatformToFilename = Option.Boolean(`--platform`, false)
|
||||
appendPlatformToFilename = Option.Boolean(`--platform`, false, {
|
||||
description: `Add platform triple to the .node file. ${chalk.green(
|
||||
'[name].linux-x64-gnu.node',
|
||||
)} for example`,
|
||||
})
|
||||
|
||||
isRelease = Option.Boolean(`--release`, false)
|
||||
isRelease = Option.Boolean(`--release`, false, {
|
||||
description: `Bypass to ${chalk.green('cargo --release')}`,
|
||||
})
|
||||
|
||||
configFileName?: string = Option.String('--config,-c')
|
||||
configFileName?: string = Option.String('--config,-c', {
|
||||
description: `napi config path, only JSON format accepted. Default to ${chalk.underline(
|
||||
chalk.green('package.json'),
|
||||
)}`,
|
||||
})
|
||||
|
||||
cargoName?: string = Option.String('--cargo-name')
|
||||
cargoName?: string = Option.String('--cargo-name', {
|
||||
description: `Override the ${chalk.green(
|
||||
'name',
|
||||
)} field in ${chalk.underline(chalk.yellowBright('Cargo.toml'))}`,
|
||||
})
|
||||
|
||||
targetTripleDir = Option.String('--target', process.env.RUST_TARGET ?? '')
|
||||
targetTripleDir = Option.String('--target', process.env.RUST_TARGET ?? '', {
|
||||
description: `Bypass to ${chalk.green('cargo --target')}`,
|
||||
})
|
||||
|
||||
features?: string = Option.String('--features')
|
||||
features?: string = Option.String('--features', {
|
||||
description: `Bypass to ${chalk.green('cargo --features')}`,
|
||||
})
|
||||
|
||||
dts?: string = Option.String('--dts')
|
||||
dts?: string = Option.String('--dts', 'index.d.ts', {
|
||||
description: `The filename and path of ${chalk.green(
|
||||
'.d.ts',
|
||||
)} file, relative to cwd`,
|
||||
})
|
||||
|
||||
cargoFlags = Option.String('--cargo-flags', '')
|
||||
cargoFlags = Option.String('--cargo-flags', '', {
|
||||
description: `All the others flag passed to ${chalk.yellow('cargo')}`,
|
||||
})
|
||||
|
||||
cargoCwd?: string = Option.String('--cargo-cwd')
|
||||
jsBinding = Option.String('--js', 'index.js', {
|
||||
description: `Path to the JS binding file, pass ${chalk.underline(
|
||||
chalk.yellow('false'),
|
||||
)} to disable it`,
|
||||
})
|
||||
|
||||
cargoCwd?: string = Option.String('--cargo-cwd', {
|
||||
description: `The cwd of ${chalk.underline(
|
||||
chalk.yellow('Cargo.toml'),
|
||||
)} file`,
|
||||
})
|
||||
|
||||
destDir = Option.String({
|
||||
required: false,
|
||||
|
@ -84,7 +120,7 @@ export class BuildCommand extends Command {
|
|||
stdio: 'inherit',
|
||||
cwd,
|
||||
})
|
||||
const { binaryName } = getNapiConfig(this.configFileName)
|
||||
const { binaryName, packageName } = getNapiConfig(this.configFileName)
|
||||
let dylibName = this.cargoName
|
||||
if (!dylibName) {
|
||||
let tomlContentString: string
|
||||
|
@ -198,10 +234,18 @@ export class BuildCommand extends Command {
|
|||
debug(`Write binary content to [${chalk.yellowBright(distModulePath)}]`)
|
||||
await copyFileAsync(sourcePath, distModulePath)
|
||||
|
||||
await processIntermediateTypeFile(
|
||||
const idents = await processIntermediateTypeFile(
|
||||
intermediateTypeFile,
|
||||
join(this.destDir ?? '.', this.dts ?? 'index.d.ts'),
|
||||
)
|
||||
await writeJsBinding(
|
||||
binaryName,
|
||||
packageName,
|
||||
this.jsBinding && this.jsBinding !== 'false'
|
||||
? join(process.cwd(), this.jsBinding)
|
||||
: null,
|
||||
idents,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,10 +268,14 @@ interface TypeDef {
|
|||
def: string
|
||||
}
|
||||
|
||||
async function processIntermediateTypeFile(source: string, target: string) {
|
||||
async function processIntermediateTypeFile(
|
||||
source: string,
|
||||
target: string,
|
||||
): Promise<string[]> {
|
||||
const idents: string[] = []
|
||||
if (!(await existsAsync(source))) {
|
||||
debug(`do not find tmp type file. skip type generation`)
|
||||
return
|
||||
return idents
|
||||
}
|
||||
|
||||
const tmpFile = await readFileAsync(source, 'utf8')
|
||||
|
@ -244,6 +292,7 @@ async function processIntermediateTypeFile(source: string, target: string) {
|
|||
|
||||
switch (def.kind) {
|
||||
case 'struct':
|
||||
idents.push(def.name)
|
||||
classes.set(def.name, def.def)
|
||||
break
|
||||
case 'impl':
|
||||
|
@ -253,6 +302,7 @@ async function processIntermediateTypeFile(source: string, target: string) {
|
|||
dts += `interface ${def.name} {\n${indentLines(def.def, 2)}\n}\n`
|
||||
break
|
||||
default:
|
||||
idents.push(def.name)
|
||||
dts += def.def + '\n'
|
||||
}
|
||||
})
|
||||
|
@ -271,6 +321,7 @@ async function processIntermediateTypeFile(source: string, target: string) {
|
|||
|
||||
await unlinkAsync(source)
|
||||
await writeFileAsync(target, dts, 'utf8')
|
||||
return idents
|
||||
}
|
||||
|
||||
function indentLines(input: string, spaces: number) {
|
||||
|
@ -279,3 +330,23 @@ function indentLines(input: string, spaces: number) {
|
|||
.map((line) => ''.padEnd(spaces, ' ') + line.trim())
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
async function writeJsBinding(
|
||||
localName: string,
|
||||
packageName: string,
|
||||
distFileName: string | null,
|
||||
idents: string[],
|
||||
) {
|
||||
if (distFileName) {
|
||||
const template = createJsBinding(localName, packageName)
|
||||
const declareCodes = `const { ${idents.join(', ')} } = nativeBinding\n`
|
||||
const exportsCode = idents.reduce((acc, cur) => {
|
||||
return `${acc}\nmodule.exports.${cur} = ${cur}`
|
||||
}, '')
|
||||
await writeFileAsync(
|
||||
distFileName,
|
||||
template + declareCodes + exportsCode,
|
||||
'utf8',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
216
cli/src/js-binding-template.ts
Normal file
216
cli/src/js-binding-template.ts
Normal file
|
@ -0,0 +1,216 @@
|
|||
export const createJsBinding = (
|
||||
localName: string,
|
||||
pkgName: string,
|
||||
) => `const { existsSync, readFileSync } = require('fs')
|
||||
const { join } = require('path')
|
||||
|
||||
const { platform, arch } = process
|
||||
|
||||
let nativeBinding = null
|
||||
let localFileExisted = false
|
||||
let isMusl = false
|
||||
let loadError = null
|
||||
|
||||
switch (platform) {
|
||||
case 'android':
|
||||
if (arch !== 'arm64') {
|
||||
throw new Error(\`Unsupported architecture on Android \${arch}\`)
|
||||
}
|
||||
localFileExisted = existsSync(join(__dirname, '${localName}.android-arm64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.android-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-android-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'win32':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.win32-x64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.win32-x64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-win32-x64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'ia32':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.win32-ia32-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.win32-ia32-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-win32-ia32-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.win32-arm64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.win32-arm64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-win32-arm64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(\`Unsupported architecture on Windows: \${arch}\`)
|
||||
}
|
||||
break
|
||||
case 'darwin':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(join(__dirname, '${localName}.darwin-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.darwin-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-darwin-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.darwin-arm64.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.darwin-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-darwin-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(\`Unsupported architecture on macOS: \${arch}\`)
|
||||
}
|
||||
break
|
||||
case 'freebsd':
|
||||
if (arch !== 'x64') {
|
||||
throw new Error(\`Unsupported architecture on FreeBSD: \${arch}\`)
|
||||
}
|
||||
localFileExisted = existsSync(join(__dirname, '${localName}.freebsd-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.freebsd-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-freebsd-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'linux':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
isMusl = readFileSync('/usr/bin/ldd', 'utf8').includes('musl')
|
||||
if (isMusl) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.linux-x64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.linux-x64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-linux-x64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.linux-x64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.linux-x64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-linux-x64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
isMusl = readFileSync('/usr/bin/ldd', 'utf8').includes('musl')
|
||||
if (isMusl) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.linux-arm64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.linux-arm64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-linux-arm64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.linux-arm64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.linux-arm64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-linux-arm64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '${localName}.linux-arm-gnueabihf.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./${localName}.linux-arm-gnueabihf.node')
|
||||
} else {
|
||||
nativeBinding = require('${pkgName}-linux-arm-gnueabihf')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(\`Unsupported architecture on Linux: \${arch}\`)
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(\`Unsupported OS: \${platform}, architecture: \${arch}\`)
|
||||
}
|
||||
|
||||
if (!nativeBinding) {
|
||||
if (loadError) {
|
||||
throw loadError
|
||||
}
|
||||
throw new Error(\`Failed to load native binding\`)
|
||||
}
|
||||
|
||||
`
|
|
@ -38,7 +38,7 @@ jobs:
|
|||
target: 'x86_64-pc-windows-msvc'
|
||||
- host: windows-latest
|
||||
build: |
|
||||
export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=32;
|
||||
export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=64;
|
||||
export CARGO_PROFILE_RELEASE_LTO=false
|
||||
yarn build --target i686-pc-windows-msvc
|
||||
yarn test
|
||||
|
|
|
@ -12,7 +12,6 @@ import { DefaultPlatforms } from '../parse-triple'
|
|||
import { createCargoContent } from './cargo'
|
||||
import { createCargoConfig } from './cargo-config'
|
||||
import { createGithubActionsCIYml } from './ci-yml'
|
||||
import { createIndexJs } from './indexjs'
|
||||
import { LibRs } from './lib-rs'
|
||||
import { NPMIgnoreFiles } from './npmignore'
|
||||
import { createPackageJson } from './package'
|
||||
|
@ -125,7 +124,6 @@ export class NewProjectCommand extends Command {
|
|||
this.writeFile('Cargo.toml', createCargoContent(this.name!))
|
||||
this.writeFile('.npmignore', NPMIgnoreFiles)
|
||||
this.writeFile('build.rs', BUILD_RS)
|
||||
this.writeFile('index.js', createIndexJs(this.name!, binaryName))
|
||||
this.writeFile(
|
||||
'package.json',
|
||||
JSON.stringify(
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
export const createIndexJs = (
|
||||
pkgName: string,
|
||||
name: string,
|
||||
) => `const { loadBinding } = require('@node-rs/helper')
|
||||
|
||||
/**
|
||||
* __dirname means load native addon from current dir
|
||||
* '${name}' is the name of native addon
|
||||
* the second arguments was decided by \`napi.name\` field in \`package.json\`
|
||||
* the third arguments was decided by \`name\` field in \`package.json\`
|
||||
* \`loadBinding\` helper will load \`${name}.[PLATFORM].node\` from \`__dirname\` first
|
||||
* If failed to load addon, it will fallback to load from \`${pkgName}-[PLATFORM]\`
|
||||
*/
|
||||
module.exports = loadBinding(__dirname, '${name}', '${pkgName}')
|
||||
`
|
|
@ -2,13 +2,13 @@
|
|||
"name": "test-module",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "node ../../cli/scripts/index.js build --features \"latest\"",
|
||||
"build-napi3": "node ../../cli/scripts/index.js build --features \"napi3\"",
|
||||
"build-aarch64": "node ../../cli/scripts/index.js build --features \"latest\" --target aarch64-unknown-linux-gnu",
|
||||
"build-armv7": "node ../../cli/scripts/index.js build --features \"latest\" --target armv7-unknown-linux-gnueabihf",
|
||||
"build-i686": "node ../../cli/scripts/index.js build --features \"latest\" --target i686-pc-windows-msvc",
|
||||
"build-i686-release": "node ../../cli/scripts/index.js build --release --features \"latest\" --target i686-pc-windows-msvc",
|
||||
"build-release": "node ../../cli/scripts/index.js build --features \"latest\" --release",
|
||||
"build": "node ../../cli/scripts/index.js build --js false --features \"latest\"",
|
||||
"build-napi3": "node ../../cli/scripts/index.js build --js false --features \"napi3\"",
|
||||
"build-aarch64": "node ../../cli/scripts/index.js build --js false --features \"latest\" --target aarch64-unknown-linux-gnu",
|
||||
"build-armv7": "node ../../cli/scripts/index.js build --js false --features \"latest\" --target armv7-unknown-linux-gnueabihf",
|
||||
"build-i686": "node ../../cli/scripts/index.js build --js false --features \"latest\" --target i686-pc-windows-msvc",
|
||||
"build-i686-release": "node ../../cli/scripts/index.js build --js false --release --features \"latest\" --target i686-pc-windows-msvc",
|
||||
"build-release": "node ../../cli/scripts/index.js build --js false --features \"latest\" --release",
|
||||
"test": "node ./index.js"
|
||||
}
|
||||
}
|
||||
|
|
33
examples/napi/index.d.ts
vendored
33
examples/napi/index.d.ts
vendored
|
@ -4,9 +4,7 @@ export function sumNums(nums: Array<number>): number
|
|||
export function readFileAsync(path: string): Promise<Buffer>
|
||||
export function asyncMultiTwo(arg: number): Promise<number>
|
||||
export function getCwd(callback: (arg0: string) => void): void
|
||||
export function readFile(
|
||||
callback: (arg0: Error | undefined, arg1: string | null) => void,
|
||||
): void
|
||||
export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void
|
||||
export function eitherStringOrNumber(input: string | number): number
|
||||
export function returnEither(input: number): string | number
|
||||
export function either3(input: string | number | boolean): number
|
||||
|
@ -14,21 +12,8 @@ interface Obj {
|
|||
v: string | number
|
||||
}
|
||||
export function either4(input: string | number | boolean | Obj): number
|
||||
export enum Kind {
|
||||
Dog = 0,
|
||||
Cat = 1,
|
||||
Duck = 2,
|
||||
}
|
||||
export enum CustomNumEnum {
|
||||
One = 1,
|
||||
Two = 2,
|
||||
Three = 3,
|
||||
Four = 4,
|
||||
Six = 6,
|
||||
Eight = 8,
|
||||
Nine = 9,
|
||||
Ten = 10,
|
||||
}
|
||||
export enum Kind { Dog = 0, Cat = 1, Duck = 2 }
|
||||
export enum CustomNumEnum { One = 1, Two = 2, Three = 3, Four = 4, Six = 6, Eight = 8, Nine = 9, Ten = 10 }
|
||||
export function enumToI32(e: CustomNumEnum): number
|
||||
export function throwError(): void
|
||||
export function mapOption(val: number | null): number | null
|
||||
|
@ -49,11 +34,7 @@ export function concatStr(mutS: string): string
|
|||
export function concatUtf16(s: string): string
|
||||
export function concatLatin1(s: string): string
|
||||
export function withoutAbortController(a: number, b: number): Promise<number>
|
||||
export function withAbortController(
|
||||
a: number,
|
||||
b: number,
|
||||
signal: AbortSignal,
|
||||
): Promise<number>
|
||||
export function withAbortController(a: number, b: number, signal: AbortSignal): Promise<number>
|
||||
export function getBuffer(): Buffer
|
||||
export class Animal {
|
||||
readonly kind: Kind
|
||||
|
@ -65,10 +46,14 @@ export class Animal {
|
|||
static getDogKind(): Kind
|
||||
}
|
||||
export class Blake2BHasher {
|
||||
|
||||
static withKey(key: Blake2bKey): Blake2BHasher
|
||||
}
|
||||
export class Blake2BKey {}
|
||||
export class Blake2BKey {
|
||||
|
||||
}
|
||||
export class Context {
|
||||
|
||||
constructor()
|
||||
static withData(data: string): Context
|
||||
method(): string
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
"main": "./index.node",
|
||||
"types": "./index.d.ts",
|
||||
"scripts": {
|
||||
"build": "node ../../cli/scripts/index.js build",
|
||||
"build-aarch64": "node ../../cli/scripts/index.js build --target aarch64-unknown-linux-gnu",
|
||||
"build-armv7": "node ../../cli/scripts/index.js build --target armv7-unknown-linux-gnueabihf",
|
||||
"build-i686": "node ../../cli/scripts/index.js build --target i686-pc-windows-msvc",
|
||||
"build-i686-release": "node ../../cli/scripts/index.js build --release --target i686-pc-windows-msvc",
|
||||
"build-release": "node ../../cli/scripts/index.js build --release"
|
||||
"build": "node ../../cli/scripts/index.js build --js false",
|
||||
"build-aarch64": "node ../../cli/scripts/index.js build --js false --target aarch64-unknown-linux-gnu",
|
||||
"build-armv7": "node ../../cli/scripts/index.js build --js false --target armv7-unknown-linux-gnueabihf",
|
||||
"build-i686": "node ../../cli/scripts/index.js build --js false --target i686-pc-windows-msvc",
|
||||
"build-i686-release": "node ../../cli/scripts/index.js build --js false --release --target i686-pc-windows-msvc",
|
||||
"build-release": "node ../../cli/scripts/index.js build --js false --release"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
"rootDir": "__test__",
|
||||
"target": "ES2015"
|
||||
},
|
||||
"exclude": ["dist"]
|
||||
"exclude": ["dist", "index.d.ts"]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue