@sdeverywhere/plugin-worker 0.1.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 +21 -0
- package/README.md +13 -0
- package/dist/index.cjs +156 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
- package/template-worker/worker.js +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Climate Interactive / New Venture Fund
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @sdeverywhere/plugin-worker
|
|
2
|
+
|
|
3
|
+
This package provides a plugin that generates a `worker.js` file that can run
|
|
4
|
+
an SDEverywhere-generated system dynamics model asynchronously in a Web Worker
|
|
5
|
+
or Node.js worker thread.
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
TODO
|
|
10
|
+
|
|
11
|
+
## License
|
|
12
|
+
|
|
13
|
+
SDEverywhere is distributed under the MIT license. See `LICENSE` for more details.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/index.ts
|
|
20
|
+
var src_exports = {};
|
|
21
|
+
__export(src_exports, {
|
|
22
|
+
workerPlugin: () => workerPlugin
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(src_exports);
|
|
25
|
+
|
|
26
|
+
// src/plugin.ts
|
|
27
|
+
var import_path2 = require("path");
|
|
28
|
+
var import_vite = require("vite");
|
|
29
|
+
|
|
30
|
+
// src/vite-config.ts
|
|
31
|
+
var import_path = require("path");
|
|
32
|
+
var import_url = require("url");
|
|
33
|
+
var import_plugin_node_resolve = require("@rollup/plugin-node-resolve");
|
|
34
|
+
|
|
35
|
+
// src/var-names.ts
|
|
36
|
+
function sdeNameForVensimName(name) {
|
|
37
|
+
return "_" + name.trim().replace(/"/g, "_").replace(/\s+!$/g, "!").replace(/\s/g, "_").replace(/,/g, "_").replace(/-/g, "_").replace(/\./g, "_").replace(/\$/g, "_").replace(/'/g, "_").replace(/&/g, "_").replace(/%/g, "_").replace(/\//g, "_").replace(/\|/g, "_").toLowerCase();
|
|
38
|
+
}
|
|
39
|
+
function sdeNameForVensimVarName(varName) {
|
|
40
|
+
const m = varName.match(/([^[]+)(?:\[([^\]]+)\])?/);
|
|
41
|
+
if (!m) {
|
|
42
|
+
throw new Error(`Invalid Vensim name: ${varName}`);
|
|
43
|
+
}
|
|
44
|
+
let id = sdeNameForVensimName(m[1]);
|
|
45
|
+
if (m[2]) {
|
|
46
|
+
const subscripts = m[2].split(",").map((x) => sdeNameForVensimName(x));
|
|
47
|
+
id += `[${subscripts.join("][")}]`;
|
|
48
|
+
}
|
|
49
|
+
return id;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/vite-config.ts
|
|
53
|
+
var import_meta = {};
|
|
54
|
+
var __filename = (0, import_url.fileURLToPath)(import_meta.url);
|
|
55
|
+
var __dirname = (0, import_path.dirname)(__filename);
|
|
56
|
+
function injectModelSpec(modelSpec) {
|
|
57
|
+
const outputVarIds = modelSpec.outputs.map((o) => sdeNameForVensimVarName(o.varName));
|
|
58
|
+
const moduleSrc = `
|
|
59
|
+
export const startTime = ${modelSpec.startTime};
|
|
60
|
+
export const endTime = ${modelSpec.endTime};
|
|
61
|
+
export const numInputs = ${modelSpec.inputs.length};
|
|
62
|
+
export const outputVarIds = ${JSON.stringify(outputVarIds)};
|
|
63
|
+
`;
|
|
64
|
+
const virtualModuleId = "virtual:model-spec";
|
|
65
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
66
|
+
return {
|
|
67
|
+
name: "vite-plugin-virtual-custom",
|
|
68
|
+
resolveId(id) {
|
|
69
|
+
if (id === virtualModuleId) {
|
|
70
|
+
return resolvedVirtualModuleId;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
load(id) {
|
|
74
|
+
if (id === resolvedVirtualModuleId) {
|
|
75
|
+
return moduleSrc;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function createViteConfig(stagedModelDir, modelJsFile, modelSpec, outputFile) {
|
|
81
|
+
const root = stagedModelDir;
|
|
82
|
+
const entry = (0, import_path.resolve)(__dirname, "..", "template-worker", "worker.js");
|
|
83
|
+
return {
|
|
84
|
+
configFile: false,
|
|
85
|
+
root,
|
|
86
|
+
clearScreen: false,
|
|
87
|
+
logLevel: "silent",
|
|
88
|
+
resolve: {
|
|
89
|
+
alias: [
|
|
90
|
+
{
|
|
91
|
+
find: "@_wasm_",
|
|
92
|
+
replacement: (0, import_path.resolve)(stagedModelDir, modelJsFile)
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
find: "threads",
|
|
96
|
+
replacement: "threads",
|
|
97
|
+
customResolver: (0, import_plugin_node_resolve.nodeResolve)({ browser: false })
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
plugins: [
|
|
102
|
+
injectModelSpec(modelSpec)
|
|
103
|
+
],
|
|
104
|
+
build: {
|
|
105
|
+
outDir: ".",
|
|
106
|
+
emptyOutDir: false,
|
|
107
|
+
lib: {
|
|
108
|
+
entry,
|
|
109
|
+
name: "worker",
|
|
110
|
+
formats: ["iife"],
|
|
111
|
+
fileName: () => outputFile
|
|
112
|
+
},
|
|
113
|
+
rollupOptions: {
|
|
114
|
+
onwarn: (warning, warn) => {
|
|
115
|
+
if (warning.code !== "EVAL") {
|
|
116
|
+
warn(warning);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/plugin.ts
|
|
125
|
+
function workerPlugin(options) {
|
|
126
|
+
return new WorkerPlugin(options);
|
|
127
|
+
}
|
|
128
|
+
var WorkerPlugin = class {
|
|
129
|
+
constructor(options) {
|
|
130
|
+
this.options = options;
|
|
131
|
+
}
|
|
132
|
+
async postGenerate(context, modelSpec) {
|
|
133
|
+
var _a;
|
|
134
|
+
const log = context.log;
|
|
135
|
+
log("info", "Building worker");
|
|
136
|
+
const prepDir = context.config.prepDir;
|
|
137
|
+
const srcDir = "model";
|
|
138
|
+
const stagedModelDir = (0, import_path2.join)(prepDir, "staged", srcDir);
|
|
139
|
+
const inModelJsFile = "wasm-model.js";
|
|
140
|
+
const outWorkerJsFile = "worker.js";
|
|
141
|
+
const outputPaths = ((_a = this.options) == null ? void 0 : _a.outputPaths) || [(0, import_path2.join)(prepDir, outWorkerJsFile)];
|
|
142
|
+
for (const outputPath of outputPaths) {
|
|
143
|
+
const dstDir = (0, import_path2.dirname)(outputPath);
|
|
144
|
+
const dstFile = (0, import_path2.basename)(outputPath);
|
|
145
|
+
context.prepareStagedFile(srcDir, outWorkerJsFile, dstDir, dstFile);
|
|
146
|
+
}
|
|
147
|
+
const viteConfig = createViteConfig(stagedModelDir, inModelJsFile, modelSpec, outWorkerJsFile);
|
|
148
|
+
await (0, import_vite.build)(viteConfig);
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
153
|
+
0 && (module.exports = {
|
|
154
|
+
workerPlugin
|
|
155
|
+
});
|
|
156
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/vite-config.ts","../src/var-names.ts"],"sourcesContent":["// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nexport type { WorkerPluginOptions } from './options'\nexport { workerPlugin } from './plugin'\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { basename, dirname, join as joinPath } from 'path'\n\nimport { build } from 'vite'\n\nimport type { BuildContext, ModelSpec, Plugin } from '@sdeverywhere/build'\n\nimport type { WorkerPluginOptions } from './options'\nimport { createViteConfig } from './vite-config'\n\nexport function workerPlugin(options?: WorkerPluginOptions): Plugin {\n return new WorkerPlugin(options)\n}\n\nclass WorkerPlugin implements Plugin {\n constructor(private readonly options?: WorkerPluginOptions) {}\n\n async postGenerate(context: BuildContext, modelSpec: ModelSpec): Promise<boolean> {\n const log = context.log\n log('info', 'Building worker')\n\n // Locate the input (model JS/Wasm) file in the staged directory. Note\n // that this relies on the `plugin-wasm` package writing a file called\n // `wasm-model.js` to the `staged/model` directory.\n const prepDir = context.config.prepDir\n const srcDir = 'model'\n const stagedModelDir = joinPath(prepDir, 'staged', srcDir)\n const inModelJsFile = 'wasm-model.js'\n const outWorkerJsFile = 'worker.js'\n\n // If `outputPaths` is undefined, write the `worker.js` to the prep dir\n const outputPaths = this.options?.outputPaths || [joinPath(prepDir, outWorkerJsFile)]\n\n // Add staged file entries; this will cause the generated worker to be copied\n // to the configured output paths during the \"copy staged files\" step\n // TODO: This assumes that other plugins that use the generated worker files\n // will run after the \"copy staged files\" step. There might be use cases\n // where a plugin needs access to these in `postGenerate`, in which case the\n // files will not have been copied already. Need to reconsider the ordering\n // of plugins and the \"copy staged files\" step(s).\n for (const outputPath of outputPaths) {\n const dstDir = dirname(outputPath)\n const dstFile = basename(outputPath)\n context.prepareStagedFile(srcDir, outWorkerJsFile, dstDir, dstFile)\n }\n\n // Build the worker and write generated file to the `staged/model` directory\n const viteConfig = createViteConfig(stagedModelDir, inModelJsFile, modelSpec, outWorkerJsFile)\n await build(viteConfig)\n\n // log('info', 'Done!')\n\n return true\n }\n}\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { dirname, resolve as resolvePath } from 'path'\nimport { fileURLToPath } from 'url'\n\nimport type { InlineConfig, Plugin as VitePlugin, ResolverObject } from 'vite'\nimport { nodeResolve } from '@rollup/plugin-node-resolve'\n\nimport type { ModelSpec } from '@sdeverywhere/build'\n\nimport { sdeNameForVensimVarName } from './var-names'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\n/**\n * This is a virtual module plugin used to inject model-specific configuration\n * values into the generated worker bundle.\n *\n * This follows the \"Virtual Modules Convention\" described here:\n * https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention\n *\n * TODO: This could be simplified by using `vite-plugin-virtual` but that\n * doesn't seem to be working correctly in an ESM setting\n */\nfunction injectModelSpec(modelSpec: ModelSpec): VitePlugin {\n const outputVarIds = modelSpec.outputs.map(o => sdeNameForVensimVarName(o.varName))\n\n const moduleSrc = `\nexport const startTime = ${modelSpec.startTime};\nexport const endTime = ${modelSpec.endTime};\nexport const numInputs = ${modelSpec.inputs.length};\nexport const outputVarIds = ${JSON.stringify(outputVarIds)};\n`\n\n const virtualModuleId = 'virtual:model-spec'\n const resolvedVirtualModuleId = '\\0' + virtualModuleId\n\n return {\n name: 'vite-plugin-virtual-custom',\n resolveId(id: string) {\n if (id === virtualModuleId) {\n return resolvedVirtualModuleId\n }\n },\n load(id: string) {\n if (id === resolvedVirtualModuleId) {\n return moduleSrc\n }\n }\n }\n}\n\n/**\n * Create a Vite `InlineConfig` that can be used to build a complete\n * worker bundle that can run the generated Wasm model in a separate\n * Web Worker or Node worker thread.\n *\n * @param stagedModelDir The `staged` directory under the `sde-prep` directory.\n * @param modelJsFile The name of the JS file containing the embedded Wasm.\n * @param modelSpec The model spec generated earlier in the build process.\n * @param outputFile The name of the generated worker JS file.\n * @return An `InlineConfig` instance that can be passed to Vite's `build` function.\n */\nexport function createViteConfig(\n stagedModelDir: string,\n modelJsFile: string,\n modelSpec: ModelSpec,\n outputFile: string\n): InlineConfig {\n // Use `staged/model` as the root directory for the worker build\n const root = stagedModelDir\n\n // Use `template-worker/worker.js` from this package as the entry file\n const entry = resolvePath(__dirname, '..', 'template-worker', 'worker.js')\n\n return {\n // Don't use an external config file\n configFile: false,\n\n // Use the root directory configured above\n root,\n\n // Don't clear the screen in dev mode so that we can see builder output\n clearScreen: false,\n\n // Disable vite output by default\n // TODO: Re-enable logging if `--verbose` option is used?\n logLevel: 'silent',\n\n // Configure path aliases\n resolve: {\n alias: [\n // In the template, we use `@_wasm_` as an alias for the JS-wrapped Wasm\n // file generated by Emscripten\n {\n find: '@_wasm_',\n replacement: resolvePath(stagedModelDir, modelJsFile)\n },\n\n // XXX: Prevent Vite from using the `browser` section of `threads/package.json`\n // since we want to force the use of the general module (under dist) that chooses\n // the correct implementation (Web Worker vs worker_threads) at runtime. Currently\n // Vite's library mode is browser focused, so using a `customResolver` seems to be\n // the easiest way to prevent Vite from picking up the `browser` exports.\n {\n find: 'threads',\n replacement: 'threads',\n customResolver: nodeResolve({ browser: false }) as ResolverObject\n }\n ]\n },\n\n plugins: [\n // Use a virtual module plugin to inject the model spec values\n injectModelSpec(modelSpec)\n ],\n\n build: {\n // Write output file to the `staged/model` directory; note that this path is\n // relative to the bundle `root` directory\n outDir: '.',\n emptyOutDir: false,\n\n lib: {\n entry,\n name: 'worker',\n formats: ['iife'],\n fileName: () => outputFile\n },\n\n rollupOptions: {\n onwarn: (warning, warn) => {\n // XXX: Suppress \"Use of eval is strongly discouraged\" warnings that are\n // triggered by use of the following pattern in threads.js:\n // eval(\"require\")(\"worker_threads\")\n // It would be nice to avoid use of `eval` there, but it's not critical for\n // our use case so we will suppress the warnings for now\n if (warning.code !== 'EVAL') {\n warn(warning)\n }\n }\n }\n }\n }\n}\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\n/**\n * Helper function that converts a Vensim variable or subscript name\n * into a valid C identifier as used by SDE.\n * TODO: Import helper function from `compile` package instead\n */\nfunction sdeNameForVensimName(name: string): string {\n return (\n '_' +\n name\n .trim()\n .replace(/\"/g, '_')\n .replace(/\\s+!$/g, '!')\n .replace(/\\s/g, '_')\n .replace(/,/g, '_')\n .replace(/-/g, '_')\n .replace(/\\./g, '_')\n .replace(/\\$/g, '_')\n .replace(/'/g, '_')\n .replace(/&/g, '_')\n .replace(/%/g, '_')\n .replace(/\\//g, '_')\n .replace(/\\|/g, '_')\n .toLowerCase()\n )\n}\n\n/**\n * Helper function that converts a Vensim variable name (possibly containing\n * subscripts) into a valid C identifier as used by SDE.\n * TODO: Import helper function from `compile` package instead\n */\nexport function sdeNameForVensimVarName(varName: string): string {\n const m = varName.match(/([^[]+)(?:\\[([^\\]]+)\\])?/)\n if (!m) {\n throw new Error(`Invalid Vensim name: ${varName}`)\n }\n let id = sdeNameForVensimName(m[1])\n if (m[2]) {\n const subscripts = m[2].split(',').map(x => sdeNameForVensimName(x))\n id += `[${subscripts.join('][')}]`\n }\n\n return id\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Plugin } from '@sdeverywhere/build';
|
|
2
|
+
|
|
3
|
+
interface WorkerPluginOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The destination paths for the generated worker JS files. If undefined,
|
|
6
|
+
* a `worker.js` file will be written to the configured `prepDir`.
|
|
7
|
+
*/
|
|
8
|
+
outputPaths?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare function workerPlugin(options?: WorkerPluginOptions): Plugin;
|
|
12
|
+
|
|
13
|
+
export { WorkerPluginOptions, workerPlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
import { basename, dirname as dirname2, join as joinPath } from "path";
|
|
3
|
+
import { build } from "vite";
|
|
4
|
+
|
|
5
|
+
// src/vite-config.ts
|
|
6
|
+
import { dirname, resolve as resolvePath } from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
|
9
|
+
|
|
10
|
+
// src/var-names.ts
|
|
11
|
+
function sdeNameForVensimName(name) {
|
|
12
|
+
return "_" + name.trim().replace(/"/g, "_").replace(/\s+!$/g, "!").replace(/\s/g, "_").replace(/,/g, "_").replace(/-/g, "_").replace(/\./g, "_").replace(/\$/g, "_").replace(/'/g, "_").replace(/&/g, "_").replace(/%/g, "_").replace(/\//g, "_").replace(/\|/g, "_").toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
function sdeNameForVensimVarName(varName) {
|
|
15
|
+
const m = varName.match(/([^[]+)(?:\[([^\]]+)\])?/);
|
|
16
|
+
if (!m) {
|
|
17
|
+
throw new Error(`Invalid Vensim name: ${varName}`);
|
|
18
|
+
}
|
|
19
|
+
let id = sdeNameForVensimName(m[1]);
|
|
20
|
+
if (m[2]) {
|
|
21
|
+
const subscripts = m[2].split(",").map((x) => sdeNameForVensimName(x));
|
|
22
|
+
id += `[${subscripts.join("][")}]`;
|
|
23
|
+
}
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/vite-config.ts
|
|
28
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
29
|
+
var __dirname = dirname(__filename);
|
|
30
|
+
function injectModelSpec(modelSpec) {
|
|
31
|
+
const outputVarIds = modelSpec.outputs.map((o) => sdeNameForVensimVarName(o.varName));
|
|
32
|
+
const moduleSrc = `
|
|
33
|
+
export const startTime = ${modelSpec.startTime};
|
|
34
|
+
export const endTime = ${modelSpec.endTime};
|
|
35
|
+
export const numInputs = ${modelSpec.inputs.length};
|
|
36
|
+
export const outputVarIds = ${JSON.stringify(outputVarIds)};
|
|
37
|
+
`;
|
|
38
|
+
const virtualModuleId = "virtual:model-spec";
|
|
39
|
+
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
40
|
+
return {
|
|
41
|
+
name: "vite-plugin-virtual-custom",
|
|
42
|
+
resolveId(id) {
|
|
43
|
+
if (id === virtualModuleId) {
|
|
44
|
+
return resolvedVirtualModuleId;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
load(id) {
|
|
48
|
+
if (id === resolvedVirtualModuleId) {
|
|
49
|
+
return moduleSrc;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function createViteConfig(stagedModelDir, modelJsFile, modelSpec, outputFile) {
|
|
55
|
+
const root = stagedModelDir;
|
|
56
|
+
const entry = resolvePath(__dirname, "..", "template-worker", "worker.js");
|
|
57
|
+
return {
|
|
58
|
+
configFile: false,
|
|
59
|
+
root,
|
|
60
|
+
clearScreen: false,
|
|
61
|
+
logLevel: "silent",
|
|
62
|
+
resolve: {
|
|
63
|
+
alias: [
|
|
64
|
+
{
|
|
65
|
+
find: "@_wasm_",
|
|
66
|
+
replacement: resolvePath(stagedModelDir, modelJsFile)
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
find: "threads",
|
|
70
|
+
replacement: "threads",
|
|
71
|
+
customResolver: nodeResolve({ browser: false })
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
plugins: [
|
|
76
|
+
injectModelSpec(modelSpec)
|
|
77
|
+
],
|
|
78
|
+
build: {
|
|
79
|
+
outDir: ".",
|
|
80
|
+
emptyOutDir: false,
|
|
81
|
+
lib: {
|
|
82
|
+
entry,
|
|
83
|
+
name: "worker",
|
|
84
|
+
formats: ["iife"],
|
|
85
|
+
fileName: () => outputFile
|
|
86
|
+
},
|
|
87
|
+
rollupOptions: {
|
|
88
|
+
onwarn: (warning, warn) => {
|
|
89
|
+
if (warning.code !== "EVAL") {
|
|
90
|
+
warn(warning);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/plugin.ts
|
|
99
|
+
function workerPlugin(options) {
|
|
100
|
+
return new WorkerPlugin(options);
|
|
101
|
+
}
|
|
102
|
+
var WorkerPlugin = class {
|
|
103
|
+
constructor(options) {
|
|
104
|
+
this.options = options;
|
|
105
|
+
}
|
|
106
|
+
async postGenerate(context, modelSpec) {
|
|
107
|
+
var _a;
|
|
108
|
+
const log = context.log;
|
|
109
|
+
log("info", "Building worker");
|
|
110
|
+
const prepDir = context.config.prepDir;
|
|
111
|
+
const srcDir = "model";
|
|
112
|
+
const stagedModelDir = joinPath(prepDir, "staged", srcDir);
|
|
113
|
+
const inModelJsFile = "wasm-model.js";
|
|
114
|
+
const outWorkerJsFile = "worker.js";
|
|
115
|
+
const outputPaths = ((_a = this.options) == null ? void 0 : _a.outputPaths) || [joinPath(prepDir, outWorkerJsFile)];
|
|
116
|
+
for (const outputPath of outputPaths) {
|
|
117
|
+
const dstDir = dirname2(outputPath);
|
|
118
|
+
const dstFile = basename(outputPath);
|
|
119
|
+
context.prepareStagedFile(srcDir, outWorkerJsFile, dstDir, dstFile);
|
|
120
|
+
}
|
|
121
|
+
const viteConfig = createViteConfig(stagedModelDir, inModelJsFile, modelSpec, outWorkerJsFile);
|
|
122
|
+
await build(viteConfig);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
export {
|
|
127
|
+
workerPlugin
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/vite-config.ts","../src/var-names.ts"],"sourcesContent":["// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { basename, dirname, join as joinPath } from 'path'\n\nimport { build } from 'vite'\n\nimport type { BuildContext, ModelSpec, Plugin } from '@sdeverywhere/build'\n\nimport type { WorkerPluginOptions } from './options'\nimport { createViteConfig } from './vite-config'\n\nexport function workerPlugin(options?: WorkerPluginOptions): Plugin {\n return new WorkerPlugin(options)\n}\n\nclass WorkerPlugin implements Plugin {\n constructor(private readonly options?: WorkerPluginOptions) {}\n\n async postGenerate(context: BuildContext, modelSpec: ModelSpec): Promise<boolean> {\n const log = context.log\n log('info', 'Building worker')\n\n // Locate the input (model JS/Wasm) file in the staged directory. Note\n // that this relies on the `plugin-wasm` package writing a file called\n // `wasm-model.js` to the `staged/model` directory.\n const prepDir = context.config.prepDir\n const srcDir = 'model'\n const stagedModelDir = joinPath(prepDir, 'staged', srcDir)\n const inModelJsFile = 'wasm-model.js'\n const outWorkerJsFile = 'worker.js'\n\n // If `outputPaths` is undefined, write the `worker.js` to the prep dir\n const outputPaths = this.options?.outputPaths || [joinPath(prepDir, outWorkerJsFile)]\n\n // Add staged file entries; this will cause the generated worker to be copied\n // to the configured output paths during the \"copy staged files\" step\n // TODO: This assumes that other plugins that use the generated worker files\n // will run after the \"copy staged files\" step. There might be use cases\n // where a plugin needs access to these in `postGenerate`, in which case the\n // files will not have been copied already. Need to reconsider the ordering\n // of plugins and the \"copy staged files\" step(s).\n for (const outputPath of outputPaths) {\n const dstDir = dirname(outputPath)\n const dstFile = basename(outputPath)\n context.prepareStagedFile(srcDir, outWorkerJsFile, dstDir, dstFile)\n }\n\n // Build the worker and write generated file to the `staged/model` directory\n const viteConfig = createViteConfig(stagedModelDir, inModelJsFile, modelSpec, outWorkerJsFile)\n await build(viteConfig)\n\n // log('info', 'Done!')\n\n return true\n }\n}\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { dirname, resolve as resolvePath } from 'path'\nimport { fileURLToPath } from 'url'\n\nimport type { InlineConfig, Plugin as VitePlugin, ResolverObject } from 'vite'\nimport { nodeResolve } from '@rollup/plugin-node-resolve'\n\nimport type { ModelSpec } from '@sdeverywhere/build'\n\nimport { sdeNameForVensimVarName } from './var-names'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\n/**\n * This is a virtual module plugin used to inject model-specific configuration\n * values into the generated worker bundle.\n *\n * This follows the \"Virtual Modules Convention\" described here:\n * https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention\n *\n * TODO: This could be simplified by using `vite-plugin-virtual` but that\n * doesn't seem to be working correctly in an ESM setting\n */\nfunction injectModelSpec(modelSpec: ModelSpec): VitePlugin {\n const outputVarIds = modelSpec.outputs.map(o => sdeNameForVensimVarName(o.varName))\n\n const moduleSrc = `\nexport const startTime = ${modelSpec.startTime};\nexport const endTime = ${modelSpec.endTime};\nexport const numInputs = ${modelSpec.inputs.length};\nexport const outputVarIds = ${JSON.stringify(outputVarIds)};\n`\n\n const virtualModuleId = 'virtual:model-spec'\n const resolvedVirtualModuleId = '\\0' + virtualModuleId\n\n return {\n name: 'vite-plugin-virtual-custom',\n resolveId(id: string) {\n if (id === virtualModuleId) {\n return resolvedVirtualModuleId\n }\n },\n load(id: string) {\n if (id === resolvedVirtualModuleId) {\n return moduleSrc\n }\n }\n }\n}\n\n/**\n * Create a Vite `InlineConfig` that can be used to build a complete\n * worker bundle that can run the generated Wasm model in a separate\n * Web Worker or Node worker thread.\n *\n * @param stagedModelDir The `staged` directory under the `sde-prep` directory.\n * @param modelJsFile The name of the JS file containing the embedded Wasm.\n * @param modelSpec The model spec generated earlier in the build process.\n * @param outputFile The name of the generated worker JS file.\n * @return An `InlineConfig` instance that can be passed to Vite's `build` function.\n */\nexport function createViteConfig(\n stagedModelDir: string,\n modelJsFile: string,\n modelSpec: ModelSpec,\n outputFile: string\n): InlineConfig {\n // Use `staged/model` as the root directory for the worker build\n const root = stagedModelDir\n\n // Use `template-worker/worker.js` from this package as the entry file\n const entry = resolvePath(__dirname, '..', 'template-worker', 'worker.js')\n\n return {\n // Don't use an external config file\n configFile: false,\n\n // Use the root directory configured above\n root,\n\n // Don't clear the screen in dev mode so that we can see builder output\n clearScreen: false,\n\n // Disable vite output by default\n // TODO: Re-enable logging if `--verbose` option is used?\n logLevel: 'silent',\n\n // Configure path aliases\n resolve: {\n alias: [\n // In the template, we use `@_wasm_` as an alias for the JS-wrapped Wasm\n // file generated by Emscripten\n {\n find: '@_wasm_',\n replacement: resolvePath(stagedModelDir, modelJsFile)\n },\n\n // XXX: Prevent Vite from using the `browser` section of `threads/package.json`\n // since we want to force the use of the general module (under dist) that chooses\n // the correct implementation (Web Worker vs worker_threads) at runtime. Currently\n // Vite's library mode is browser focused, so using a `customResolver` seems to be\n // the easiest way to prevent Vite from picking up the `browser` exports.\n {\n find: 'threads',\n replacement: 'threads',\n customResolver: nodeResolve({ browser: false }) as ResolverObject\n }\n ]\n },\n\n plugins: [\n // Use a virtual module plugin to inject the model spec values\n injectModelSpec(modelSpec)\n ],\n\n build: {\n // Write output file to the `staged/model` directory; note that this path is\n // relative to the bundle `root` directory\n outDir: '.',\n emptyOutDir: false,\n\n lib: {\n entry,\n name: 'worker',\n formats: ['iife'],\n fileName: () => outputFile\n },\n\n rollupOptions: {\n onwarn: (warning, warn) => {\n // XXX: Suppress \"Use of eval is strongly discouraged\" warnings that are\n // triggered by use of the following pattern in threads.js:\n // eval(\"require\")(\"worker_threads\")\n // It would be nice to avoid use of `eval` there, but it's not critical for\n // our use case so we will suppress the warnings for now\n if (warning.code !== 'EVAL') {\n warn(warning)\n }\n }\n }\n }\n }\n}\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\n/**\n * Helper function that converts a Vensim variable or subscript name\n * into a valid C identifier as used by SDE.\n * TODO: Import helper function from `compile` package instead\n */\nfunction sdeNameForVensimName(name: string): string {\n return (\n '_' +\n name\n .trim()\n .replace(/\"/g, '_')\n .replace(/\\s+!$/g, '!')\n .replace(/\\s/g, '_')\n .replace(/,/g, '_')\n .replace(/-/g, '_')\n .replace(/\\./g, '_')\n .replace(/\\$/g, '_')\n .replace(/'/g, '_')\n .replace(/&/g, '_')\n .replace(/%/g, '_')\n .replace(/\\//g, '_')\n .replace(/\\|/g, '_')\n .toLowerCase()\n )\n}\n\n/**\n * Helper function that converts a Vensim variable name (possibly containing\n * subscripts) into a valid C identifier as used by SDE.\n * TODO: Import helper function from `compile` package instead\n */\nexport function sdeNameForVensimVarName(varName: string): string {\n const m = varName.match(/([^[]+)(?:\\[([^\\]]+)\\])?/)\n if (!m) {\n throw new Error(`Invalid Vensim name: ${varName}`)\n }\n let id = sdeNameForVensimName(m[1])\n if (m[2]) {\n const subscripts = m[2].split(',').map(x => sdeNameForVensimName(x))\n id += `[${subscripts.join('][')}]`\n }\n\n return id\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sdeverywhere/plugin-worker",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist/**",
|
|
6
|
+
"template-worker/**"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/index.cjs",
|
|
10
|
+
"module": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@rollup/plugin-node-resolve": "^13.3.0",
|
|
21
|
+
"@sdeverywhere/build": "^0.1.0",
|
|
22
|
+
"@sdeverywhere/runtime": "^0.1.0",
|
|
23
|
+
"@sdeverywhere/runtime-async": "^0.1.0",
|
|
24
|
+
"vite": "2.9.6"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^16.11.7"
|
|
28
|
+
},
|
|
29
|
+
"author": "Climate Interactive",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"homepage": "https://sdeverywhere.org",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/climateinteractive/SDEverywhere.git",
|
|
35
|
+
"directory": "packages/plugin-worker"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/climateinteractive/SDEverywhere/issues"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"clean": "rm -rf dist",
|
|
42
|
+
"lint": "eslint src --ext .ts --max-warnings 0",
|
|
43
|
+
"prettier:check": "prettier --check .",
|
|
44
|
+
"prettier:fix": "prettier --write .",
|
|
45
|
+
"precommit": "../../scripts/precommit",
|
|
46
|
+
"test": "echo No tests yet",
|
|
47
|
+
"test:watch": "echo No tests yet",
|
|
48
|
+
"test:ci": "echo No tests yet",
|
|
49
|
+
"type-check": "tsc --noEmit -p tsconfig-build.json",
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"ci:build": "run-s clean lint prettier:check test:ci type-check build"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright (c) 2022 Climate Interactive / New Venture Fund
|
|
2
|
+
|
|
3
|
+
import { initWasmModelAndBuffers } from '@sdeverywhere/runtime'
|
|
4
|
+
|
|
5
|
+
// NOTE: This import *must* specify "worker" at the end (instead of the general
|
|
6
|
+
// "index" import), otherwise Vite will pull in more code than necessary and it will
|
|
7
|
+
// generate a worker that won't run correctly in Node or the browser.
|
|
8
|
+
import { exposeModelWorker } from '@sdeverywhere/runtime-async/worker'
|
|
9
|
+
|
|
10
|
+
import { startTime, endTime, numInputs, outputVarIds } from 'virtual:model-spec'
|
|
11
|
+
import loadWasmModule from '@_wasm_'
|
|
12
|
+
|
|
13
|
+
async function initWasmModel() {
|
|
14
|
+
// Load the wasm module asynchronously
|
|
15
|
+
const wasmModule = await loadWasmModule()
|
|
16
|
+
|
|
17
|
+
// Initialize the wasm model and its associated buffers
|
|
18
|
+
return initWasmModelAndBuffers(wasmModule, numInputs, outputVarIds, startTime, endTime)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
exposeModelWorker(initWasmModel)
|