Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
N
nfkit
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
nfkit
Commits
02e42928
Commit
02e42928
authored
Oct 31, 2025
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update build system
parent
1d5ec34b
Pipeline
#41332
passed with stages
in 1 minute and 59 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
172 additions
and
4 deletions
+172
-4
build.js
build.js
+167
-0
package.json
package.json
+5
-4
No files found.
build.js
0 → 100644
View file @
02e42928
#!/usr/bin/env node
/* build.js - node build.js [all|cjs|esm|types|clean] */
const
fs
=
require
(
'
fs
'
);
const
path
=
require
(
'
path
'
);
const
{
builtinModules
}
=
require
(
'
module
'
);
const
DIST_DIR
=
'
dist
'
;
/* ------------------------- utils ------------------------- */
function
readJSONSafe
(
file
,
fallback
=
{})
{
try
{
const
p
=
path
.
resolve
(
process
.
cwd
(),
file
);
const
txt
=
fs
.
readFileSync
(
p
,
'
utf8
'
);
return
JSON
.
parse
(
txt
);
}
catch
{
return
fallback
;
}
}
function
uniq
(
arr
)
{
return
Array
.
from
(
new
Set
(
arr
));
}
function
ensureDir
(
p
)
{
fs
.
mkdirSync
(
p
,
{
recursive
:
true
});
}
function
rimraf
(
p
)
{
if
(
fs
.
existsSync
(
p
))
fs
.
rmSync
(
p
,
{
recursive
:
true
,
force
:
true
});
}
function
depsAsExternal
(
pkg
)
{
const
dep
=
Object
.
keys
(
pkg
.
dependencies
||
{});
const
peer
=
Object
.
keys
(
pkg
.
peerDependencies
||
{});
const
names
=
uniq
([...
dep
,
...
peer
]);
// 覆盖子路径导入(lodash/fp、react/jsx-runtime)
return
uniq
(
names
.
flatMap
((
n
)
=>
[
n
,
`
${
n
}
/*`
]));
}
function
nodeBuiltinsExternal
()
{
// 既包含 'fs' 也包含 'node:fs' 形式
return
uniq
([...
builtinModules
,
...
builtinModules
.
map
((
m
)
=>
`node:
${
m
}
`
)]);
}
async
function
loadEsbuild
()
{
try
{
return
require
(
'
esbuild
'
);
}
catch
{
const
mod
=
await
import
(
'
esbuild
'
);
return
mod
.
build
?
mod
:
mod
.
default
;
}
}
function
tsconfigPath
()
{
return
fs
.
existsSync
(
'
tsconfig.json
'
)
?
'
tsconfig.json
'
:
undefined
;
}
function
entryPointsFromPkg
(
/*pkg*/
)
{
return
[
'
index.ts
'
];
}
/* ------------------------- esbuild builds ------------------------- */
async
function
buildOne
(
format
,
options
)
{
const
esbuild
=
await
loadEsbuild
();
const
{
external
,
tsconfig
,
entryPoints
}
=
options
;
const
isCjs
=
format
===
'
cjs
'
;
const
outfile
=
path
.
join
(
DIST_DIR
,
isCjs
?
'
index.cjs
'
:
'
index.mjs
'
);
ensureDir
(
path
.
dirname
(
outfile
));
console
.
log
(
`[build]
${
format
}
->
${
outfile
}
`
);
await
esbuild
.
build
({
entryPoints
,
outfile
,
bundle
:
true
,
sourcemap
:
true
,
format
,
// 'cjs' | 'esm'
platform
:
isCjs
?
'
node
'
:
'
neutral
'
,
target
:
isCjs
?
'
es2021
'
:
'
esnext
'
,
external
,
// deps + peerDeps + node builtins (含 node:*)
logLevel
:
'
info
'
,
...(
tsconfig
?
{
tsconfig
}
:
{}),
});
}
/* ------------------------- types via TypeScript API ------------------------- */
function
buildTypesAPI
(
outDir
=
DIST_DIR
)
{
let
ts
;
try
{
ts
=
require
(
'
typescript
'
);
}
catch
{
console
.
error
(
'
[types] Missing dependency: typescript
'
);
process
.
exit
(
1
);
}
const
cfgPath
=
ts
.
findConfigFile
(
'
./
'
,
ts
.
sys
.
fileExists
,
'
tsconfig.json
'
);
let
fileNames
,
options
;
if
(
cfgPath
)
{
// 读取 tsconfig.json
const
{
config
}
=
ts
.
readConfigFile
(
cfgPath
,
ts
.
sys
.
readFile
);
const
parsed
=
ts
.
parseJsonConfigFileContent
(
config
,
ts
.
sys
,
path
.
dirname
(
cfgPath
));
fileNames
=
parsed
.
fileNames
;
options
=
parsed
.
options
;
}
else
{
// 没有 tsconfig 的降级:仅用 index.ts
console
.
warn
(
'
[types] tsconfig.json not found; fallback to index.ts with basic options.
'
);
fileNames
=
[
'
index.ts
'
].
filter
((
f
)
=>
fs
.
existsSync
(
f
));
options
=
{
moduleResolution
:
99
,
// NodeNext(避免引入 enum 名字,用常量值)
target
:
99
,
// ESNext
skipLibCheck
:
true
,
strict
:
true
,
};
}
// 强制仅输出声明
options
.
declaration
=
true
;
options
.
emitDeclarationOnly
=
true
;
options
.
outDir
=
outDir
;
// 为了不受 sourceMap/emit 等其它设置影响
options
.
noEmitOnError
=
false
;
console
.
log
(
'
[types] Generating .d.ts ...
'
);
const
program
=
ts
.
createProgram
(
fileNames
,
options
);
const
pre
=
ts
.
getPreEmitDiagnostics
(
program
);
const
emitResult
=
program
.
emit
();
const
diagnostics
=
pre
.
concat
(
emitResult
.
diagnostics
);
if
(
diagnostics
.
length
)
{
const
formatHost
=
{
getCanonicalFileName
:
(
p
)
=>
p
,
getCurrentDirectory
:
ts
.
sys
.
getCurrentDirectory
,
getNewLine
:
()
=>
ts
.
sys
.
newLine
,
};
const
message
=
ts
.
formatDiagnosticsWithColorAndContext
(
diagnostics
,
formatHost
);
console
.
error
(
message
);
if
(
emitResult
.
emitSkipped
)
{
throw
new
Error
(
'
[types] Type generation failed.
'
);
}
}
console
.
log
(
'
[types] Declarations generated.
'
);
}
/* ------------------------- main dispatcher ------------------------- */
(
async
function
main
()
{
const
sub
=
(
process
.
argv
[
2
]
||
'
all
'
).
toLowerCase
();
// all | cjs | esm | types | clean
const
pkg
=
readJSONSafe
(
'
package.json
'
);
const
externalFromPkg
=
depsAsExternal
(
pkg
);
// 统一 external:依赖 + peer + Node 内置(含 node:*)
const
external
=
uniq
([...
externalFromPkg
,
...
nodeBuiltinsExternal
()]);
const
tscPath
=
tsconfigPath
();
const
entryPoints
=
entryPointsFromPkg
(
pkg
);
switch
(
sub
)
{
case
'
clean
'
:
{
console
.
log
(
'
[clean] remove dist/
'
);
rimraf
(
DIST_DIR
);
break
;
}
case
'
cjs
'
:
{
await
buildOne
(
'
cjs
'
,
{
external
,
tsconfig
:
tscPath
,
entryPoints
});
break
;
}
case
'
esm
'
:
{
await
buildOne
(
'
esm
'
,
{
external
,
tsconfig
:
tscPath
,
entryPoints
});
break
;
}
case
'
types
'
:
{
ensureDir
(
DIST_DIR
);
buildTypesAPI
(
DIST_DIR
);
break
;
}
case
'
all
'
:
default
:
{
console
.
log
(
'
[clean] remove dist/
'
);
rimraf
(
DIST_DIR
);
await
buildOne
(
'
cjs
'
,
{
external
,
tsconfig
:
tscPath
,
entryPoints
});
await
buildOne
(
'
esm
'
,
{
external
,
tsconfig
:
tscPath
,
entryPoints
});
buildTypesAPI
(
DIST_DIR
);
console
.
log
(
'
[build] Done.
'
);
break
;
}
}
})().
catch
((
err
)
=>
{
console
.
error
(
'
[build] Failed:
'
,
err
);
process
.
exit
(
1
);
});
package.json
View file @
02e42928
...
...
@@ -14,10 +14,11 @@
},
"scripts"
:
{
"lint"
:
"eslint --fix ."
,
"compile:cjs"
:
"esbuild index.ts --outfile=dist/index.cjs --bundle --sourcemap --platform=node --target=es2019 --external:*"
,
"compile:esm"
:
"esbuild index.ts --outfile=dist/index.mjs --bundle --sourcemap --platform=neutral --target=esnext --external:*"
,
"compile:types"
:
"tsc --emitDeclarationOnly --declaration"
,
"build"
:
"rimraf dist && npm run compile:cjs && npm run compile:esm && npm run compile:types"
,
"build"
:
"node build.js"
,
"build:cjs"
:
"node build.js cjs"
,
"build:esm"
:
"node build.js esm"
,
"build:types"
:
"node build.js types"
,
"clean"
:
"node build.js clean"
,
"test"
:
"jest --passWithNoTests"
,
"start"
:
"node dist/index.js"
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment