Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
I
init-things
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
init-things
Commits
906598e4
Commit
906598e4
authored
Oct 31, 2025
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
build
parent
7214d650
Pipeline
#41331
passed with stages
in 14 minutes and 4 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
172 additions
and
4 deletions
+172
-4
things/npm/build.js
things/npm/build.js
+167
-0
things/npm/package.json
things/npm/package.json
+5
-4
No files found.
things/npm/build.js
0 → 100644
View file @
906598e4
#!/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
);
});
things/npm/package.json
View file @
906598e4
...
...
@@ -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