@needle-tools/engine 5.1.0-alpha.1 → 5.1.0-canary.0d9f44e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.needle/generated/needle-bindings.gen.d.ts +5 -0
- package/components.needle.json +1 -1
- package/dist/{gltf-progressive-DJBMx-zB.umd.cjs → gltf-progressive-BmblPzFj.umd.cjs} +4 -4
- package/dist/{gltf-progressive-BryRjllq.min.js → gltf-progressive-CN_mbb66.min.js} +2 -2
- package/dist/{gltf-progressive-Cl167Vjx.js → gltf-progressive-DUlhxdv4.js} +5 -2
- package/dist/{needle-engine.bundle-BGyKqxBH.js → needle-engine.bundle-B35n_IHX.js} +8736 -8500
- package/dist/{needle-engine.bundle-DzVx9Z8D.umd.cjs → needle-engine.bundle-CDj15wRB.umd.cjs} +164 -164
- package/dist/{needle-engine.bundle-CiYtOO2O.min.js → needle-engine.bundle-D5zzggEG.min.js} +164 -164
- package/dist/needle-engine.d.ts +140 -22
- package/dist/needle-engine.js +172 -170
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-B_9sKVU7.min.js → postprocessing-B571qGWR.min.js} +34 -34
- package/dist/{postprocessing-WDc9WwI3.js → postprocessing-CfrLAbLX.js} +0 -1
- package/dist/{postprocessing-B2wb6pzI.umd.cjs → postprocessing-CiGkAeM9.umd.cjs} +17 -17
- package/dist/three-examples.js +4289 -3778
- package/dist/three-examples.min.js +301 -14
- package/dist/three-examples.umd.cjs +301 -14
- package/dist/{vendor-CAcsI0eU.js → vendor-BFrMaK9q.js} +8983 -9136
- package/dist/vendor-CJmyOrCq.min.js +1116 -0
- package/dist/vendor-DkMW3WY4.umd.cjs +1116 -0
- package/lib/engine/api.d.ts +12 -0
- package/lib/engine/api.js +2 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug_environment.js +1 -1
- package/lib/engine/debug/debug_environment.js.map +1 -1
- package/lib/engine/engine_application.js +8 -6
- package/lib/engine/engine_application.js.map +1 -1
- package/lib/engine/engine_constants.js +6 -0
- package/lib/engine/engine_constants.js.map +1 -1
- package/lib/engine/engine_context.d.ts +31 -2
- package/lib/engine/engine_context.js +43 -2
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_context_registry.js +1 -1
- package/lib/engine/engine_context_registry.js.map +1 -1
- package/lib/engine/engine_init.js +5 -0
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_input.d.ts +3 -2
- package/lib/engine/engine_input.js +3 -2
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_license.d.ts +2 -0
- package/lib/engine/engine_license.js +25 -15
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_lifecycle_functions_internal.js +5 -0
- package/lib/engine/engine_lifecycle_functions_internal.js.map +1 -1
- package/lib/engine/engine_networking_blob.d.ts +1 -1
- package/lib/engine/engine_networking_blob.js +5 -11
- package/lib/engine/engine_networking_blob.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +0 -1
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_pmrem.js +2 -2
- package/lib/engine/engine_pmrem.js.map +1 -1
- package/lib/engine/engine_scenedata.d.ts +34 -0
- package/lib/engine/engine_scenedata.js +135 -0
- package/lib/engine/engine_scenedata.js.map +1 -0
- package/lib/engine/engine_ssr.d.ts +18 -0
- package/lib/engine/engine_ssr.js +40 -0
- package/lib/engine/engine_ssr.js.map +1 -0
- package/lib/engine/engine_three_utils.d.ts +14 -7
- package/lib/engine/engine_three_utils.js +14 -7
- package/lib/engine/engine_three_utils.js.map +1 -1
- package/lib/engine/engine_types.d.ts +2 -0
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_utils.js +2 -0
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/engine_utils_hash.d.ts +9 -0
- package/lib/engine/engine_utils_hash.js +112 -0
- package/lib/engine/engine_utils_hash.js.map +1 -0
- package/lib/engine/webcomponents/logo-element.d.ts +10 -1
- package/lib/engine/webcomponents/logo-element.js +2 -1
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +12 -4
- package/lib/engine/webcomponents/needle menu/needle-menu.js +2 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-button.d.ts +15 -1
- package/lib/engine/webcomponents/needle-button.js +2 -1
- package/lib/engine/webcomponents/needle-button.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +7 -1
- package/lib/engine/webcomponents/needle-engine.js +2 -1
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.js +1 -1
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/Light.d.ts +25 -8
- package/lib/engine-components/Light.js +132 -27
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/RigidBody.js +3 -3
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +2 -0
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/BloomEffect.d.ts +1 -1
- package/lib/engine-components/postprocessing/Effects/Sharpening.js +1 -2
- package/lib/engine-components/postprocessing/Effects/Sharpening.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.js +5 -6
- package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +0 -1
- package/lib/engine-components/web/ScrollFollow.js +3 -2
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/needle-engine.d.ts +1 -0
- package/lib/needle-engine.js +1 -0
- package/lib/needle-engine.js.map +1 -1
- package/package.json +7 -5
- package/plugins/dts-generator/dts.codegen.js +334 -0
- package/plugins/dts-generator/dts.scan.js +99 -0
- package/plugins/dts-generator/dts.writer.js +59 -0
- package/plugins/dts-generator/glb.discovery.js +279 -0
- package/plugins/dts-generator/glb.extractor.js +215 -0
- package/plugins/dts-generator/glb.reader.js +167 -0
- package/plugins/dts-generator/index.js +36 -0
- package/plugins/dts-generator/manifest.types.js +174 -0
- package/plugins/types/index.d.ts +2 -1
- package/plugins/types/needle-bindings.d.ts +30 -0
- package/plugins/types/userconfig.d.ts +21 -2
- package/plugins/vite/asap.js +1 -1
- package/plugins/vite/dependency-watcher.d.ts +2 -2
- package/plugins/vite/dependency-watcher.js +3 -4
- package/plugins/vite/drop.d.ts +2 -2
- package/plugins/vite/drop.js +3 -4
- package/plugins/vite/dts-generator.d.ts +7 -0
- package/plugins/vite/dts-generator.js +191 -0
- package/plugins/vite/index.d.ts +10 -3
- package/plugins/vite/index.js +27 -10
- package/plugins/vite/logging.js +2 -2
- package/plugins/vite/meta.js +4 -2
- package/plugins/vite/poster.d.ts +2 -2
- package/plugins/vite/poster.js +3 -5
- package/plugins/vite/reload.d.ts +2 -2
- package/plugins/vite/reload.js +5 -5
- package/src/engine/api.ts +15 -1
- package/src/engine/debug/debug_environment.ts +1 -1
- package/src/engine/engine_application.ts +8 -6
- package/src/engine/engine_constants.ts +11 -6
- package/src/engine/engine_context.ts +47 -2
- package/src/engine/engine_context_registry.ts +1 -1
- package/src/engine/engine_init.ts +4 -0
- package/src/engine/engine_input.ts +3 -2
- package/src/engine/engine_license.ts +23 -19
- package/src/engine/engine_lifecycle_functions_internal.ts +7 -0
- package/src/engine/engine_networking_blob.ts +5 -11
- package/src/engine/engine_physics_rapier.ts +0 -3
- package/src/engine/engine_pmrem.ts +3 -3
- package/src/engine/engine_scenedata.ts +133 -0
- package/src/engine/engine_ssr.ts +48 -0
- package/src/engine/engine_three_utils.ts +15 -7
- package/src/engine/engine_types.ts +2 -0
- package/src/engine/engine_utils.ts +1 -0
- package/src/engine/engine_utils_hash.ts +65 -0
- package/src/engine/webcomponents/logo-element.ts +10 -1
- package/src/engine/webcomponents/needle menu/needle-menu.ts +11 -2
- package/src/engine/webcomponents/needle-button.ts +15 -1
- package/src/engine/webcomponents/needle-engine.ts +8 -1
- package/src/engine/xr/NeedleXRSession.ts +1 -1
- package/src/engine-components/Light.ts +132 -27
- package/src/engine-components/RigidBody.ts +3 -3
- package/src/engine-components/SceneSwitcher.ts +1 -0
- package/src/engine-components/postprocessing/Effects/BloomEffect.ts +1 -1
- package/src/engine-components/postprocessing/Effects/Sharpening.ts +1 -2
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +4 -8
- package/src/engine-components/web/ScrollFollow.ts +2 -2
- package/src/needle-engine.ts +2 -0
- package/src/vite-env.d.ts +16 -0
- package/dist/vendor-CEM38hLE.umd.cjs +0 -1116
- package/dist/vendor-HRlxIBga.min.js +0 -1116
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Needle Engine — HTML binding DTS generator
|
|
4
|
+
*
|
|
5
|
+
* Scans all GLB/glTF files in the project's assets directory, extracts
|
|
6
|
+
* NEEDLE_components data, and emits a `needle-bindings.d.ts` virtual-module
|
|
7
|
+
* declaration so that TypeScript can type-check HTML ↔ 3D component bindings.
|
|
8
|
+
*
|
|
9
|
+
* Typical generated output:
|
|
10
|
+
*
|
|
11
|
+
* declare module "needle-bindings" {
|
|
12
|
+
* interface SceneData {
|
|
13
|
+
* Sphere: {
|
|
14
|
+
* MyBall: { speed: number; label: string; };
|
|
15
|
+
* };
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* How component field types are resolved:
|
|
20
|
+
* - For built-in Needle Engine components, types are read from
|
|
21
|
+
* `components.needle.json` which lists only @serializable fields with
|
|
22
|
+
* their proper TypeScript types.
|
|
23
|
+
* - For user-defined components (not in the manifest), types are inferred
|
|
24
|
+
* from the JSON value in the GLB (number/string/boolean → typed, else → unknown).
|
|
25
|
+
* - Known Three.js types (Color, Vector3, Object3D, …) are emitted as
|
|
26
|
+
* `import("three").TypeName` and known Needle types (RGBAColor, AssetReference, …)
|
|
27
|
+
* as `import("@needle-tools/engine").TypeName`.
|
|
28
|
+
* - Truly unknown types fall back to `unknown`.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export { resolveEntrypointGlbs, collectSceneFiles } from './glb.discovery.js';
|
|
32
|
+
export { readGlbJsonChunk, readGltfJsonFile, readRemoteGlbJsonChunk } from './glb.reader.js';
|
|
33
|
+
export { extractComponentBindings, sanitizeNodeName, inferNodeThreeType, inferTsType } from './glb.extractor.js';
|
|
34
|
+
export { scanBindings } from './dts.scan.js';
|
|
35
|
+
export { generateDts, generateHtmlCustomData } from './dts.codegen.js';
|
|
36
|
+
export { generateBindingsDts } from './dts.writer.js';
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Type tables and components.needle.json manifest loader.
|
|
4
|
+
*
|
|
5
|
+
* Knows about primitive TS types, known Three.js types, known Needle Engine
|
|
6
|
+
* types, and how to resolve field types from the manifest.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, readFileSync } from 'fs';
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
|
|
16
|
+
/** Primitive TS type strings that can safely appear in an ambient declaration. */
|
|
17
|
+
export const PRIMITIVE_TYPES = new Set(["number", "string", "boolean"]);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Known Three.js types → import("three").TypeName
|
|
21
|
+
* @type {Record<string, string>}
|
|
22
|
+
*/
|
|
23
|
+
export const THREE_TYPES = {
|
|
24
|
+
Color: `import("three").Color`,
|
|
25
|
+
ColorRepresentation: `import("three").ColorRepresentation`,
|
|
26
|
+
Euler: `import("three").Euler`,
|
|
27
|
+
Texture: `import("three").Texture`,
|
|
28
|
+
// Materials
|
|
29
|
+
Material: `import("three").Material`,
|
|
30
|
+
MeshStandardMaterial: `import("three").MeshStandardMaterial`,
|
|
31
|
+
// Objects
|
|
32
|
+
Object3D: `import("three").Object3D`,
|
|
33
|
+
Mesh: `import("three").Mesh`,
|
|
34
|
+
SkinnedMesh: `import("three").SkinnedMesh`,
|
|
35
|
+
// Other
|
|
36
|
+
Vector2: `import("three").Vector2`,
|
|
37
|
+
Vector3: `import("three").Vector3`,
|
|
38
|
+
Vector4: `import("three").Vector4`,
|
|
39
|
+
Matrix3: `import("three").Matrix3`,
|
|
40
|
+
Matrix4: `import("three").Matrix4`,
|
|
41
|
+
Quaternion: `import("three").Quaternion`,
|
|
42
|
+
// Animation
|
|
43
|
+
AnimationClip: `import("three").AnimationClip`,
|
|
44
|
+
AnimationMixer: `import("three").AnimationMixer`,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Known Needle Engine types → import("@needle-tools/engine").TypeName
|
|
49
|
+
* @type {Record<string, string>}
|
|
50
|
+
*/
|
|
51
|
+
export const NEEDLE_TYPES = {
|
|
52
|
+
AssetReference: `import("@needle-tools/engine").AssetReference`,
|
|
53
|
+
EventList: `import("@needle-tools/engine").EventList`,
|
|
54
|
+
GameObject: `import("@needle-tools/engine").GameObject`,
|
|
55
|
+
LookAtConstraint: `import("@needle-tools/engine").LookAtConstraint`,
|
|
56
|
+
RGBAColor: `import("@needle-tools/engine").RGBAColor`,
|
|
57
|
+
RenderTexture: `import("@needle-tools/engine").RenderTexture`,
|
|
58
|
+
Renderer: `import("@needle-tools/engine").Renderer`,
|
|
59
|
+
Rigidbody: `import("@needle-tools/engine").Rigidbody`,
|
|
60
|
+
Sprite: `import("@needle-tools/engine").Sprite`,
|
|
61
|
+
Vec2: `import("@needle-tools/engine").Vec2`,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Map a single non-array, non-primitive type token to its TS representation.
|
|
66
|
+
* Returns null if unknown.
|
|
67
|
+
* @param {string} token
|
|
68
|
+
* @returns {string | null}
|
|
69
|
+
*/
|
|
70
|
+
function mapKnownType(token) {
|
|
71
|
+
if (token in THREE_TYPES) return THREE_TYPES[token];
|
|
72
|
+
if (token in NEEDLE_TYPES) return NEEDLE_TYPES[token];
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Convert a manifest type string to a safe ambient TS type.
|
|
78
|
+
* Primitives and known Three.js/Needle types are resolved precisely.
|
|
79
|
+
* For unknown types on a manifest component, falls back to
|
|
80
|
+
* `import("@needle-tools/engine").ComponentName["fieldName"]`.
|
|
81
|
+
* Truly unresolvable types → "unknown".
|
|
82
|
+
*
|
|
83
|
+
* @param {string} typeStr
|
|
84
|
+
* @param {string} [componentName] The manifest component class name (enables indexed-access fallback)
|
|
85
|
+
* @param {string} [fieldName] The field name on that component
|
|
86
|
+
* @returns {string}
|
|
87
|
+
*/
|
|
88
|
+
export function manifestTypeToTs(typeStr, componentName, fieldName) {
|
|
89
|
+
const parts = typeStr.split(" | ").map(p => p.trim());
|
|
90
|
+
const safeParts = parts.map(p => {
|
|
91
|
+
if (p === "undefined" || p === "null") return p;
|
|
92
|
+
const arrayMatch = p.match(/^(number|string|boolean)\[\]$/);
|
|
93
|
+
if (arrayMatch) return p;
|
|
94
|
+
if (PRIMITIVE_TYPES.has(p)) return p;
|
|
95
|
+
const arrayTypeMatch = p.match(/^(\w+)\[\]$/);
|
|
96
|
+
if (arrayTypeMatch) {
|
|
97
|
+
const base = arrayTypeMatch[1];
|
|
98
|
+
const mapped = mapKnownType(base);
|
|
99
|
+
if (mapped) return `${mapped}[]`;
|
|
100
|
+
}
|
|
101
|
+
const known = mapKnownType(p);
|
|
102
|
+
if (known) return known;
|
|
103
|
+
return null;
|
|
104
|
+
});
|
|
105
|
+
if (safeParts.every(p => p !== null)) {
|
|
106
|
+
return /** @type {string[]} */ (safeParts).join(" | ");
|
|
107
|
+
}
|
|
108
|
+
if (componentName && fieldName) {
|
|
109
|
+
return `import("@needle-tools/engine").${componentName}["${fieldName}"]`;
|
|
110
|
+
}
|
|
111
|
+
return "unknown";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Load components.needle.json and build a lookup:
|
|
116
|
+
* componentName → Map<fieldName, tsType>
|
|
117
|
+
* Inherited fields are flattened (inheritedFrom chain is resolved).
|
|
118
|
+
*
|
|
119
|
+
* @returns {Map<string, Map<string, string>>}
|
|
120
|
+
*/
|
|
121
|
+
export function loadComponentsManifest() {
|
|
122
|
+
/** @type {Map<string, Map<string, string>>} */
|
|
123
|
+
const manifest = new Map();
|
|
124
|
+
const manifestPath = join(__dirname, "../../components.needle.json");
|
|
125
|
+
if (!existsSync(manifestPath)) return manifest;
|
|
126
|
+
try {
|
|
127
|
+
/** @type {Array<{name: string, inheritedFrom?: string, children?: Array<{name: string, kind: string, type: string}>}>} */
|
|
128
|
+
const entries = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
129
|
+
|
|
130
|
+
/** @type {Map<string, Map<string, string>>} */
|
|
131
|
+
const ownFields = new Map();
|
|
132
|
+
/** @type {Map<string, string>} */
|
|
133
|
+
const inheritedFrom = new Map();
|
|
134
|
+
for (const entry of entries) {
|
|
135
|
+
if (!entry.name) continue;
|
|
136
|
+
inheritedFrom.set(entry.name, entry.inheritedFrom || "");
|
|
137
|
+
/** @type {Map<string, string>} */
|
|
138
|
+
const fields = new Map();
|
|
139
|
+
if (Array.isArray(entry.children)) {
|
|
140
|
+
for (const child of entry.children) {
|
|
141
|
+
if (child.kind === "property" && child.name && child.type) {
|
|
142
|
+
fields.set(child.name, manifestTypeToTs(child.type, entry.name, child.name));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
ownFields.set(entry.name, fields);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** @param {string} name @returns {Map<string, string>} */
|
|
150
|
+
function resolveFields(name) {
|
|
151
|
+
if (manifest.has(name)) return /** @type {Map<string, string>} */ (manifest.get(name));
|
|
152
|
+
const own = ownFields.get(name) ?? new Map();
|
|
153
|
+
const parent = inheritedFrom.get(name);
|
|
154
|
+
if (parent && ownFields.has(parent)) {
|
|
155
|
+
const parentFields = resolveFields(parent);
|
|
156
|
+
const merged = new Map([...parentFields, ...own]);
|
|
157
|
+
manifest.set(name, merged);
|
|
158
|
+
return merged;
|
|
159
|
+
}
|
|
160
|
+
manifest.set(name, own);
|
|
161
|
+
return own;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (const name of ownFields.keys()) {
|
|
165
|
+
resolveFields(name);
|
|
166
|
+
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.warn("[needle:dts-generator] Failed to load components.needle.json:", (/** @type {any} */ (e))?.message ?? e);
|
|
169
|
+
}
|
|
170
|
+
return manifest;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** @type {Map<string, Map<string, string>>} */
|
|
174
|
+
export const componentsManifest = loadComponentsManifest();
|
package/plugins/types/index.d.ts
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient module declaration for `needle-bindings`.
|
|
3
|
+
*
|
|
4
|
+
* `SceneData` is keyed by GLB friendly name, then by the node hierarchy:
|
|
5
|
+
* ctx.sceneData.Minimal.Camera.$object // → THREE.Camera
|
|
6
|
+
* ctx.sceneData.Minimal.Camera.$components.OrbitControls.autoRotate = true;
|
|
7
|
+
* ctx.sceneData.Minimal.UI.Button.$components.Button
|
|
8
|
+
*
|
|
9
|
+
* Each node entry has:
|
|
10
|
+
* $object — the Three.js Object3D (typed precisely, e.g. Mesh, Camera, Light)
|
|
11
|
+
* $components — Needle components attached to this node
|
|
12
|
+
* [childName] — child nodes, recursively typed
|
|
13
|
+
*
|
|
14
|
+
* When the `needle:dts-generator` Vite plugin is active it writes
|
|
15
|
+
* `.needle/generated/needle-bindings.gen.d.ts` next to the installed package,
|
|
16
|
+
* which augments this interface with the actual bindings extracted from
|
|
17
|
+
* the project's GLB files at build time.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Pull in the project-local generated augmentation (written by needle:dts-generator).
|
|
21
|
+
/// <reference path="../../.needle/generated/needle-bindings.gen.d.ts" />
|
|
22
|
+
|
|
23
|
+
declare module "needle-bindings" {
|
|
24
|
+
/**
|
|
25
|
+
* Scene data keyed by GLB friendly name, then by node hierarchy.
|
|
26
|
+
* Fallback index signature allows unknown names without crashing.
|
|
27
|
+
*/
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
29
|
+
interface SceneData {}
|
|
30
|
+
}
|
|
@@ -26,10 +26,17 @@ export type userSettings = {
|
|
|
26
26
|
noCopy?: boolean;
|
|
27
27
|
/** When enabled the needle-engine include directory will be copied */
|
|
28
28
|
copyIncludesFromEngine?: boolean;
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/** Set to `false` to prevent the Rapier physics engine from loading.
|
|
32
|
+
* NOTE: by default Needle Engine uses dynamic loading of the Rapier physics engine. This means that the Rapier code is only loaded when a physics component is used in the scene.
|
|
33
|
+
*/
|
|
30
34
|
useRapier?: boolean;
|
|
31
|
-
/**
|
|
35
|
+
/** Set to `false` to prevent postprocessing effects from loading.
|
|
36
|
+
* NOTE: by default Needle Engine uses dynamic loading of postprocessing modules. This means that the postprocessing code is only loaded when a postprocessing effect is used in the scene.
|
|
37
|
+
*/
|
|
32
38
|
usePostprocessing?: boolean;
|
|
39
|
+
|
|
33
40
|
noDependencyWatcher?: boolean;
|
|
34
41
|
/** set to false to suppress editor-sync package installation and connection */
|
|
35
42
|
dontInstallEditor?: boolean;
|
|
@@ -169,4 +176,16 @@ export type userSettings = {
|
|
|
169
176
|
|
|
170
177
|
/** Set to true to disable the plugin that ensures VSCode workspace settings for custom-elements.json data */
|
|
171
178
|
noCustomElementData?: boolean;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Generate Typescript declaration files for references 3D assets in your project.
|
|
182
|
+
* These will be available via `context.sceneData` in your code.
|
|
183
|
+
* @default enabled
|
|
184
|
+
*/
|
|
185
|
+
dts?: {
|
|
186
|
+
/** When set to false, disables the generation of TypeScript declaration files.
|
|
187
|
+
* @default true
|
|
188
|
+
*/
|
|
189
|
+
enabled?: boolean;
|
|
190
|
+
}
|
|
172
191
|
}
|
package/plugins/vite/asap.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @param {"build" | "serve"}
|
|
2
|
+
* @param {"build" | "serve" | undefined} _command
|
|
3
3
|
* @param {unknown} _config
|
|
4
4
|
* @param {import('../types').userSettings} userSettings
|
|
5
5
|
* @returns {import('vite').Plugin | null}
|
|
6
6
|
*/
|
|
7
|
-
export function needleDependencyWatcher(
|
|
7
|
+
export function needleDependencyWatcher(_command: "build" | "serve" | undefined, _config: unknown, userSettings: import("../types").userSettings): import("vite").Plugin | null;
|
|
8
8
|
export type PackageJson = {
|
|
9
9
|
dependencies?: Record<string, string>;
|
|
10
10
|
devDependencies?: Record<string, string>;
|
|
@@ -12,14 +12,12 @@ function log(...msg) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @param {"build" | "serve"}
|
|
15
|
+
* @param {"build" | "serve" | undefined} _command
|
|
16
16
|
* @param {unknown} _config
|
|
17
17
|
* @param {import('../types').userSettings} userSettings
|
|
18
18
|
* @returns {import('vite').Plugin | null}
|
|
19
19
|
*/
|
|
20
|
-
export function needleDependencyWatcher(
|
|
21
|
-
if (command === "build") return null;
|
|
22
|
-
|
|
20
|
+
export function needleDependencyWatcher(_command, _config, userSettings) {
|
|
23
21
|
if (userSettings?.noDependencyWatcher === true) return null;
|
|
24
22
|
|
|
25
23
|
const dir = process.cwd();
|
|
@@ -28,6 +26,7 @@ export function needleDependencyWatcher(command, _config, userSettings) {
|
|
|
28
26
|
|
|
29
27
|
return /** @type {import('vite').Plugin} */ ({
|
|
30
28
|
name: 'needle-dependency-watcher',
|
|
29
|
+
apply: 'serve',
|
|
31
30
|
/** @param {import('vite').ViteDevServer} server */
|
|
32
31
|
configureServer(server) {
|
|
33
32
|
manageClients(server);
|
package/plugins/vite/drop.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Experimental, allow dropping files from Unity into the running scene.
|
|
2
|
-
* @param {"build" | "serve"}
|
|
2
|
+
* @param {"build" | "serve" | undefined} _command
|
|
3
3
|
* @param {import('../types/needleConfig').needleMeta | null | undefined} config
|
|
4
4
|
* @param {import('../types/userconfig.js').userSettings} userSettings
|
|
5
5
|
* @returns {import('vite').Plugin | null | undefined}
|
|
6
6
|
*/
|
|
7
|
-
export function needleDrop(
|
|
7
|
+
export function needleDrop(_command: "build" | "serve" | undefined, config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types/userconfig.js").userSettings): import("vite").Plugin | null | undefined;
|
package/plugins/vite/drop.js
CHANGED
|
@@ -7,18 +7,17 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
7
7
|
const __dirname = path.dirname(__filename);
|
|
8
8
|
|
|
9
9
|
/** Experimental, allow dropping files from Unity into the running scene.
|
|
10
|
-
* @param {"build" | "serve"}
|
|
10
|
+
* @param {"build" | "serve" | undefined} _command
|
|
11
11
|
* @param {import('../types/needleConfig').needleMeta | null | undefined} config
|
|
12
12
|
* @param {import('../types/userconfig.js').userSettings} userSettings
|
|
13
13
|
* @returns {import('vite').Plugin | null | undefined}
|
|
14
14
|
*/
|
|
15
|
-
export function needleDrop(
|
|
16
|
-
if (command === "build") return;
|
|
17
|
-
|
|
15
|
+
export function needleDrop(_command, config, userSettings) {
|
|
18
16
|
if(userSettings.useDrop !== true) return null;
|
|
19
17
|
|
|
20
18
|
return {
|
|
21
19
|
name: "needle:drop",
|
|
20
|
+
apply: 'serve',
|
|
22
21
|
config(/** @type {{ server?: { hmr?: { port?: number } } }} */ viteConfig) {
|
|
23
22
|
if(userSettings)
|
|
24
23
|
if (!viteConfig.server) viteConfig.server = {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {"build" | "serve"} _command Vite command (unused — runs in both modes)
|
|
3
|
+
* @param {import('../types/needleConfig').needleMeta | null | undefined} _config
|
|
4
|
+
* @param {import('../types').userSettings} [_userSettings]
|
|
5
|
+
* @returns {import('vite').Plugin | null}
|
|
6
|
+
*/
|
|
7
|
+
export function needleDtsGenerator(_command: "build" | "serve", _config: import("../types/needleConfig").needleMeta | null | undefined, _userSettings?: import("../types").userSettings): import("vite").Plugin | null;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Vite plugin: needle:dts-generator
|
|
4
|
+
*
|
|
5
|
+
* Thin wrapper around plugins/dts-generator/index.js.
|
|
6
|
+
* Regenerates `needle-bindings.d.ts` on startup and whenever a .glb / .gltf
|
|
7
|
+
* file changes in the assets directory.
|
|
8
|
+
*
|
|
9
|
+
* The generated file is written to `{codegenDirectory}/needle-bindings.d.ts`
|
|
10
|
+
* (falls back to `src/generated/needle-bindings.d.ts`).
|
|
11
|
+
*
|
|
12
|
+
* Usage — the plugin is already wired into needlePlugins(). To use standalone:
|
|
13
|
+
*
|
|
14
|
+
* import { needleDtsGenerator } from "@needle-tools/engine/plugins/vite/dts-generator.js";
|
|
15
|
+
* // in vite.config.js plugins array:
|
|
16
|
+
* needleDtsGenerator(command, needleConfig, userSettings)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { join, resolve, dirname } from 'path';
|
|
20
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, realpathSync } from 'fs';
|
|
21
|
+
import { tryLoadProjectConfig } from './config.js';
|
|
22
|
+
import { generateBindingsDts } from '../dts-generator/index.js';
|
|
23
|
+
import { needleLog } from './logging.js';
|
|
24
|
+
|
|
25
|
+
// Two dirs up from plugins/vite/ → package root.
|
|
26
|
+
// Use fileURLToPath so %7E and other URL-encoded characters in the path are decoded correctly.
|
|
27
|
+
// realpathSync follows symlinks so the path is stable even in npm link / monorepo setups.
|
|
28
|
+
import { fileURLToPath } from 'url';
|
|
29
|
+
let _packageRoot = /** @type {string | null} */ (null);
|
|
30
|
+
try {
|
|
31
|
+
_packageRoot = realpathSync(join(dirname(fileURLToPath(import.meta.url)), '..', '..'));
|
|
32
|
+
} catch (_e) {
|
|
33
|
+
// If we can't resolve the package root (e.g. unusual install layout), the plugin
|
|
34
|
+
// will silently skip generation rather than crashing the dev server.
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Ensure `.vscode/settings.json` references the generated `needle-html-data.json`
|
|
39
|
+
* so VS Code provides `data-bind-needle` completions in HTML files automatically.
|
|
40
|
+
* Only adds the entry if it isn't already present — never overwrites other settings.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} projectRoot
|
|
43
|
+
* @param {string} htmlDataPath Absolute path to the generated needle-html-data.json
|
|
44
|
+
*/
|
|
45
|
+
function ensureVscodeHtmlCustomData(projectRoot, htmlDataPath) {
|
|
46
|
+
const vscodeDir = join(projectRoot, ".vscode");
|
|
47
|
+
const settingsPath = join(vscodeDir, "settings.json");
|
|
48
|
+
|
|
49
|
+
// Relative path from project root for portability
|
|
50
|
+
const relPath = htmlDataPath.replace(projectRoot + "/", "").replace(projectRoot + "\\", "");
|
|
51
|
+
|
|
52
|
+
/** @type {Record<string, unknown>} */
|
|
53
|
+
let settings = {};
|
|
54
|
+
if (existsSync(settingsPath)) {
|
|
55
|
+
try {
|
|
56
|
+
settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
57
|
+
} catch (_e) { /* malformed JSON — leave settings empty, will add key */ }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const key = "html.customData";
|
|
61
|
+
const existing = Array.isArray(settings[key]) ? /** @type {string[]} */ (settings[key]) : [];
|
|
62
|
+
if (existing.includes(relPath)) return; // already registered
|
|
63
|
+
|
|
64
|
+
settings[key] = [...existing, relPath];
|
|
65
|
+
|
|
66
|
+
mkdirSync(vscodeDir, { recursive: true });
|
|
67
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
68
|
+
needleLog("needle:dts-generator", `registered HTML completions in .vscode/settings.json`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {"build" | "serve"} _command Vite command (unused — runs in both modes)
|
|
73
|
+
* @param {import('../types/needleConfig').needleMeta | null | undefined} _config
|
|
74
|
+
* @param {import('../types').userSettings} [_userSettings]
|
|
75
|
+
* @returns {import('vite').Plugin | null}
|
|
76
|
+
*/
|
|
77
|
+
export function needleDtsGenerator(_command, _config, _userSettings) {
|
|
78
|
+
|
|
79
|
+
if(_userSettings?.dts?.enabled === false) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let projectRoot = process.cwd();
|
|
84
|
+
|
|
85
|
+
function resolveCodegenDir() {
|
|
86
|
+
const projectConfig = tryLoadProjectConfig();
|
|
87
|
+
return projectConfig?.codegenDirectory
|
|
88
|
+
? resolve(projectRoot, projectConfig.codegenDirectory)
|
|
89
|
+
: join(projectRoot, "src", "generated");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolveOutputPath() {
|
|
93
|
+
// Write to a .needle dotfolder at the package root.
|
|
94
|
+
// Not in the `files` allowlist → never npm-published.
|
|
95
|
+
// ../../.needle/ from plugins/types/ resolves correctly for both
|
|
96
|
+
// symlinked (js/package~/) and published (node_modules/@needle-tools/engine/) layouts.
|
|
97
|
+
return join(/** @type {string} */ (_packageRoot), ".needle", "generated", "needle-bindings.gen.d.ts");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function resolveAssetsDir() {
|
|
101
|
+
const projectConfig = tryLoadProjectConfig();
|
|
102
|
+
return projectConfig?.assetsDirectory
|
|
103
|
+
? resolve(projectRoot, projectConfig.assetsDirectory)
|
|
104
|
+
: join(projectRoot, "assets");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** @type {import('vite').ViteDevServer | undefined} */
|
|
108
|
+
let devServer;
|
|
109
|
+
|
|
110
|
+
/** @type {Promise<void> | null} */
|
|
111
|
+
let _runInFlight = null;
|
|
112
|
+
|
|
113
|
+
function run() {
|
|
114
|
+
if (_runInFlight) return _runInFlight;
|
|
115
|
+
_runInFlight = _doRun().finally(() => { _runInFlight = null; });
|
|
116
|
+
return _runInFlight;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function _doRun() {
|
|
120
|
+
try {
|
|
121
|
+
if (!_packageRoot) return;
|
|
122
|
+
const assetsDir = resolveAssetsDir();
|
|
123
|
+
const outputPath = resolveOutputPath();
|
|
124
|
+
const codegenDir = resolveCodegenDir();
|
|
125
|
+
const count = await generateBindingsDts({ assetsDir, outputPath, projectRoot, codegenDir });
|
|
126
|
+
// HTML custom data sits next to the generated dts in .needle/generated/
|
|
127
|
+
const htmlDataPath = join(/** @type {string} */ (_packageRoot), ".needle", "generated", "needle-html-data.json");
|
|
128
|
+
ensureVscodeHtmlCustomData(projectRoot, htmlDataPath);
|
|
129
|
+
if (count !== false) {
|
|
130
|
+
needleLog("needle:dts-generator", `${count} binding(s) → ${outputPath.replace(process.cwd(), ".")}`);
|
|
131
|
+
if (devServer) {
|
|
132
|
+
const hot = devServer.hot ?? devServer.ws;
|
|
133
|
+
hot.send({ type: "full-reload", path: "*" });
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
needleLog("needle:dts-generator", `up-to-date → ${outputPath.replace(process.cwd(), ".")}`);
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
needleLog("needle:dts-generator", "Failed: " + (/** @type {any} */ (err)?.message ?? err));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
name: "needle:dts-generator",
|
|
145
|
+
|
|
146
|
+
/** @param {import('vite').ResolvedConfig} config */
|
|
147
|
+
configResolved(config) {
|
|
148
|
+
projectRoot = config.root ?? process.cwd();
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
buildStart() {
|
|
152
|
+
// In serve mode, the configureServer post-hook runs instead.
|
|
153
|
+
// Only run here for actual builds (no devServer).
|
|
154
|
+
if (!devServer) return run();
|
|
155
|
+
return undefined;
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/** @param {import('vite').ViteDevServer} server */
|
|
159
|
+
configureServer(server) {
|
|
160
|
+
devServer = server;
|
|
161
|
+
|
|
162
|
+
// Watch assets directory for GLB/glTF changes and regenerate
|
|
163
|
+
const assetsDir = resolveAssetsDir();
|
|
164
|
+
server.watcher.add(assetsDir);
|
|
165
|
+
|
|
166
|
+
// Also watch files that determine which GLBs are entrypoints
|
|
167
|
+
const indexHtmlPath = join(projectRoot, "index.html");
|
|
168
|
+
const genJsPath = join(resolveCodegenDir(), "gen.js");
|
|
169
|
+
server.watcher.add(indexHtmlPath);
|
|
170
|
+
server.watcher.add(genJsPath);
|
|
171
|
+
|
|
172
|
+
server.watcher.on("change", (file) => {
|
|
173
|
+
if (
|
|
174
|
+
(/\.(glb|gltf)$/i.test(file) && file.startsWith(assetsDir)) ||
|
|
175
|
+
file === indexHtmlPath ||
|
|
176
|
+
file === genJsPath
|
|
177
|
+
) {
|
|
178
|
+
run();
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
server.watcher.on("add", (file) => {
|
|
182
|
+
if (/\.(glb|gltf)$/i.test(file) && file.startsWith(assetsDir)) {
|
|
183
|
+
run();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Return post-hook so Vite awaits the initial run before printing "ready"
|
|
188
|
+
return () => run();
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
package/plugins/vite/index.d.ts
CHANGED
|
@@ -19,13 +19,20 @@
|
|
|
19
19
|
* ],
|
|
20
20
|
* }
|
|
21
21
|
* ```
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* When used without arguments (e.g. in a SvelteKit `defineConfig({})` plain object),
|
|
23
|
+
* the command is resolved automatically from Vite's `configResolved` hook.
|
|
24
|
+
* ```js
|
|
25
|
+
* // SvelteKit — no command needed:
|
|
26
|
+
* export default defineConfig({ plugins: [sveltekit(), needlePlugins()] });
|
|
27
|
+
* ```
|
|
28
|
+
* @param {"build" | "serve" | undefined} [command]
|
|
29
|
+
* @param {import('../types/needleConfig').needleMeta | null | undefined} [config]
|
|
24
30
|
* @param {import('../types/index.js').userSettings} [userSettings]
|
|
25
31
|
* @returns {Promise<import('vite').Plugin[]>}
|
|
26
32
|
*/
|
|
27
|
-
export function needlePlugins(command
|
|
33
|
+
export function needlePlugins(command?: "build" | "serve" | undefined, config?: import("../types/needleConfig").needleMeta | null | undefined, userSettings?: import("../types/index.js").userSettings): Promise<import("vite").Plugin[]>;
|
|
28
34
|
export { needleAI } from "./ai.js";
|
|
35
|
+
export { needleDtsGenerator } from "./dts-generator.js";
|
|
29
36
|
export { needleAsap } from "./asap.js";
|
|
30
37
|
export { needleDefines } from "./defines.js";
|
|
31
38
|
export { needleBuildPipeline } from "./build-pipeline.js";
|
package/plugins/vite/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { needleAI } from "./ai.js";
|
|
2
2
|
export { needleAI } from "./ai.js";
|
|
3
3
|
|
|
4
|
+
import { needleDtsGenerator } from "./dts-generator.js";
|
|
5
|
+
export { needleDtsGenerator } from "./dts-generator.js";
|
|
6
|
+
|
|
4
7
|
import { needleAsap } from "./asap.js";
|
|
5
8
|
export { needleAsap } from "./asap.js";
|
|
6
9
|
|
|
@@ -113,12 +116,18 @@ const defaultUserSettings = {
|
|
|
113
116
|
* ],
|
|
114
117
|
* }
|
|
115
118
|
* ```
|
|
116
|
-
*
|
|
117
|
-
*
|
|
119
|
+
* When used without arguments (e.g. in a SvelteKit `defineConfig({})` plain object),
|
|
120
|
+
* the command is resolved automatically from Vite's `configResolved` hook.
|
|
121
|
+
* ```js
|
|
122
|
+
* // SvelteKit — no command needed:
|
|
123
|
+
* export default defineConfig({ plugins: [sveltekit(), needlePlugins()] });
|
|
124
|
+
* ```
|
|
125
|
+
* @param {"build" | "serve" | undefined} [command]
|
|
126
|
+
* @param {import('../types/needleConfig').needleMeta | null | undefined} [config]
|
|
118
127
|
* @param {import('../types/index.js').userSettings} [userSettings]
|
|
119
128
|
* @returns {Promise<import('vite').Plugin[]>}
|
|
120
129
|
*/
|
|
121
|
-
export async function needlePlugins(command, config = undefined, userSettings = {}) {
|
|
130
|
+
export async function needlePlugins(command = undefined, config = undefined, userSettings = {}) {
|
|
122
131
|
|
|
123
132
|
if (!config) config = {}
|
|
124
133
|
|
|
@@ -126,6 +135,7 @@ export async function needlePlugins(command, config = undefined, userSettings =
|
|
|
126
135
|
userSettings = { ...defaultUserSettings, ...userSettings };
|
|
127
136
|
|
|
128
137
|
const array = [
|
|
138
|
+
needleDtsGenerator(command, config, userSettings),
|
|
129
139
|
needleAI(command, config, userSettings),
|
|
130
140
|
needleLogger(command, config, userSettings),
|
|
131
141
|
needleDefines(command, config, userSettings),
|
|
@@ -164,14 +174,21 @@ export async function needlePlugins(command, config = undefined, userSettings =
|
|
|
164
174
|
array.push(await editorConnection(command, config, userSettings, array));
|
|
165
175
|
array.push(needleDependencyWatcher(command, config, userSettings));
|
|
166
176
|
|
|
167
|
-
// Ensure the process exits on SIGINT (Ctrl+C) since plugin timers/sockets can keep the event loop alive
|
|
168
|
-
|
|
177
|
+
// Ensure the process exits on SIGINT (Ctrl+C) since plugin timers/sockets can keep the event loop alive.
|
|
178
|
+
// If command is unknown at call time (e.g. SvelteKit plain defineConfig), defer to configResolved.
|
|
179
|
+
const registerSigint = () => {
|
|
169
180
|
process.on('SIGINT', () => {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
181
|
+
setTimeout(() => { console.debug('\nGoodbye!'); process.exit(); }, 1000);
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
if (command === "serve") {
|
|
185
|
+
registerSigint();
|
|
186
|
+
} else if (command === undefined) {
|
|
187
|
+
array.push({
|
|
188
|
+
name: "needle:sigint",
|
|
189
|
+
configResolved(config) {
|
|
190
|
+
if (config.command === "serve") registerSigint();
|
|
191
|
+
}
|
|
175
192
|
});
|
|
176
193
|
}
|
|
177
194
|
|