@tsparticles/rollup-plugin 3.4.14 → 4.0.0-beta.12
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/dist/buildMap.d.ts +1 -1
- package/dist/buildMap.d.ts.map +1 -1
- package/dist/config/createConfig.d.ts.map +1 -1
- package/dist/config/createSingleConfig.d.ts +1 -0
- package/dist/config/createSingleConfig.d.ts.map +1 -1
- package/dist/config/entry.d.ts +1 -0
- package/dist/config/entry.d.ts.map +1 -1
- package/dist/config/externals.d.ts +3 -4
- package/dist/config/externals.d.ts.map +1 -1
- package/dist/config/umdPolicy.d.ts +6 -0
- package/dist/config/umdPolicy.d.ts.map +1 -0
- package/dist/createParticlesBuild.d.ts.map +1 -1
- package/dist/index.cjs +584 -16
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +584 -17
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
1
2
|
import path from 'node:path';
|
|
3
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
2
4
|
import replace from '@rollup/plugin-replace';
|
|
3
5
|
import terser from '@rollup/plugin-terser';
|
|
4
6
|
import { visualizer } from 'rollup-plugin-visualizer';
|
|
@@ -86,19 +88,276 @@ const buildMap = {
|
|
|
86
88
|
banner: ({ version }) => `Updater v${version}`,
|
|
87
89
|
minBanner: ({ version }) => `Updater v${version}`,
|
|
88
90
|
},
|
|
91
|
+
util: {
|
|
92
|
+
format: "",
|
|
93
|
+
hasBundle: false,
|
|
94
|
+
banner: ({ version }) => `Utility v${version}`,
|
|
95
|
+
minBanner: ({ version, bundleName }) => `tsParticles ${bundleName ?? "Utility"} v${version}`,
|
|
96
|
+
},
|
|
89
97
|
};
|
|
90
98
|
|
|
91
99
|
const getEntry = (data) => {
|
|
92
|
-
const { bundle, format, lazy, min, name } = data, fileName = bundle ? "bundle" : "index", completeFileName = lazy ? `${fileName}.lazy` : fileName, fixFormat = format ? `.${format}` : "", fixName = name ? `.${name}` : "", fixMin = min ? ".min" : "", fixLazy = lazy ? ".lazy" : "";
|
|
100
|
+
const { bundle, dir, format, lazy, min, name } = data, fileName = bundle ? "bundle" : "index", browserFileName = "browser", completeFileName = lazy ? `${fileName}.lazy` : fileName, completeBrowserFileName = lazy ? `${browserFileName}.lazy` : browserFileName, browserCandidate = path.resolve(dir, "dist/browser", `${completeBrowserFileName}.js`), inputFileName = !bundle && fs.existsSync(browserCandidate) ? completeBrowserFileName : completeFileName, fixFormat = format ? `.${format}` : "", fixName = name ? `.${name}` : "", fixMin = min ? ".min" : "", fixLazy = lazy ? ".lazy" : "";
|
|
93
101
|
return {
|
|
94
102
|
name: `tsparticles${fixFormat}${fixName}${fixLazy}${fixMin}`,
|
|
95
|
-
input: `./dist/browser/${
|
|
103
|
+
input: `./dist/browser/${inputFileName}.js`,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const internalRoot = "__tsParticlesInternals";
|
|
108
|
+
const toScopeSegment = (value) => {
|
|
109
|
+
const normalized = value
|
|
110
|
+
.replaceAll(/([a-z\d])([A-Z])/g, "$1-$2")
|
|
111
|
+
.replaceAll(/[._\s]+/g, "-")
|
|
112
|
+
.toLowerCase();
|
|
113
|
+
return normalized
|
|
114
|
+
.split("-")
|
|
115
|
+
.filter(Boolean)
|
|
116
|
+
.map((segment, index) => index === 0 ? segment : `${segment[0]?.toUpperCase() ?? ""}${segment.slice(1)}`)
|
|
117
|
+
.join("");
|
|
118
|
+
};
|
|
119
|
+
const resolveBundleScope = (moduleName) => {
|
|
120
|
+
if (!moduleName) {
|
|
121
|
+
return "full";
|
|
122
|
+
}
|
|
123
|
+
return toScopeSegment(moduleName);
|
|
124
|
+
};
|
|
125
|
+
const resolveKind = (scope) => {
|
|
126
|
+
if (scope === "pjs") {
|
|
127
|
+
return "pjs";
|
|
128
|
+
}
|
|
129
|
+
if (scope === "confetti") {
|
|
130
|
+
return "confetti";
|
|
131
|
+
}
|
|
132
|
+
if (scope === "fireworks") {
|
|
133
|
+
return "fireworks";
|
|
134
|
+
}
|
|
135
|
+
return "bundle";
|
|
136
|
+
};
|
|
137
|
+
const buildTypePrefix = {
|
|
138
|
+
effect: "effects",
|
|
139
|
+
interaction: "interactions",
|
|
140
|
+
interactionExternal: "interactions",
|
|
141
|
+
interactionParticles: "interactions",
|
|
142
|
+
palette: "palettes",
|
|
143
|
+
path: "paths",
|
|
144
|
+
plugin: "plugins",
|
|
145
|
+
pluginEasing: "plugins",
|
|
146
|
+
pluginEmittersShape: "plugins.emittersShapes",
|
|
147
|
+
pluginExport: "plugins",
|
|
148
|
+
preset: "presets",
|
|
149
|
+
shape: "shapes",
|
|
150
|
+
template: "utils",
|
|
151
|
+
updater: "updaters",
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Qualifies a raw module-name leaf with a type-specific prefix so that
|
|
155
|
+
* `getUmdPolicyData` produces the same namespace as `getUmdGlobalForExternal`.
|
|
156
|
+
* Without this, `interactionExternal "parallax"` would land on
|
|
157
|
+
* `interactions.parallax` while the non-bundled consumer expects
|
|
158
|
+
* `interactions.externalParallax`, causing a UMD global mismatch.
|
|
159
|
+
*/
|
|
160
|
+
const leafPrefixes = {
|
|
161
|
+
interactionExternal: "external-",
|
|
162
|
+
interactionParticles: "particles-",
|
|
163
|
+
pluginEasing: "easing-",
|
|
164
|
+
};
|
|
165
|
+
const qualifyLeaf = (type, rawLeaf) => {
|
|
166
|
+
const prefix = leafPrefixes[type];
|
|
167
|
+
return prefix ? `${prefix}${rawLeaf}` : rawLeaf;
|
|
168
|
+
};
|
|
169
|
+
const getUmdPolicyData = (type, moduleName) => {
|
|
170
|
+
if (type === "engine") {
|
|
171
|
+
return {
|
|
172
|
+
kind: "engine",
|
|
173
|
+
scope: `${internalRoot}.engine`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (type === "bundle") {
|
|
177
|
+
const scope = resolveBundleScope(moduleName);
|
|
178
|
+
return {
|
|
179
|
+
kind: resolveKind(scope),
|
|
180
|
+
scope: `${internalRoot}.bundles.${scope}`,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (type === "util") {
|
|
184
|
+
// Util packages use the moduleName as-is (dots as separators), e.g. "canvas.utils" -> "__tsParticlesInternals.canvas.utils"
|
|
185
|
+
// This must match the getUmdGlobalForExternal fallback for deps that reference these packages.
|
|
186
|
+
return {
|
|
187
|
+
kind: "package",
|
|
188
|
+
scope: `${internalRoot}.${moduleName ?? "util"}`,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const prefix = buildTypePrefix[type], rawLeaf = moduleName ?? "default", leaf = toScopeSegment(qualifyLeaf(type, rawLeaf));
|
|
192
|
+
return {
|
|
193
|
+
kind: "package",
|
|
194
|
+
scope: `${internalRoot}.${prefix}.${leaf}`,
|
|
96
195
|
};
|
|
97
196
|
};
|
|
197
|
+
const buildScopedPath = (prefix, rawLeaf) => {
|
|
198
|
+
const leaf = toScopeSegment(rawLeaf);
|
|
199
|
+
return `${internalRoot}.${prefix}.${leaf}`;
|
|
200
|
+
};
|
|
201
|
+
const bundleLeafGlobals = new Map(["all", "basic", "confetti", "fireworks", "pjs", "slim"].map(leaf => [leaf, `${internalRoot}.bundles.${leaf}`]));
|
|
202
|
+
const scopedPrefixRules = [
|
|
203
|
+
{
|
|
204
|
+
// @tsparticles/plugin-export-image -> __tsParticlesInternals.plugins.image
|
|
205
|
+
prefix: "plugin-export-",
|
|
206
|
+
scope: "plugins",
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
prefix: "plugin-emitters-shape-",
|
|
210
|
+
scope: "plugins.emittersShapes",
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
prefix: "plugin-",
|
|
214
|
+
scope: "plugins",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
prefix: "interaction-external-",
|
|
218
|
+
scope: "interactions",
|
|
219
|
+
transform: segment => `external-${segment}`,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
prefix: "interaction-particles-",
|
|
223
|
+
scope: "interactions",
|
|
224
|
+
transform: segment => `particles-${segment}`,
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
prefix: "interaction-",
|
|
228
|
+
scope: "interactions",
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
prefix: "effect-",
|
|
232
|
+
scope: "effects",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
prefix: "path-",
|
|
236
|
+
scope: "paths",
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
prefix: "shape-",
|
|
240
|
+
scope: "shapes",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
prefix: "updater-",
|
|
244
|
+
scope: "updaters",
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
prefix: "palette-",
|
|
248
|
+
scope: "palettes",
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
prefix: "preset-",
|
|
252
|
+
scope: "presets",
|
|
253
|
+
},
|
|
254
|
+
];
|
|
255
|
+
const getScopedGlobalFromPrefix = (leaf) => {
|
|
256
|
+
for (const rule of scopedPrefixRules) {
|
|
257
|
+
if (!leaf.startsWith(rule.prefix)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const segment = leaf.slice(rule.prefix.length);
|
|
261
|
+
return buildScopedPath(rule.scope, rule.transform ? rule.transform(segment) : segment);
|
|
262
|
+
}
|
|
263
|
+
return undefined;
|
|
264
|
+
};
|
|
265
|
+
const getScopedGlobalForLeaf = (leaf) => {
|
|
266
|
+
const directLeafMap = new Map([
|
|
267
|
+
["engine", `${internalRoot}.engine`],
|
|
268
|
+
// Util packages: not "path plugins" but helper utilities; map to their actual scope
|
|
269
|
+
["path-utils", `${internalRoot}.path.utils`],
|
|
270
|
+
["canvas-utils", `${internalRoot}.canvas.utils`],
|
|
271
|
+
// Historical package name mismatch: @tsparticles/path-zig-zag exposes paths.zigzag.
|
|
272
|
+
["path-zig-zag", `${internalRoot}.paths.zigzag`],
|
|
273
|
+
// Historical package name mismatch: @tsparticles/plugin-poisson-disc exposes plugins.poisson.
|
|
274
|
+
["plugin-poisson-disc", `${internalRoot}.plugins.poisson`],
|
|
275
|
+
...bundleLeafGlobals,
|
|
276
|
+
]), bundleLeaf = directLeafMap.get(leaf);
|
|
277
|
+
if (bundleLeaf) {
|
|
278
|
+
return bundleLeaf;
|
|
279
|
+
}
|
|
280
|
+
const scopedLeaf = getScopedGlobalFromPrefix(leaf);
|
|
281
|
+
if (scopedLeaf) {
|
|
282
|
+
return scopedLeaf;
|
|
283
|
+
}
|
|
284
|
+
return `${internalRoot}.${leaf.split("-").map(toScopeSegment).join(".")}`;
|
|
285
|
+
};
|
|
286
|
+
const getUmdGlobalForExternal = (id) => {
|
|
287
|
+
if (id === "tsparticles") {
|
|
288
|
+
return `${internalRoot}.bundles.full`;
|
|
289
|
+
}
|
|
290
|
+
if (id.startsWith("tsparticles-")) {
|
|
291
|
+
return buildScopedPath("bundles", id.slice("tsparticles-".length));
|
|
292
|
+
}
|
|
293
|
+
if (!id.startsWith("@tsparticles/")) {
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
return getScopedGlobalForLeaf(id.slice("@tsparticles/".length));
|
|
297
|
+
};
|
|
298
|
+
const getUmdGlobalsBootstrap = (temporaryGlobalName) => {
|
|
299
|
+
const temporaryBootstrap = `g.${temporaryGlobalName}=g.${temporaryGlobalName}||{};`
|
|
300
|
+
;
|
|
301
|
+
// Pre-create namespaces (including nested ones) to avoid eager UMD external lookups
|
|
302
|
+
// crashing on missing branches like plugins.emittersShapes.circle.
|
|
303
|
+
const namespaces = [
|
|
304
|
+
"bundles",
|
|
305
|
+
"effects",
|
|
306
|
+
"engine",
|
|
307
|
+
"interactions",
|
|
308
|
+
"palettes",
|
|
309
|
+
"paths",
|
|
310
|
+
"plugins",
|
|
311
|
+
"plugins.emittersShapes",
|
|
312
|
+
"presets",
|
|
313
|
+
"shapes",
|
|
314
|
+
"updaters",
|
|
315
|
+
"utils",
|
|
316
|
+
"canvas",
|
|
317
|
+
"canvas.utils",
|
|
318
|
+
"path",
|
|
319
|
+
"path.utils",
|
|
320
|
+
], namespacesBootstrap = namespaces
|
|
321
|
+
.map(namespace => {
|
|
322
|
+
const segments = namespace.split(".");
|
|
323
|
+
let currentPath = "g.__tsParticlesInternals";
|
|
324
|
+
return segments
|
|
325
|
+
.map(segment => {
|
|
326
|
+
currentPath += `.${segment}`;
|
|
327
|
+
return `${currentPath}=${currentPath}||{};`;
|
|
328
|
+
})
|
|
329
|
+
.join("");
|
|
330
|
+
})
|
|
331
|
+
.join("");
|
|
332
|
+
return (`(function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};${namespacesBootstrap}` +
|
|
333
|
+
`var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};` +
|
|
334
|
+
`g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);` +
|
|
335
|
+
`g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);` +
|
|
336
|
+
`g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);` +
|
|
337
|
+
`g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);` +
|
|
338
|
+
`g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);` +
|
|
339
|
+
`g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);` +
|
|
340
|
+
`g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);` +
|
|
341
|
+
`g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);` +
|
|
342
|
+
`g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);` +
|
|
343
|
+
`g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);` +
|
|
344
|
+
`g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);` +
|
|
345
|
+
`g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);` +
|
|
346
|
+
`g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);` +
|
|
347
|
+
`${temporaryBootstrap}})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);\n`);
|
|
348
|
+
};
|
|
98
349
|
|
|
350
|
+
const defaultGlobal = "window";
|
|
351
|
+
const getRootGlobal = (external) => {
|
|
352
|
+
const root = external.data?.root;
|
|
353
|
+
if (Array.isArray(root)) {
|
|
354
|
+
return root.filter((t) => typeof t === "string").join(".") || defaultGlobal;
|
|
355
|
+
}
|
|
356
|
+
return typeof root === "string" ? root : defaultGlobal;
|
|
357
|
+
};
|
|
99
358
|
const getExternal = ({ bundle, additionalExternals = [] }) => {
|
|
100
359
|
if (bundle) {
|
|
101
|
-
return
|
|
360
|
+
return additionalExternals.filter(e => !e.bundle).map(e => e.name);
|
|
102
361
|
}
|
|
103
362
|
return [
|
|
104
363
|
...additionalExternals.map(e => e.name),
|
|
@@ -108,22 +367,302 @@ const getExternal = ({ bundle, additionalExternals = [] }) => {
|
|
|
108
367
|
];
|
|
109
368
|
};
|
|
110
369
|
const getGlobals = (additionalExternals = [], bundle) => {
|
|
111
|
-
|
|
112
|
-
|
|
370
|
+
const globalsAdditional = bundle ? additionalExternals.filter(e => !e.bundle) : additionalExternals;
|
|
371
|
+
const additionalMap = new Map(globalsAdditional.map(e => [e.name, getRootGlobal(e)]));
|
|
372
|
+
return (id) => {
|
|
373
|
+
if (additionalMap.has(id)) {
|
|
374
|
+
return additionalMap.get(id) ?? defaultGlobal;
|
|
375
|
+
}
|
|
376
|
+
const tsparticlesGlobal = getUmdGlobalForExternal(id);
|
|
377
|
+
if (tsparticlesGlobal) {
|
|
378
|
+
return tsparticlesGlobal;
|
|
379
|
+
}
|
|
380
|
+
return defaultGlobal;
|
|
381
|
+
};
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const toJsBanner = (text) => {
|
|
385
|
+
return `/* ${text} */`;
|
|
386
|
+
};
|
|
387
|
+
const temporaryUmdGlobal = "tsparticlesInternalExports";
|
|
388
|
+
const lazyWrapperVirtualPrefix = "\0tsparticles-lazy-wrapper:";
|
|
389
|
+
// Public export predicate per kind
|
|
390
|
+
const getPublicExports = (exports$1, kind) => {
|
|
391
|
+
const fixedPublicMap = {
|
|
392
|
+
confetti: "confetti",
|
|
393
|
+
engine: "tsParticles",
|
|
394
|
+
fireworks: "fireworks",
|
|
395
|
+
pjs: "initPjs",
|
|
396
|
+
};
|
|
397
|
+
if (kind === "bundle") {
|
|
398
|
+
// Bundles expose load* functions AND the tsParticles instance (needed for bundle users)
|
|
399
|
+
return exports$1.filter(t => /^load[A-Z]/.test(t) || t === "tsParticles");
|
|
400
|
+
}
|
|
401
|
+
if (kind === "package") {
|
|
402
|
+
return exports$1.filter(t => /^load[A-Z]/.test(t));
|
|
113
403
|
}
|
|
114
|
-
|
|
404
|
+
const requiredExport = fixedPublicMap[kind];
|
|
405
|
+
if (!exports$1.includes(requiredExport)) {
|
|
406
|
+
throw new Error(`UMD public export policy violated: missing ${requiredExport}`);
|
|
407
|
+
}
|
|
408
|
+
return [requiredExport];
|
|
409
|
+
};
|
|
410
|
+
const validatePublicExports = (publicExports, allExports, kind) => {
|
|
411
|
+
const fixedPublicMap = {
|
|
412
|
+
confetti: "confetti",
|
|
413
|
+
engine: "tsParticles",
|
|
414
|
+
fireworks: "fireworks",
|
|
415
|
+
pjs: "initPjs",
|
|
416
|
+
};
|
|
417
|
+
if (kind !== "bundle" && kind !== "package") {
|
|
418
|
+
const required = fixedPublicMap[kind];
|
|
419
|
+
if (!allExports.includes(required)) {
|
|
420
|
+
throw new Error(`UMD public export policy violated: missing ${required}`);
|
|
421
|
+
}
|
|
422
|
+
if (publicExports.length !== 1 || publicExports[0] !== required) {
|
|
423
|
+
throw new Error(`UMD public export policy violated: ${kind} can expose only ${required}`);
|
|
424
|
+
}
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
// For bundle/package: only load* (and tsParticles for bundle) are allowed on window
|
|
428
|
+
const invalid = publicExports.filter(t => !/^load[A-Z]/.test(t) && t !== "tsParticles");
|
|
429
|
+
if (invalid.length > 0) {
|
|
430
|
+
throw new Error(`UMD public export policy violated: only load* exports (and tsParticles for bundles) are allowed on window, found ${invalid.join(", ")}`);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
/**
|
|
434
|
+
* Build the namespace initialization expression to use as the UMD factory's first argument.
|
|
435
|
+
* Example: scope = "__tsParticlesInternals.engine"
|
|
436
|
+
* Result: "(global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.engine = global.__tsParticlesInternals.engine || {})"
|
|
437
|
+
*
|
|
438
|
+
* This is used to REPLACE `global.window = global.tsparticlesInternalExports || {}` in the UMD wrapper,
|
|
439
|
+
* so that rollup writes all exports directly into the correct namespace object.
|
|
440
|
+
*/
|
|
441
|
+
const buildGlobalNamespaceInit = (scope) => {
|
|
442
|
+
const segments = scope.split(".");
|
|
443
|
+
const inits = [];
|
|
444
|
+
let currentPath = "global";
|
|
445
|
+
for (const segment of segments) {
|
|
446
|
+
currentPath += `.${segment}`;
|
|
447
|
+
inits.push(`${currentPath} = ${currentPath} || {}`);
|
|
448
|
+
}
|
|
449
|
+
return `(${inits.join(", ")})`;
|
|
450
|
+
};
|
|
451
|
+
/**
|
|
452
|
+
* Replace the UMD factory's exports target (global.window = ...) with the correct namespace path.
|
|
453
|
+
* This makes rollup write all `exports.X = X` directly into __tsParticlesInternals.<scope>.
|
|
454
|
+
*/
|
|
455
|
+
const redirectUmdExportsToNamespace = (code, scope) => {
|
|
456
|
+
const namespaceInit = buildGlobalNamespaceInit(scope);
|
|
457
|
+
return code
|
|
458
|
+
// multi-dependency case: factory(global.window = ..., globalDep1, ...)
|
|
459
|
+
.replaceAll(`factory(global.window = global.${temporaryUmdGlobal} || {}, `, `factory(${namespaceInit}, `)
|
|
460
|
+
.replaceAll(`factory(global.window = {}, `, `factory(${namespaceInit}, `)
|
|
461
|
+
// single case: factory(global.window = ...)
|
|
462
|
+
.replaceAll(`factory(global.window = global.${temporaryUmdGlobal} || {})`, `factory(${namespaceInit})`)
|
|
463
|
+
.replaceAll(`factory(global.window = {})`, `factory(${namespaceInit})`);
|
|
464
|
+
};
|
|
465
|
+
/**
|
|
466
|
+
* Build the code that copies public exports from the namespace to window.
|
|
467
|
+
* Reads from globalThis.__tsParticlesInternals.<scope>.<export> after the factory has run.
|
|
468
|
+
*/
|
|
469
|
+
const buildWindowExposureCode = (scope, publicExports) => {
|
|
470
|
+
if (publicExports.length === 0) {
|
|
471
|
+
return "";
|
|
472
|
+
}
|
|
473
|
+
const assignments = publicExports.map(exp => `${exp}: (globalThis.${scope} || {}).${exp}`).join(", ");
|
|
474
|
+
return `Object.assign(globalThis.window || globalThis, { ${assignments} });\n`;
|
|
475
|
+
};
|
|
476
|
+
const buildBundleEngineAliasCode = (umdPolicy) => {
|
|
477
|
+
if (umdPolicy.kind !== "bundle") {
|
|
478
|
+
return "";
|
|
479
|
+
}
|
|
480
|
+
// Keep backward compatibility for packages that still resolve engine externals from internals.engine.
|
|
481
|
+
return (`globalThis.__tsParticlesInternals = globalThis.__tsParticlesInternals || {};\n` +
|
|
482
|
+
`if (!globalThis.__tsParticlesInternals.engine || !globalThis.__tsParticlesInternals.engine.tsParticles) {\n` +
|
|
483
|
+
` globalThis.__tsParticlesInternals.engine = globalThis.${umdPolicy.scope} || {};\n` +
|
|
484
|
+
`}\n`);
|
|
485
|
+
};
|
|
486
|
+
const buildLazyRuntimePath = (name) => {
|
|
487
|
+
return `chunks/${name}.js`;
|
|
115
488
|
};
|
|
489
|
+
const getLazyRuntimeInputPath = (dir) => {
|
|
490
|
+
return path.resolve(dir, "dist/browser/index.lazy.js");
|
|
491
|
+
};
|
|
492
|
+
const parseNamedExports = (content) => {
|
|
493
|
+
const exports$1 = new Set();
|
|
494
|
+
for (const match of content.matchAll(/export\s+(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/g)) {
|
|
495
|
+
exports$1.add(match[1]);
|
|
496
|
+
}
|
|
497
|
+
for (const match of content.matchAll(/export\s*{([^}]+)}(?!\s*from)/g)) {
|
|
498
|
+
const values = match[1]
|
|
499
|
+
.split(",")
|
|
500
|
+
.map(value => value.trim())
|
|
501
|
+
.filter(Boolean)
|
|
502
|
+
.map(value => value.split(/\s+as\s+/).pop()?.trim())
|
|
503
|
+
.filter((value) => Boolean(value));
|
|
504
|
+
for (const value of values) {
|
|
505
|
+
exports$1.add(value);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return [...exports$1];
|
|
509
|
+
};
|
|
510
|
+
const resolveLazyEntryExports = (filePath, visited = new Set()) => {
|
|
511
|
+
if (visited.has(filePath) || !fs.existsSync(filePath)) {
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
visited.add(filePath);
|
|
515
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
516
|
+
const exports$1 = new Set(parseNamedExports(content));
|
|
517
|
+
for (const match of content.matchAll(/export\s+(?:\*|{[^}]+})\s+from\s+["'](.+?)["']/g)) {
|
|
518
|
+
const specifier = match[1];
|
|
519
|
+
if (!specifier.startsWith(".")) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const resolvedPath = path.resolve(path.dirname(filePath), specifier);
|
|
523
|
+
const normalizedPath = path.extname(resolvedPath) ? resolvedPath : `${resolvedPath}.js`;
|
|
524
|
+
for (const value of resolveLazyEntryExports(normalizedPath, visited)) {
|
|
525
|
+
exports$1.add(value);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return [...exports$1];
|
|
529
|
+
};
|
|
530
|
+
const createLazyWrapperEntryPlugin = (params, min) => {
|
|
531
|
+
const { dir, umdPolicy } = params;
|
|
532
|
+
const { name } = getEntry({ ...params.entry, dir, min, lazy: true });
|
|
533
|
+
const runtimePath = buildLazyRuntimePath(name);
|
|
534
|
+
const runtimeInputPath = getLazyRuntimeInputPath(dir);
|
|
535
|
+
const lazyExports = resolveLazyEntryExports(runtimeInputPath);
|
|
536
|
+
const publicExports = getPublicExports([...new Set(umdPolicy.kind === "bundle" ? [...lazyExports, "tsParticles"] : lazyExports)], umdPolicy.kind);
|
|
537
|
+
const needsEngineExports = publicExports.includes("tsParticles") || umdPolicy.kind === "bundle";
|
|
538
|
+
const exportedDeclarations = publicExports
|
|
539
|
+
.filter(exp => exp !== "tsParticles")
|
|
540
|
+
.map(exp => `const ${exp} = async (...args) => { const module = await getLazyModule(); return module.${exp}(...args); };`)
|
|
541
|
+
.join("\n");
|
|
542
|
+
const tsParticlesExport = publicExports.includes("tsParticles")
|
|
543
|
+
? "const tsParticles = engineExports.tsParticles;"
|
|
544
|
+
: "";
|
|
545
|
+
const namedExports = publicExports.join(", ");
|
|
546
|
+
const engineBootstrap = needsEngineExports
|
|
547
|
+
? [
|
|
548
|
+
"globalThis.__tsParticlesInternals = globalThis.__tsParticlesInternals || {};",
|
|
549
|
+
"globalThis.__tsParticlesInternals.engine = globalThis.__tsParticlesInternals.engine || engineExports;",
|
|
550
|
+
].join("\n")
|
|
551
|
+
: "";
|
|
552
|
+
const imports = needsEngineExports ? 'import * as engineExports from "@tsparticles/engine";\n' : "";
|
|
553
|
+
const source = `${imports}
|
|
554
|
+
const currentScript = typeof document !== "undefined" ? document.currentScript : undefined;
|
|
555
|
+
const runtimeUrl = new URL("${runtimePath}", currentScript?.src ?? globalThis.location?.href ?? "/").href;
|
|
556
|
+
let lazyModulePromise;
|
|
557
|
+
const dynamicImport = new Function("path", "return import(path);");
|
|
558
|
+
const getLazyModule = () => {
|
|
559
|
+
lazyModulePromise ??= dynamicImport(runtimeUrl);
|
|
116
560
|
|
|
561
|
+
return lazyModulePromise;
|
|
562
|
+
};
|
|
563
|
+
${engineBootstrap}
|
|
564
|
+
${tsParticlesExport}
|
|
565
|
+
${exportedDeclarations}
|
|
566
|
+
export { ${namedExports} };
|
|
567
|
+
`;
|
|
568
|
+
return {
|
|
569
|
+
name: "tsparticles-lazy-wrapper-entry",
|
|
570
|
+
resolveId(id) {
|
|
571
|
+
return id === `${lazyWrapperVirtualPrefix}${name}` ? id : null;
|
|
572
|
+
},
|
|
573
|
+
load(id) {
|
|
574
|
+
return id === `${lazyWrapperVirtualPrefix}${name}` ? source : null;
|
|
575
|
+
},
|
|
576
|
+
};
|
|
577
|
+
};
|
|
578
|
+
const exposeEntryExports = (enabled, umdPolicy) => {
|
|
579
|
+
return {
|
|
580
|
+
name: "expose-entry-exports",
|
|
581
|
+
renderChunk(code, chunk) {
|
|
582
|
+
if (!chunk.isEntry) {
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
const exports$1 = chunk.exports.filter(t => t !== "default");
|
|
586
|
+
// No exports at all - just bootstrap namespace and clean up
|
|
587
|
+
if (exports$1.length === 0) {
|
|
588
|
+
if (!umdPolicy) {
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
const umdCode = redirectUmdExportsToNamespace(code, umdPolicy.scope);
|
|
592
|
+
return {
|
|
593
|
+
code: `${getUmdGlobalsBootstrap(temporaryUmdGlobal)}${umdCode}\ndelete (globalThis.window || globalThis).${temporaryUmdGlobal};\n`,
|
|
594
|
+
map: null,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
// No UMD policy (e.g. ESM lazy split bundles) - expose all to window (old behavior)
|
|
598
|
+
if (!umdPolicy) {
|
|
599
|
+
const assignments = exports$1.map(t => `${t}: ${t}`).join(", ");
|
|
600
|
+
return {
|
|
601
|
+
code: `${code}\nObject.assign(globalThis.window || globalThis, { ${assignments} });\n`,
|
|
602
|
+
map: null,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
// With UMD policy:
|
|
606
|
+
// 1) Redirect factory's exports target to the internal namespace
|
|
607
|
+
// 2) After factory runs, copy public exports from namespace to window
|
|
608
|
+
const publicExports = getPublicExports(exports$1, umdPolicy.kind);
|
|
609
|
+
validatePublicExports(publicExports, exports$1, umdPolicy.kind);
|
|
610
|
+
// The key step: replace factory's first arg so rollup writes all exports to __tsParticlesInternals.<scope>
|
|
611
|
+
const umdCode = redirectUmdExportsToNamespace(code, umdPolicy.scope);
|
|
612
|
+
// Read public exports from the namespace and expose on window
|
|
613
|
+
const windowCode = buildWindowExposureCode(umdPolicy.scope, publicExports);
|
|
614
|
+
const engineAliasCode = buildBundleEngineAliasCode(umdPolicy);
|
|
615
|
+
return {
|
|
616
|
+
code: `${getUmdGlobalsBootstrap(temporaryUmdGlobal)}${umdCode}\n${windowCode}${engineAliasCode}` +
|
|
617
|
+
`delete (globalThis.window || globalThis).${temporaryUmdGlobal};\n`,
|
|
618
|
+
map: null,
|
|
619
|
+
};
|
|
620
|
+
},
|
|
621
|
+
};
|
|
622
|
+
};
|
|
117
623
|
const createSingleConfig = (params, min, lazy) => {
|
|
118
|
-
const { additionalExternals, banner, bundle, dir, entry, minBanner, version
|
|
624
|
+
const { additionalExternals, banner, bundle, dir, entry, minBanner, version } = params, { name, input } = getEntry({ ...entry, dir, min, lazy }), wrapperEntryPlugin = lazy ? createLazyWrapperEntryPlugin(params, min) : undefined;
|
|
625
|
+
if (lazy) {
|
|
626
|
+
return {
|
|
627
|
+
input: `${lazyWrapperVirtualPrefix}${name}`,
|
|
628
|
+
external: getExternal({ bundle, additionalExternals }),
|
|
629
|
+
plugins: [
|
|
630
|
+
wrapperEntryPlugin,
|
|
631
|
+
nodeResolve({
|
|
632
|
+
browser: true,
|
|
633
|
+
}),
|
|
634
|
+
replace({
|
|
635
|
+
preventAssignment: true,
|
|
636
|
+
__VERSION__: JSON.stringify(version),
|
|
637
|
+
}),
|
|
638
|
+
exposeEntryExports(true, params.umdPolicy),
|
|
639
|
+
min && terser(),
|
|
640
|
+
].filter(Boolean),
|
|
641
|
+
output: {
|
|
642
|
+
file: path.resolve(dir, "dist", `${name}.js`),
|
|
643
|
+
format: "umd",
|
|
644
|
+
name: temporaryUmdGlobal,
|
|
645
|
+
globals: getGlobals(additionalExternals, bundle),
|
|
646
|
+
banner: toJsBanner(min ? minBanner : banner),
|
|
647
|
+
// inlineDynamicImports must be true for UMD (Rollup doesn't support code-splitting in UMD format).
|
|
648
|
+
// The actual lazy loading is handled at runtime via `new Function("path", "return import(path)")`
|
|
649
|
+
// which Rollup cannot see/inline — so setting this to true has no effect on lazy behaviour.
|
|
650
|
+
inlineDynamicImports: true,
|
|
651
|
+
},
|
|
652
|
+
};
|
|
653
|
+
}
|
|
119
654
|
return {
|
|
120
655
|
input,
|
|
121
656
|
external: getExternal({ bundle, additionalExternals }),
|
|
122
657
|
plugins: [
|
|
658
|
+
nodeResolve({
|
|
659
|
+
browser: true,
|
|
660
|
+
}),
|
|
123
661
|
replace({
|
|
124
662
|
preventAssignment: true,
|
|
125
663
|
__VERSION__: JSON.stringify(version),
|
|
126
664
|
}),
|
|
665
|
+
exposeEntryExports(true, params.umdPolicy),
|
|
127
666
|
!min &&
|
|
128
667
|
visualizer({
|
|
129
668
|
filename: path.resolve(dir, "dist/report.html"),
|
|
@@ -133,21 +672,44 @@ const createSingleConfig = (params, min, lazy) => {
|
|
|
133
672
|
output: {
|
|
134
673
|
file: path.resolve(dir, "dist", `${name}.js`),
|
|
135
674
|
format: "umd",
|
|
136
|
-
name:
|
|
675
|
+
name: temporaryUmdGlobal,
|
|
137
676
|
globals: getGlobals(additionalExternals, bundle),
|
|
138
|
-
banner: min ? minBanner : banner,
|
|
677
|
+
banner: toJsBanner(min ? minBanner : banner),
|
|
139
678
|
inlineDynamicImports: true,
|
|
140
679
|
},
|
|
141
680
|
};
|
|
142
681
|
};
|
|
682
|
+
const createLazyRuntimeConfig = (params, min) => {
|
|
683
|
+
const { additionalExternals, banner, bundle, dir, entry, minBanner, version } = params, { name } = getEntry({ ...entry, dir, min, lazy: true });
|
|
684
|
+
return {
|
|
685
|
+
input: getLazyRuntimeInputPath(dir),
|
|
686
|
+
external: getExternal({ bundle, additionalExternals }),
|
|
687
|
+
plugins: [
|
|
688
|
+
nodeResolve({
|
|
689
|
+
browser: true,
|
|
690
|
+
}),
|
|
691
|
+
replace({
|
|
692
|
+
preventAssignment: true,
|
|
693
|
+
__VERSION__: JSON.stringify(version),
|
|
694
|
+
}),
|
|
695
|
+
min && terser(),
|
|
696
|
+
].filter(Boolean),
|
|
697
|
+
output: {
|
|
698
|
+
dir: path.resolve(dir, "dist"),
|
|
699
|
+
format: "es",
|
|
700
|
+
entryFileNames: buildLazyRuntimePath(name),
|
|
701
|
+
chunkFileNames: min ? "chunks/[name]-[hash].min.js" : "chunks/[name]-[hash].js",
|
|
702
|
+
banner: toJsBanner(min ? minBanner : banner),
|
|
703
|
+
},
|
|
704
|
+
};
|
|
705
|
+
};
|
|
143
706
|
|
|
144
707
|
const createConfig = (params) => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
createSingleConfig(params, true,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
];
|
|
708
|
+
const configs = [createSingleConfig(params, false, false), createSingleConfig(params, true, false)];
|
|
709
|
+
if (params.includeLazy) {
|
|
710
|
+
configs.push(createLazyRuntimeConfig(params, false), createSingleConfig(params, false, true), createLazyRuntimeConfig(params, true), createSingleConfig(params, true, true));
|
|
711
|
+
}
|
|
712
|
+
return configs;
|
|
151
713
|
};
|
|
152
714
|
|
|
153
715
|
const createParticlesBuild = (type, params) => {
|
|
@@ -155,7 +717,7 @@ const createParticlesBuild = (type, params) => {
|
|
|
155
717
|
if (!def) {
|
|
156
718
|
throw new Error(`Unknown build type: ${type}`);
|
|
157
719
|
}
|
|
158
|
-
const dir = params.dir, version = params.version, additionalExternals = params.additionalExternals, moduleName = params.moduleName, bundle = params.bundle, banner = def.banner(params), minBanner = def.minBanner(params), base = createConfig({
|
|
720
|
+
const dir = params.dir, version = params.version, additionalExternals = params.additionalExternals, moduleName = params.moduleName, bundle = params.bundle, umdPolicy = getUmdPolicyData(type, moduleName), banner = def.banner(params), minBanner = def.minBanner(params), base = createConfig({
|
|
159
721
|
entry: {
|
|
160
722
|
format: def.format,
|
|
161
723
|
name: moduleName,
|
|
@@ -166,6 +728,8 @@ const createParticlesBuild = (type, params) => {
|
|
|
166
728
|
minBanner,
|
|
167
729
|
dir,
|
|
168
730
|
bundle: false,
|
|
731
|
+
includeLazy: false,
|
|
732
|
+
umdPolicy,
|
|
169
733
|
additionalExternals,
|
|
170
734
|
});
|
|
171
735
|
if (def.hasBundle && (bundle ?? true)) {
|
|
@@ -184,6 +748,8 @@ const createParticlesBuild = (type, params) => {
|
|
|
184
748
|
minBanner,
|
|
185
749
|
dir,
|
|
186
750
|
bundle: true,
|
|
751
|
+
includeLazy: false,
|
|
752
|
+
umdPolicy,
|
|
187
753
|
additionalExternals,
|
|
188
754
|
}),
|
|
189
755
|
];
|
|
@@ -207,5 +773,6 @@ const loadParticlesPreset = (p) => createParticlesBuild("preset", p);
|
|
|
207
773
|
const loadParticlesShape = (p) => createParticlesBuild("shape", p);
|
|
208
774
|
const loadParticlesTemplate = (p) => createParticlesBuild("template", p);
|
|
209
775
|
const loadParticlesUpdater = (p) => createParticlesBuild("updater", p);
|
|
776
|
+
const loadParticlesUtil = (p) => createParticlesBuild("util", p);
|
|
210
777
|
|
|
211
|
-
export { createParticlesBuild, loadParticlesBundle, loadParticlesEffect, loadParticlesEngine, loadParticlesInteraction, loadParticlesInteractionExternal, loadParticlesInteractionParticles, loadParticlesPalette, loadParticlesPath, loadParticlesPlugin, loadParticlesPluginEasing, loadParticlesPluginEmittersShape, loadParticlesPluginExport, loadParticlesPreset, loadParticlesShape, loadParticlesTemplate, loadParticlesUpdater };
|
|
778
|
+
export { createParticlesBuild, loadParticlesBundle, loadParticlesEffect, loadParticlesEngine, loadParticlesInteraction, loadParticlesInteractionExternal, loadParticlesInteractionParticles, loadParticlesPalette, loadParticlesPath, loadParticlesPlugin, loadParticlesPluginEasing, loadParticlesPluginEmittersShape, loadParticlesPluginExport, loadParticlesPreset, loadParticlesShape, loadParticlesTemplate, loadParticlesUpdater, loadParticlesUtil };
|