@swmansion/popcorn 0.3.2 → 0.4.0-next.0
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/LICENSE +1 -1
- package/NOTICE +12 -0
- package/README.md +78 -2
- package/dist/beam.d.ts +10 -0
- package/dist/errors.d.ts +96 -39
- package/dist/etf.d.ts +38 -0
- package/dist/events.d.ts +82 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.mjs +1287 -2
- package/dist/plugins/beam_tools/lib/popcorn/beam_tools/beam_patcher.ex +184 -0
- package/dist/plugins/beam_tools/lib/popcorn/beam_tools/cli.ex +74 -0
- package/dist/plugins/beam_tools/lib/popcorn/beam_tools/packager.ex +540 -0
- package/dist/plugins/beam_tools/mix.exs +16 -0
- package/dist/plugins/beam_tools/patches/kernel/prim_tty.erl +13 -0
- package/dist/plugins/beam_tools/patches/stdlib/beam_lib.erl +27 -0
- package/dist/plugins/esbuild.d.ts +10 -2
- package/dist/plugins/esbuild.mjs +39 -34
- package/dist/plugins/rollup.d.ts +10 -2
- package/dist/plugins/rollup.mjs +46 -25
- package/dist/plugins/shared.d.ts +54 -4
- package/dist/plugins/shared.mjs +207 -0
- package/dist/plugins/vite.d.ts +17 -2
- package/dist/plugins/vite.mjs +201 -75
- package/dist/popcorn.d.ts +237 -110
- package/dist/runtimes/core/beam.emu.mjs +141 -0
- package/dist/runtimes/core/beam.mjs +141 -0
- package/dist/runtimes/core/beam.wasm +0 -0
- package/dist/runtimes/core/manifest.json +1 -0
- package/dist/runtimes/crypto/beam.emu.mjs +520 -0
- package/dist/runtimes/crypto/beam.mjs +520 -0
- package/dist/runtimes/crypto/beam.wasm +0 -0
- package/dist/runtimes/crypto/manifest.json +1 -0
- package/dist/tar.d.ts +4 -0
- package/dist/types.d.ts +108 -63
- package/dist/utils.d.ts +7 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.mjs +765 -0
- package/package.json +20 -28
- package/dist/AtomVM.mjs +0 -7992
- package/dist/AtomVM.wasm +0 -0
- package/dist/bridge.d.ts +0 -22
- package/dist/bridge.mjs +0 -66
- package/dist/errors.mjs +0 -55
- package/dist/iframe.d.ts +0 -1
- package/dist/iframe.mjs +0 -215
- package/dist/popcorn.mjs +0 -381
- package/dist/types.mjs +0 -25
package/dist/plugins/esbuild.mjs
CHANGED
|
@@ -1,54 +1,59 @@
|
|
|
1
|
-
import { mkdir,
|
|
2
|
-
import { dirname, resolve
|
|
3
|
-
import {
|
|
1
|
+
import { mkdir, cp, rm } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { p as popcorn$1, c as copyRuntime } from './shared.mjs';
|
|
4
|
+
import 'node:child_process';
|
|
5
|
+
import 'node:os';
|
|
6
|
+
import 'node:util';
|
|
7
|
+
import 'node:url';
|
|
8
|
+
import 'node:zlib';
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Copies the worker, VM runtime, and `otp/` assets into the output directory after a successful esbuild build.
|
|
12
|
+
*
|
|
13
|
+
* Requires `format: "esm"` and either `outdir` or `outfile`.
|
|
14
|
+
* If the application bundle is elsewhere, set `PopcornOpts.workerUrl` to the copied `worker.mjs`.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link Options} for application packaging and server requirements.
|
|
17
|
+
*/
|
|
8
18
|
function popcorn(options) {
|
|
9
|
-
const bundles = options.bundlePaths.map((p) => ({
|
|
10
|
-
name: basename(p),
|
|
11
|
-
dir: dirname(p),
|
|
12
|
-
}));
|
|
13
19
|
let outputDir;
|
|
14
20
|
return {
|
|
15
|
-
name: "popcorn",
|
|
21
|
+
name: "popcorn-otp",
|
|
16
22
|
setup(build) {
|
|
17
23
|
build.onStart(() => {
|
|
18
24
|
const opts = build.initialOptions;
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
if (outdir === undefined) {
|
|
26
|
-
throw new Error("[popcorn] outdir is not specified, cannot copy files");
|
|
27
|
-
}
|
|
28
|
-
outputDir = outdir;
|
|
25
|
+
const outdir = opts.outdir ??
|
|
26
|
+
(opts.outfile === undefined ? undefined : dirname(opts.outfile));
|
|
27
|
+
assert(opts.format === "esm", "Popcorn OTP works only with esm builds.");
|
|
28
|
+
assert(outdir !== undefined, "outdir is not specified, cannot copy files");
|
|
29
|
+
outputDir = resolve(outdir);
|
|
29
30
|
});
|
|
30
|
-
build.onEnd(async () => {
|
|
31
|
-
|
|
31
|
+
build.onEnd(async (result) => {
|
|
32
|
+
if (result.errors.length > 0)
|
|
33
|
+
return;
|
|
34
|
+
assert(outputDir !== undefined, "outdir was not resolved");
|
|
35
|
+
const outDir = outputDir;
|
|
36
|
+
const prepared = await popcorn$1(options);
|
|
32
37
|
try {
|
|
38
|
+
await mkdir(outDir, { recursive: true });
|
|
33
39
|
await Promise.all([
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
copy("iframe.mjs", { inDir: popcornDistDir, outDir: outputDir }),
|
|
39
|
-
copy("AtomVM.mjs", { inDir: popcornDistDir, outDir: outputDir }),
|
|
40
|
-
copy("AtomVM.wasm", { inDir: popcornDistDir, outDir: outputDir }),
|
|
40
|
+
copyRuntime(outDir, prepared.runtimeVariant),
|
|
41
|
+
cp(resolve(prepared.dir, "otp"), resolve(outDir, "otp"), {
|
|
42
|
+
recursive: true,
|
|
43
|
+
}),
|
|
41
44
|
]);
|
|
42
45
|
}
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
finally {
|
|
47
|
+
await rm(prepared.dir, { recursive: true, force: true });
|
|
45
48
|
}
|
|
46
49
|
});
|
|
47
50
|
},
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
function assert(ok, message) {
|
|
54
|
+
if (!ok) {
|
|
55
|
+
throw new Error(`[popcorn-otp] ${message}`);
|
|
56
|
+
}
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
export { popcorn };
|
package/dist/plugins/rollup.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import type { Plugin } from "rollup";
|
|
2
|
-
import { type
|
|
3
|
-
|
|
2
|
+
import { type Options } from "./shared";
|
|
3
|
+
/**
|
|
4
|
+
* Copies the worker, VM runtime, and `otp/` assets into the output directory after Rollup writes the bundle.
|
|
5
|
+
*
|
|
6
|
+
* Requires `output.format: "es"` and either `output.dir` or `output.file`.
|
|
7
|
+
* If the application bundle is elsewhere, set `PopcornOpts.workerUrl` to the copied `worker.mjs`.
|
|
8
|
+
*
|
|
9
|
+
* @see {@link Options} for application packaging and server requirements.
|
|
10
|
+
*/
|
|
11
|
+
export declare function popcorn(options: Options): Plugin;
|
package/dist/plugins/rollup.mjs
CHANGED
|
@@ -1,35 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { mkdir, cp, rm } from 'node:fs/promises';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { p as popcorn$1, c as copyRuntime } from './shared.mjs';
|
|
4
|
+
import 'node:child_process';
|
|
5
|
+
import 'node:os';
|
|
6
|
+
import 'node:util';
|
|
7
|
+
import 'node:url';
|
|
8
|
+
import 'node:zlib';
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Copies the worker, VM runtime, and `otp/` assets into the output directory after Rollup writes the bundle.
|
|
12
|
+
*
|
|
13
|
+
* Requires `output.format: "es"` and either `output.dir` or `output.file`.
|
|
14
|
+
* If the application bundle is elsewhere, set `PopcornOpts.workerUrl` to the copied `worker.mjs`.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link Options} for application packaging and server requirements.
|
|
17
|
+
*/
|
|
8
18
|
function popcorn(options) {
|
|
9
|
-
|
|
10
|
-
path: p,
|
|
11
|
-
name: basename(p),
|
|
12
|
-
}));
|
|
19
|
+
let outputDir;
|
|
13
20
|
return {
|
|
14
|
-
name: "popcorn",
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
fileName: resolve(popcornDistDir, bundle.name),
|
|
21
|
-
source: await readFile(bundle.path),
|
|
22
|
-
});
|
|
21
|
+
name: "popcorn-otp",
|
|
22
|
+
renderStart(outputOptions) {
|
|
23
|
+
assert(outputOptions.format === "es", "Popcorn OTP works only with esm builds.");
|
|
24
|
+
let dir = outputOptions.dir;
|
|
25
|
+
if (dir === undefined && outputOptions.file !== undefined) {
|
|
26
|
+
dir = dirname(outputOptions.file);
|
|
23
27
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
assert(dir !== undefined, "output dir is not specified, cannot copy files");
|
|
29
|
+
outputDir = resolve(dir);
|
|
30
|
+
},
|
|
31
|
+
async writeBundle() {
|
|
32
|
+
assert(outputDir !== undefined, "output dir was not resolved");
|
|
33
|
+
const outDir = outputDir;
|
|
34
|
+
const prepared = await popcorn$1(options);
|
|
35
|
+
try {
|
|
36
|
+
await mkdir(outDir, { recursive: true });
|
|
37
|
+
await Promise.all([
|
|
38
|
+
copyRuntime(outDir, prepared.runtimeVariant),
|
|
39
|
+
cp(resolve(prepared.dir, "otp"), resolve(outDir, "otp"), {
|
|
40
|
+
recursive: true,
|
|
41
|
+
}),
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await rm(prepared.dir, { recursive: true, force: true });
|
|
30
46
|
}
|
|
31
47
|
},
|
|
32
48
|
};
|
|
33
49
|
}
|
|
50
|
+
function assert(ok, message) {
|
|
51
|
+
if (!ok) {
|
|
52
|
+
throw new Error(`[popcorn-otp] ${message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
34
55
|
|
|
35
56
|
export { popcorn };
|
package/dist/plugins/shared.d.ts
CHANGED
|
@@ -1,7 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Shared options for the Vite, Rollup, and esbuild plugins.
|
|
3
|
+
*
|
|
4
|
+
* Compile the project before the plugin runs.
|
|
5
|
+
* The plugins use the local `mix` executable to package applications and dependencies.
|
|
6
|
+
*
|
|
7
|
+
* On the production server, set `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp`.
|
|
8
|
+
* Serve compressed variants with the matching `Content-Encoding` header.
|
|
9
|
+
*/
|
|
10
|
+
type RuntimeVariant = "core" | "crypto";
|
|
11
|
+
export type Options = {
|
|
3
12
|
/**
|
|
4
|
-
*
|
|
13
|
+
* Runtime variant override.
|
|
14
|
+
*
|
|
15
|
+
* By default, the plugin selects `crypto` when an application requires it and `core` otherwise.
|
|
5
16
|
*/
|
|
6
|
-
|
|
17
|
+
runtimeVariant?: RuntimeVariant;
|
|
18
|
+
/**
|
|
19
|
+
* Mix project directory.
|
|
20
|
+
*
|
|
21
|
+
* Reads compiled apps from `_build/$MIX_ENV/lib`, with `MIX_ENV` defaulting to `dev`.
|
|
22
|
+
*/
|
|
23
|
+
rootDir: string;
|
|
24
|
+
/**
|
|
25
|
+
* OTP application to start after VM boot.
|
|
26
|
+
*
|
|
27
|
+
* Use `null` to boot without an entrypoint application.
|
|
28
|
+
*/
|
|
29
|
+
app: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Additional applications to package with their dependencies.
|
|
32
|
+
*
|
|
33
|
+
* Does not start them automatically. Defaults to `[]`.
|
|
34
|
+
*/
|
|
35
|
+
extraApps?: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Adds Brotli tarball variants beside the gzip and uncompressed files.
|
|
38
|
+
*
|
|
39
|
+
* Defaults to `false`.
|
|
40
|
+
*/
|
|
41
|
+
brotli?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Removes nonessential BEAM chunks.
|
|
44
|
+
*
|
|
45
|
+
* Experimental. Defaults to `true`.
|
|
46
|
+
*/
|
|
47
|
+
strip?: boolean;
|
|
48
|
+
};
|
|
49
|
+
export type Prepared = {
|
|
50
|
+
dir: string;
|
|
51
|
+
runtimeVariant: RuntimeVariant;
|
|
52
|
+
notes: unknown[];
|
|
7
53
|
};
|
|
54
|
+
export declare function popcorn(opts: Options): Promise<Prepared>;
|
|
55
|
+
export declare function runtimeDirectory(variant: RuntimeVariant): string;
|
|
56
|
+
export declare function copyRuntime(targetDir: string, variant: RuntimeVariant): Promise<void>;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { mkdtemp, rm, mkdir, writeFile, copyFile, readFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve, dirname, normalize, basename } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { brotliCompress, gzip, constants } from 'node:zlib';
|
|
8
|
+
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
const brotliCompressAsync = promisify(brotliCompress);
|
|
11
|
+
const gzipAsync = promisify(gzip);
|
|
12
|
+
async function popcorn(opts) {
|
|
13
|
+
const useBrotli = opts.brotli ?? false;
|
|
14
|
+
const strip = opts.strip ?? true;
|
|
15
|
+
const assetVariants = [
|
|
16
|
+
"uncompressed",
|
|
17
|
+
"gzip",
|
|
18
|
+
useBrotli && "brotli",
|
|
19
|
+
];
|
|
20
|
+
const preparedDir = await mkdtemp(p `${tmpdir()}/popcorn-otp-`);
|
|
21
|
+
try {
|
|
22
|
+
const report = await withTmp(async (packedDir) => {
|
|
23
|
+
const report = await packTarballs({
|
|
24
|
+
rootDir: resolve(opts.rootDir),
|
|
25
|
+
outDir: packedDir,
|
|
26
|
+
runtimeVariant: opts.runtimeVariant,
|
|
27
|
+
app: opts.app,
|
|
28
|
+
extraApps: opts.extraApps ?? [],
|
|
29
|
+
strip,
|
|
30
|
+
});
|
|
31
|
+
if (!report.ok) {
|
|
32
|
+
throw new Error(`[popcorn-otp] ${formatPackError(report.error)}`);
|
|
33
|
+
}
|
|
34
|
+
await Promise.all([
|
|
35
|
+
copy(report.manifestPath, p `${preparedDir}/otp/manifest.json`),
|
|
36
|
+
copy(report.bootPath, p `${preparedDir}/otp/bin/vm.boot`),
|
|
37
|
+
copy(report.tarPaths, p `${preparedDir}/otp/lib`, {
|
|
38
|
+
variants: assetVariants,
|
|
39
|
+
}),
|
|
40
|
+
]);
|
|
41
|
+
return report;
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
dir: preparedDir,
|
|
45
|
+
runtimeVariant: report.runtimeVariant,
|
|
46
|
+
notes: report.notes ?? [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
await rm(preparedDir, { recursive: true, force: true });
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function runtimeDirectory(variant) {
|
|
55
|
+
if (variant !== "core" && variant !== "crypto") {
|
|
56
|
+
throw new Error(`[popcorn-otp] Unknown runtime variant: ${variant}`);
|
|
57
|
+
}
|
|
58
|
+
return p `${dirname(fileURLToPath(import.meta.url))}/../runtimes/${variant}`;
|
|
59
|
+
}
|
|
60
|
+
async function copyRuntime(targetDir, variant) {
|
|
61
|
+
const distDir = p `${dirname(fileURLToPath(import.meta.url))}/..`;
|
|
62
|
+
const runtimeDir = runtimeDirectory(variant);
|
|
63
|
+
await Promise.all(["worker.mjs", "beam.mjs", "beam.emu.mjs", "beam.wasm"].map((file) => copy(p `${file === "worker.mjs" ? distDir : runtimeDir}/${file}`, p `${targetDir}/${file}`)));
|
|
64
|
+
}
|
|
65
|
+
async function packTarballs(opts) {
|
|
66
|
+
const { rootDir, outDir, runtimeVariant, app, extraApps, strip } = opts;
|
|
67
|
+
const toolDir = p `${dirname(fileURLToPath(import.meta.url))}/beam_tools`;
|
|
68
|
+
const packerArgs = [
|
|
69
|
+
"run",
|
|
70
|
+
"--no-start",
|
|
71
|
+
"-e",
|
|
72
|
+
"Popcorn.BeamTools.CLI.main(System.argv())",
|
|
73
|
+
"--",
|
|
74
|
+
"--root-dir",
|
|
75
|
+
rootDir,
|
|
76
|
+
"--out-dir",
|
|
77
|
+
outDir,
|
|
78
|
+
"--runtimes-dir",
|
|
79
|
+
p `${toolDir}/../../runtimes`,
|
|
80
|
+
];
|
|
81
|
+
if (runtimeVariant !== undefined) {
|
|
82
|
+
packerArgs.push("--runtime-variant", runtimeVariant);
|
|
83
|
+
}
|
|
84
|
+
if (app !== null) {
|
|
85
|
+
packerArgs.push("--entrypoint-app", app);
|
|
86
|
+
}
|
|
87
|
+
for (const extraApp of extraApps) {
|
|
88
|
+
packerArgs.push("--extra-app", extraApp);
|
|
89
|
+
}
|
|
90
|
+
if (strip) {
|
|
91
|
+
packerArgs.push("--strip");
|
|
92
|
+
}
|
|
93
|
+
const env = {
|
|
94
|
+
...process.env,
|
|
95
|
+
MIX_BUILD_PATH: p `${outDir}/beam_tools_build`,
|
|
96
|
+
MIX_QUIET: "1",
|
|
97
|
+
};
|
|
98
|
+
const { stdout } = await execFileAsync("mix", packerArgs, {
|
|
99
|
+
cwd: toolDir,
|
|
100
|
+
env,
|
|
101
|
+
});
|
|
102
|
+
return JSON.parse(stdout);
|
|
103
|
+
}
|
|
104
|
+
function hasCode(error, code) {
|
|
105
|
+
return (typeof error === "object" &&
|
|
106
|
+
error !== null &&
|
|
107
|
+
error.code === code);
|
|
108
|
+
}
|
|
109
|
+
function isMissingDepError(error) {
|
|
110
|
+
return hasCode(error, "missing_dep");
|
|
111
|
+
}
|
|
112
|
+
function isUnsupportedAppsError(error) {
|
|
113
|
+
return hasCode(error, "unsupported_apps");
|
|
114
|
+
}
|
|
115
|
+
function isMissingExtraAppsError(error) {
|
|
116
|
+
return hasCode(error, "missing_extra_apps");
|
|
117
|
+
}
|
|
118
|
+
function toolchainOf(error) {
|
|
119
|
+
if (typeof error !== "object" || error === null) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
return error.toolchain;
|
|
123
|
+
}
|
|
124
|
+
function errorLines(error) {
|
|
125
|
+
if (isMissingDepError(error)) {
|
|
126
|
+
return [
|
|
127
|
+
`${error.app} depends on ${error.dep}, which isn't available.`,
|
|
128
|
+
`BEAM applications come from your project build and your active`,
|
|
129
|
+
`Erlang/Elixir installation; nothing is bundled with the package.`,
|
|
130
|
+
`Apps built by your project: ${error.available_apps.join(", ")}.`,
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
if (isUnsupportedAppsError(error)) {
|
|
134
|
+
const apps = error.apps
|
|
135
|
+
.map(({ app, capability }) => `${app} (needs ${capability})`)
|
|
136
|
+
.join(", ");
|
|
137
|
+
return [
|
|
138
|
+
`These applications need native support the Wasm runtime wasn't built`,
|
|
139
|
+
`with: ${apps}.`,
|
|
140
|
+
`Drop them from your dependencies, or use a runtime built with it.`,
|
|
141
|
+
];
|
|
142
|
+
}
|
|
143
|
+
if (isMissingExtraAppsError(error)) {
|
|
144
|
+
return [
|
|
145
|
+
`Extra apps not found: ${error.apps.join(", ")}.`,
|
|
146
|
+
`They have to come from your project build or your Erlang/Elixir install.`,
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
return [`packaging failed: ${JSON.stringify(error)}`];
|
|
150
|
+
}
|
|
151
|
+
function formatPackError(error) {
|
|
152
|
+
const lines = errorLines(error);
|
|
153
|
+
const toolchain = toolchainOf(error);
|
|
154
|
+
if (toolchain !== undefined) {
|
|
155
|
+
lines.push(`Using ${toolchain.executable} (Erlang/OTP ${toolchain.otp}, Elixir ${toolchain.elixir}).`);
|
|
156
|
+
}
|
|
157
|
+
return lines.join("\n ");
|
|
158
|
+
}
|
|
159
|
+
async function copy(source, target, { variants = ["uncompressed"] } = {}) {
|
|
160
|
+
const sources = typeof source === "string" ? [source] : source;
|
|
161
|
+
const targetIsDir = typeof source !== "string";
|
|
162
|
+
await Promise.all(sources.map(async (sourcePath) => {
|
|
163
|
+
const targetPath = targetIsDir
|
|
164
|
+
? p `${target}/${basename(sourcePath)}`
|
|
165
|
+
: target;
|
|
166
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
167
|
+
let content;
|
|
168
|
+
const read = () => (content ??= readFile(sourcePath));
|
|
169
|
+
await Promise.all(variants
|
|
170
|
+
.filter((variant) => Boolean(variant))
|
|
171
|
+
.map(async (variant) => {
|
|
172
|
+
switch (variant) {
|
|
173
|
+
case "uncompressed":
|
|
174
|
+
await copyFile(sourcePath, targetPath);
|
|
175
|
+
break;
|
|
176
|
+
case "gzip": {
|
|
177
|
+
const input = await read();
|
|
178
|
+
const buffer = await gzipAsync(input, { level: 9 });
|
|
179
|
+
await writeFile(`${targetPath}.gz`, buffer);
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case "brotli": {
|
|
183
|
+
const Q = constants.BROTLI_PARAM_QUALITY;
|
|
184
|
+
const opts = { params: { [Q]: 11 } };
|
|
185
|
+
const input = await read();
|
|
186
|
+
const buffer = await brotliCompressAsync(input, opts);
|
|
187
|
+
await writeFile(`${targetPath}.br`, buffer);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}));
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
function p(strings, ...values) {
|
|
195
|
+
return normalize(String.raw(strings, ...values));
|
|
196
|
+
}
|
|
197
|
+
async function withTmp(f) {
|
|
198
|
+
const dir = await mkdtemp(p `${tmpdir()}/popcorn-otp-`);
|
|
199
|
+
try {
|
|
200
|
+
return await f(dir);
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
await rm(dir, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export { copyRuntime as c, popcorn as p, runtimeDirectory as r };
|
package/dist/plugins/vite.d.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
-
import { type PopcornPluginOptions } from "./shared";
|
|
2
1
|
import type { Plugin } from "vite";
|
|
3
|
-
|
|
2
|
+
import { type Options } from "./shared";
|
|
3
|
+
/**
|
|
4
|
+
* Serves application assets during developmens.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { defineConfig } from "vite";
|
|
9
|
+
* import { popcorn } from "@swmansion/popcorn/vite";
|
|
10
|
+
*
|
|
11
|
+
* export default defineConfig({
|
|
12
|
+
* plugins: [popcorn({ rootDir: "../my_app", app: "my_app" })],
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @see {@link Options} for production server requirements.
|
|
17
|
+
*/
|
|
18
|
+
export declare function popcorn(options: Options): Plugin;
|