wesl-plugin 0.6.46 → 0.6.49
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/README.md +96 -70
- package/dist/{WeslPlugin-D0IEnDmK.js → WeslPlugin-JYxf2uLM.js} +44 -79
- package/dist/{WeslPluginOptions-BXvD7dWh.d.ts → WeslPluginOptions-BljqDSO5.d.ts} +2 -0
- package/dist/pluginIndex.js +1 -1
- package/dist/plugins/astro.d.ts +1 -1
- package/dist/plugins/astro.js +1 -1
- package/dist/plugins/esbuild.d.ts +1 -1
- package/dist/plugins/esbuild.js +1 -1
- package/dist/plugins/farm.d.ts +1 -1
- package/dist/plugins/farm.js +1 -1
- package/dist/plugins/nuxt.d.ts +1 -1
- package/dist/plugins/nuxt.js +3 -3
- package/dist/plugins/rollup.d.ts +1 -1
- package/dist/plugins/rollup.js +1 -1
- package/dist/plugins/rspack.d.ts +1 -1
- package/dist/plugins/rspack.js +1 -1
- package/dist/plugins/vite.d.ts +1 -1
- package/dist/plugins/vite.js +2 -2
- package/dist/plugins/webpack.d.ts +1 -1
- package/dist/plugins/webpack.js +2 -2
- package/dist/{vite-CccajS5p.js → vite-CE8Yhwk-.js} +1 -1
- package/dist/{webpack-Duvcn8o1.js → webpack-C7YoLSyP.js} +1 -1
- package/package.json +2 -2
- package/src/WeslPlugin.ts +40 -9
- package/src/WeslPluginOptions.ts +3 -0
- package/src/extensions/LinkExtension.ts +1 -1
package/README.md
CHANGED
|
@@ -1,109 +1,135 @@
|
|
|
1
|
-
#
|
|
1
|
+
# WESL Plugin
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/wesl-plugin)
|
|
4
4
|
[](https://wesl-lang.dev/)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
in JavaScript bundlers to make using webgpu shaders more convenient.
|
|
6
|
+
Bundler plugin for importing `.wesl` and `.wgsl` shader files in JavaScript/TypeScript.
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
## Install
|
|
10
9
|
|
|
11
|
-
```ts
|
|
12
|
-
import linkConfig from "./shaders/app.wesl?link";
|
|
13
10
|
```
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import linkConfig from "./shaders/app.wesl?static";
|
|
11
|
+
npm install wesl wesl-plugin
|
|
17
12
|
```
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
## Quick Start
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
### Build-time linking (?static)
|
|
17
|
+
|
|
18
|
+
Link shaders at build time for the smallest application bundle size.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// vite.config.ts
|
|
22
|
+
import { staticBuildExtension } from "wesl-plugin";
|
|
23
|
+
import viteWesl from "wesl-plugin/vite";
|
|
22
24
|
|
|
25
|
+
export default {
|
|
26
|
+
plugins: [viteWesl({ extensions: [staticBuildExtension] })]
|
|
27
|
+
};
|
|
23
28
|
```
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// app.ts
|
|
32
|
+
import wgsl from "./shaders/main.wesl?static";
|
|
33
|
+
|
|
34
|
+
const module = device.createShaderModule({ code: wgsl });
|
|
26
35
|
```
|
|
27
36
|
|
|
28
|
-
###
|
|
37
|
+
### Runtime linking (?link)
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
Link shaders at runtime when you need dynamic conditions or constants:
|
|
31
40
|
|
|
32
41
|
```ts
|
|
33
|
-
|
|
34
|
-
import weslPlugin from "wesl-plugin/vite";
|
|
42
|
+
// vite.config.ts
|
|
35
43
|
import { linkBuildExtension } from "wesl-plugin";
|
|
44
|
+
import viteWesl from "wesl-plugin/vite";
|
|
36
45
|
|
|
37
|
-
|
|
38
|
-
plugins: [
|
|
46
|
+
export default {
|
|
47
|
+
plugins: [viteWesl({ extensions: [linkBuildExtension] })]
|
|
39
48
|
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// app.ts
|
|
53
|
+
import { link } from "wesl";
|
|
54
|
+
import shaderConfig from "./shaders/main.wesl?link";
|
|
55
|
+
|
|
56
|
+
const linked = await link({
|
|
57
|
+
...shaderConfig,
|
|
58
|
+
conditions: { MOBILE: isMobileGPU },
|
|
59
|
+
constants: { num_lights: 4 }
|
|
60
|
+
});
|
|
40
61
|
|
|
41
|
-
|
|
62
|
+
const module = linked.createShaderModule(device, {});
|
|
42
63
|
```
|
|
43
64
|
|
|
44
|
-
|
|
45
|
-
wesl or wgsl shaders with a `?link` suffix and link them into WGSL at runtime.
|
|
65
|
+
## Other Bundlers
|
|
46
66
|
|
|
47
67
|
```ts
|
|
48
|
-
import
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
rootModuleName: "myVerts.wesl",
|
|
54
|
-
conditions: {mobileGPU: true}
|
|
55
|
-
});
|
|
56
|
-
const computeShader = await link({
|
|
57
|
-
...linkConfig,
|
|
58
|
-
rootModuleName: "myCompute.wesl",
|
|
59
|
-
constants: {num_lights: 1}
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
68
|
+
import viteWesl from "wesl-plugin/vite";
|
|
69
|
+
import esbuildWesl from "wesl-plugin/esbuild";
|
|
70
|
+
import rollupWesl from "wesl-plugin/rollup";
|
|
71
|
+
import webpackWesl from "wesl-plugin/webpack";
|
|
72
|
+
// Also: nuxt, farm, rspack, astro
|
|
63
73
|
```
|
|
64
74
|
|
|
65
|
-
|
|
75
|
+
## Extensions
|
|
76
|
+
|
|
77
|
+
Extensions enable different import suffixes:
|
|
78
|
+
|
|
79
|
+
| Extension | Suffix | Output | Use Case |
|
|
80
|
+
|-----------|--------|--------|----------|
|
|
81
|
+
| `staticBuildExtension` | `?static` | WGSL string | Build-time linking, simplest |
|
|
82
|
+
| `linkBuildExtension` | `?link` | LinkParams object | Runtime conditions/constants |
|
|
66
83
|
|
|
67
|
-
|
|
84
|
+
### Combining Extensions
|
|
68
85
|
|
|
69
|
-
```
|
|
70
|
-
import
|
|
71
|
-
import
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
```ts
|
|
87
|
+
import { staticBuildExtension, linkBuildExtension } from "wesl-plugin";
|
|
88
|
+
import viteWesl from "wesl-plugin/vite";
|
|
89
|
+
|
|
90
|
+
export default {
|
|
91
|
+
plugins: [viteWesl({
|
|
92
|
+
extensions: [staticBuildExtension, linkBuildExtension]
|
|
93
|
+
})]
|
|
94
|
+
};
|
|
77
95
|
```
|
|
78
96
|
|
|
79
|
-
|
|
97
|
+
### Conditions in Import Path
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
Reads the `wesl.toml` file to find local shader files and libraries,
|
|
83
|
-
Returns a `LinkParams` object ready to use for runtime linking.
|
|
99
|
+
For `?static`, you can specify conditions directly in the import:
|
|
84
100
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
101
|
+
```ts
|
|
102
|
+
import wgsl from "./app.wesl MOBILE=true DEBUG=false ?static";
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Configuration (wesl.toml)
|
|
106
|
+
|
|
107
|
+
The plugin reads `wesl.toml` to find shader files and dependencies:
|
|
89
108
|
|
|
90
|
-
|
|
109
|
+
```toml
|
|
110
|
+
weslFiles = ["shaders/**/*.wesl"]
|
|
111
|
+
weslRoot = "shaders"
|
|
112
|
+
dependencies = ["auto"] # Auto-detect from package.json
|
|
113
|
+
```
|
|
91
114
|
|
|
92
|
-
|
|
93
|
-
translate some wgsl `struct` elements into JavaScript and TypeScript.
|
|
94
|
-
Demonstrates to wesl-plugin extension authors how to connect
|
|
95
|
-
to the wesl-plugin, how to produce JavaScript, and how to produce TypeScript.
|
|
96
|
-
- **BindingLayoutExtension** - (_prototype_) import `?bindingLayout` to collect JavaScript
|
|
97
|
-
`BindingGroupLayout` objects.
|
|
98
|
-
Works in concert with the `bindingStructsPlugin` to translate a proposed new WGSL
|
|
99
|
-
feature for defining binding group layouts in shaders [#4957](https://github.com/gpuweb/gpuweb/issues/4957).
|
|
115
|
+
## Prototype Extensions
|
|
100
116
|
|
|
101
|
-
|
|
117
|
+
- **SimpleReflectExtension** - Demo for extension authors showing how to generate JS/TS from shader structs
|
|
118
|
+
- **BindingLayoutExtension** - Prototype for generating `BindGroupLayout` objects from shaders
|
|
102
119
|
|
|
103
|
-
|
|
120
|
+
## Writing Custom Extensions
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
122
|
+
```ts
|
|
123
|
+
import type { PluginExtension } from "wesl-plugin";
|
|
124
|
+
|
|
125
|
+
const myExtension: PluginExtension = {
|
|
126
|
+
extensionName: "myfeature", // enables ?myfeature imports
|
|
127
|
+
emitFn: async (shaderPath, api, conditions) => {
|
|
128
|
+
const sources = await api.weslSrc();
|
|
129
|
+
// Return JavaScript code as a string
|
|
130
|
+
return `export default ${JSON.stringify(sources)};`;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
```
|
|
108
134
|
|
|
109
|
-
See [PluginExtension.ts](https://github.com/wgsl-tooling-wg/wesl-js/blob/
|
|
135
|
+
See [PluginExtension.ts](https://github.com/wgsl-tooling-wg/wesl-js/blob/main/tools/packages/wesl-plugin/src/PluginExtension.ts) for the full API.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as resolve } from "./import-meta-resolve-CUFqnZwT.js";
|
|
2
2
|
import path, { posix, win32 } from "node:path";
|
|
3
|
-
import { RecordResolver, WeslParseError,
|
|
3
|
+
import { RecordResolver, WeslParseError, filterMap, findUnboundIdents, npmNameVariations } from "wesl";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import * as actualFS from "node:fs";
|
|
6
6
|
import { createUnplugin } from "unplugin";
|
|
@@ -5841,41 +5841,6 @@ const glob = Object.assign(glob_, {
|
|
|
5841
5841
|
});
|
|
5842
5842
|
glob.glob = glob;
|
|
5843
5843
|
|
|
5844
|
-
//#endregion
|
|
5845
|
-
//#region ../wesl-tooling/src/FindUnboundIdents.ts
|
|
5846
|
-
/**
|
|
5847
|
-
* Find unbound package references in library sources.
|
|
5848
|
-
*
|
|
5849
|
-
* Binds local references without following cross-package imports, revealing
|
|
5850
|
-
* which external packages are referenced but not resolved.
|
|
5851
|
-
*
|
|
5852
|
-
* @param resolver - Module resolver that supports batch operations
|
|
5853
|
-
* @returns Array of unbound module paths, each as an array of path segments
|
|
5854
|
-
* (e.g., [['foo', 'bar', 'baz'], ['other', 'pkg']])
|
|
5855
|
-
*/
|
|
5856
|
-
function findUnboundIdents(resolver) {
|
|
5857
|
-
const bindContext = {
|
|
5858
|
-
resolver,
|
|
5859
|
-
conditions: {},
|
|
5860
|
-
knownDecls: /* @__PURE__ */ new Set(),
|
|
5861
|
-
foundScopes: /* @__PURE__ */ new Set(),
|
|
5862
|
-
globalNames: /* @__PURE__ */ new Set(),
|
|
5863
|
-
globalStatements: /* @__PURE__ */ new Map(),
|
|
5864
|
-
mangler: minimalMangle,
|
|
5865
|
-
unbound: [],
|
|
5866
|
-
dontFollowDecls: true
|
|
5867
|
-
};
|
|
5868
|
-
for (const [_modulePath, ast] of resolver.allModules()) {
|
|
5869
|
-
const declEntries = findValidRootDecls(ast.rootScope, {}).map((d) => [d.originalName, d]);
|
|
5870
|
-
const liveDecls = {
|
|
5871
|
-
decls: new Map(declEntries),
|
|
5872
|
-
parent: null
|
|
5873
|
-
};
|
|
5874
|
-
bindIdentsRecursive(ast.rootScope, bindContext, liveDecls, true);
|
|
5875
|
-
}
|
|
5876
|
-
return bindContext.unbound;
|
|
5877
|
-
}
|
|
5878
|
-
|
|
5879
5844
|
//#endregion
|
|
5880
5845
|
//#region ../../node_modules/.pnpm/toml@3.0.0/node_modules/toml/lib/parser.js
|
|
5881
5846
|
var require_parser = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/toml@3.0.0/node_modules/toml/lib/parser.js": ((exports, module) => {
|
|
@@ -9712,38 +9677,6 @@ async function findWeslToml(projectDir, specifiedToml) {
|
|
|
9712
9677
|
};
|
|
9713
9678
|
}
|
|
9714
9679
|
|
|
9715
|
-
//#endregion
|
|
9716
|
-
//#region ../wesl-tooling/src/PackageNameUtils.ts
|
|
9717
|
-
/** Generate npm package name variations from sanitized WESL identifier.
|
|
9718
|
-
*
|
|
9719
|
-
* Uses double-underscore encoding to distinguish scoped vs unscoped packages:
|
|
9720
|
-
* - Has __ → scoped package (try @scope/pkg variants)
|
|
9721
|
-
* - No __ → unscoped package (try pkg variants)
|
|
9722
|
-
*
|
|
9723
|
-
* Examples:
|
|
9724
|
-
* "lygia__shader_utils" → ["@lygia/shader_utils", "@lygia/shader-utils"]
|
|
9725
|
-
* "random_wgsl" → ["random_wgsl", "random-wgsl"]
|
|
9726
|
-
*/
|
|
9727
|
-
function* npmNameVariations(sanitizedPath) {
|
|
9728
|
-
const [pkg, sub] = breakAt(sanitizedPath, "/");
|
|
9729
|
-
let pkgName = pkg;
|
|
9730
|
-
let scopePrefix = "";
|
|
9731
|
-
if (pkg.includes("__")) {
|
|
9732
|
-
const [scope, ...rest] = pkg.split("__");
|
|
9733
|
-
pkgName = rest.join("__");
|
|
9734
|
-
scopePrefix = `@${scope}/`;
|
|
9735
|
-
}
|
|
9736
|
-
yield `${scopePrefix}${pkgName}${sub}`;
|
|
9737
|
-
yield `${scopePrefix}${pkgName.replaceAll("_", "-")}${sub}`;
|
|
9738
|
-
}
|
|
9739
|
-
/** Break string at first occurrence of delimiter.
|
|
9740
|
-
* @returns [before, after] where after includes the delimiter */
|
|
9741
|
-
function breakAt(str, delimiter) {
|
|
9742
|
-
const index = str.indexOf(delimiter);
|
|
9743
|
-
if (index === -1) return [str, ""];
|
|
9744
|
-
return [str.slice(0, index), str.slice(index)];
|
|
9745
|
-
}
|
|
9746
|
-
|
|
9747
9680
|
//#endregion
|
|
9748
9681
|
//#region ../wesl-tooling/src/NpmResolver.ts
|
|
9749
9682
|
/** Find longest resolvable npm subpath from WESL module path segments.
|
|
@@ -9947,11 +9880,14 @@ function weslPlugin(options, meta) {
|
|
|
9947
9880
|
meta,
|
|
9948
9881
|
options
|
|
9949
9882
|
};
|
|
9883
|
+
const log = options.debug ? debugLog : noopLog;
|
|
9884
|
+
log("init", { extensions: options.extensions?.map((e) => e.extensionName) });
|
|
9950
9885
|
return {
|
|
9951
9886
|
name: "wesl-plugin",
|
|
9952
|
-
resolveId: buildResolver(options, context),
|
|
9953
|
-
load: buildLoader(context),
|
|
9887
|
+
resolveId: buildResolver(options, context, log),
|
|
9888
|
+
load: buildLoader(context, log),
|
|
9954
9889
|
watchChange(id, _change) {
|
|
9890
|
+
log("watchChange", { id });
|
|
9955
9891
|
if (id.endsWith("wesl.toml")) {
|
|
9956
9892
|
cache.weslToml = void 0;
|
|
9957
9893
|
cache.registry = void 0;
|
|
@@ -9972,15 +9908,18 @@ function pluginsByName(options) {
|
|
|
9972
9908
|
* or
|
|
9973
9909
|
* foo/bar.wesl COND=false ?static
|
|
9974
9910
|
*
|
|
9911
|
+
* Bundlers may add extra query params (e.g. Vite adds ?import for dynamic imports,
|
|
9912
|
+
* ?t=123 for cache busting), so we capture the full query and search within it.
|
|
9913
|
+
*
|
|
9975
9914
|
* someday it'd be nice to support import attributes like:
|
|
9976
9915
|
* import "foo.bar.wesl?static" with { COND: false};
|
|
9977
9916
|
* (but that doesn't seem supported to be supported in the the bundler plugins yet)
|
|
9978
9917
|
*/
|
|
9979
|
-
const pluginMatch = /(^^)?(?<baseId>.*\.w[eg]sl)(?<cond>(\s*\w+(=\w+)?\s*)*)\?(?<
|
|
9918
|
+
const pluginMatch = /(^^)?(?<baseId>.*\.w[eg]sl)(?<cond>(\s*\w+(=\w+)?\s*)*)\?(?<query>.+)$/;
|
|
9980
9919
|
const resolvedPrefix = "^^";
|
|
9981
9920
|
/** build plugin entry for 'resolverId'
|
|
9982
9921
|
* to validate our javascript virtual module imports (with e.g. ?static or ?link suffixes) */
|
|
9983
|
-
function buildResolver(options, context) {
|
|
9922
|
+
function buildResolver(options, context, log) {
|
|
9984
9923
|
const suffixes = pluginNames(options);
|
|
9985
9924
|
return resolver;
|
|
9986
9925
|
/**
|
|
@@ -9994,39 +9933,58 @@ function buildResolver(options, context) {
|
|
|
9994
9933
|
if (id.startsWith(resolvedPrefix)) return id;
|
|
9995
9934
|
if (id === context.weslToml) return id;
|
|
9996
9935
|
const matched = pluginSuffixMatch(id, suffixes);
|
|
9936
|
+
log("resolveId", {
|
|
9937
|
+
id,
|
|
9938
|
+
matched: !!matched,
|
|
9939
|
+
suffixes
|
|
9940
|
+
});
|
|
9997
9941
|
if (matched) {
|
|
9998
9942
|
const { importParams, baseId, pluginName } = matched;
|
|
9999
9943
|
const importerDir = path.dirname(importer);
|
|
10000
|
-
|
|
9944
|
+
const result = resolvedPrefix + path.join(importerDir, baseId) + importParams + "?" + pluginName;
|
|
9945
|
+
log("resolveId resolved", { result });
|
|
9946
|
+
return result;
|
|
10001
9947
|
}
|
|
10002
9948
|
return matched ? id : null;
|
|
10003
9949
|
}
|
|
10004
9950
|
}
|
|
9951
|
+
/** Find matching plugin suffix in query string (handles ?import&static, ?t=123&static, etc.) */
|
|
10005
9952
|
function pluginSuffixMatch(id, suffixes) {
|
|
10006
|
-
const
|
|
10007
|
-
const
|
|
10008
|
-
if (!
|
|
9953
|
+
const match$1 = id.match(pluginMatch);
|
|
9954
|
+
const query = match$1?.groups?.query;
|
|
9955
|
+
if (!query) return null;
|
|
9956
|
+
const segments = query.split("&");
|
|
9957
|
+
const pluginName = suffixes.find((s) => segments.includes(s));
|
|
9958
|
+
if (!pluginName) return null;
|
|
10009
9959
|
return {
|
|
10010
9960
|
pluginName,
|
|
10011
|
-
baseId:
|
|
10012
|
-
importParams:
|
|
9961
|
+
baseId: match$1.groups.baseId,
|
|
9962
|
+
importParams: match$1.groups?.cond
|
|
10013
9963
|
};
|
|
10014
9964
|
}
|
|
10015
9965
|
/** build plugin function for serving a javascript module in response to
|
|
10016
9966
|
* an import of of our virtual import modules. */
|
|
10017
|
-
function buildLoader(context) {
|
|
9967
|
+
function buildLoader(context, log) {
|
|
10018
9968
|
const { options } = context;
|
|
10019
9969
|
const suffixes = pluginNames(options);
|
|
10020
9970
|
const pluginsMap = pluginsByName(options);
|
|
10021
9971
|
return loader;
|
|
10022
9972
|
async function loader(id) {
|
|
10023
9973
|
const matched = pluginSuffixMatch(id, suffixes);
|
|
9974
|
+
log("load", {
|
|
9975
|
+
id,
|
|
9976
|
+
matched: matched?.pluginName ?? null
|
|
9977
|
+
});
|
|
10024
9978
|
if (matched) {
|
|
10025
9979
|
const buildPluginApi = buildApi(context, this);
|
|
10026
9980
|
const plugin = pluginsMap[matched.pluginName];
|
|
10027
9981
|
const { baseId, importParams } = matched;
|
|
10028
9982
|
const conditions = importParamsToConditions(importParams);
|
|
10029
9983
|
const shaderPath = baseId.startsWith(resolvedPrefix) ? baseId.slice(2) : baseId;
|
|
9984
|
+
log("load emitting", {
|
|
9985
|
+
shaderPath,
|
|
9986
|
+
conditions
|
|
9987
|
+
});
|
|
10030
9988
|
return await plugin.emitFn(shaderPath, buildPluginApi, conditions);
|
|
10031
9989
|
}
|
|
10032
9990
|
return null;
|
|
@@ -10048,6 +10006,13 @@ function importParamsToConditions(importParams) {
|
|
|
10048
10006
|
});
|
|
10049
10007
|
return Object.fromEntries(condEntries);
|
|
10050
10008
|
}
|
|
10009
|
+
function fmtDebugData(data) {
|
|
10010
|
+
return data ? " " + JSON.stringify(data) : "";
|
|
10011
|
+
}
|
|
10012
|
+
function debugLog(msg, data) {
|
|
10013
|
+
console.error(`[wesl-plugin] ${msg}${fmtDebugData(data)}`);
|
|
10014
|
+
}
|
|
10015
|
+
function noopLog() {}
|
|
10051
10016
|
const unplugin = createUnplugin((options, meta) => {
|
|
10052
10017
|
return weslPlugin(options, meta);
|
|
10053
10018
|
});
|
|
@@ -4,6 +4,8 @@ import { n as PluginExtension } from "./PluginExtension-DlhUTOLC.js";
|
|
|
4
4
|
interface WeslPluginOptions {
|
|
5
5
|
weslToml?: string;
|
|
6
6
|
extensions?: PluginExtension[];
|
|
7
|
+
/** Log plugin activity to stderr for debugging */
|
|
8
|
+
debug?: boolean;
|
|
7
9
|
}
|
|
8
10
|
//#endregion
|
|
9
11
|
export { WeslPluginOptions as t };
|
package/dist/pluginIndex.js
CHANGED
|
@@ -17,7 +17,7 @@ async function emitLinkJs(baseId, api) {
|
|
|
17
17
|
const autoDeps = await api.weslDependencies();
|
|
18
18
|
const sanitizedDeps = autoDeps.map((dep) => dep.replaceAll("/", "_"));
|
|
19
19
|
const bundleImports = autoDeps.map((p, i) => `import ${sanitizedDeps[i]} from "${p}";`).join("\n");
|
|
20
|
-
const paramsName = `link${path.basename(rootModuleName)}Config`;
|
|
20
|
+
const paramsName = `link${path.basename(rootModuleName).replace(/\W/g, "_")}Config`;
|
|
21
21
|
const linkParams = {
|
|
22
22
|
rootModuleName,
|
|
23
23
|
weslSrc,
|
package/dist/plugins/astro.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../PluginExtension-DlhUTOLC.js";
|
|
2
|
-
import { t as WeslPluginOptions } from "../WeslPluginOptions-
|
|
2
|
+
import { t as WeslPluginOptions } from "../WeslPluginOptions-BljqDSO5.js";
|
|
3
3
|
|
|
4
4
|
//#region src/plugins/astro.d.ts
|
|
5
5
|
declare const _default: (options: WeslPluginOptions) => any;
|
package/dist/plugins/astro.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../PluginExtension-DlhUTOLC.js";
|
|
2
|
-
import { t as WeslPluginOptions } from "../WeslPluginOptions-
|
|
2
|
+
import { t as WeslPluginOptions } from "../WeslPluginOptions-BljqDSO5.js";
|
|
3
3
|
import * as esbuild0 from "esbuild";
|
|
4
4
|
|
|
5
5
|
//#region src/plugins/esbuild.d.ts
|
package/dist/plugins/esbuild.js
CHANGED
package/dist/plugins/farm.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../PluginExtension-DlhUTOLC.js";
|
|
2
|
-
import { t as WeslPluginOptions } from "../WeslPluginOptions-
|
|
2
|
+
import { t as WeslPluginOptions } from "../WeslPluginOptions-BljqDSO5.js";
|
|
3
3
|
import * as _farmfe_core0 from "@farmfe/core";
|
|
4
4
|
|
|
5
5
|
//#region src/plugins/farm.d.ts
|
package/dist/plugins/farm.js
CHANGED
package/dist/plugins/nuxt.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../PluginExtension-DlhUTOLC.js";
|
|
2
|
-
import { t as WeslPluginOptions } from "../WeslPluginOptions-
|
|
2
|
+
import { t as WeslPluginOptions } from "../WeslPluginOptions-BljqDSO5.js";
|
|
3
3
|
import * as _nuxt_schema0 from "@nuxt/schema";
|
|
4
4
|
|
|
5
5
|
//#region src/plugins/nuxt.d.ts
|
package/dist/plugins/nuxt.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import "../WeslPlugin-
|
|
1
|
+
import "../WeslPlugin-JYxf2uLM.js";
|
|
2
2
|
import "../import-meta-resolve-CUFqnZwT.js";
|
|
3
|
-
import { t as vite_default } from "../vite-
|
|
4
|
-
import { t as webpack_default } from "../webpack-
|
|
3
|
+
import { t as vite_default } from "../vite-CE8Yhwk-.js";
|
|
4
|
+
import { t as webpack_default } from "../webpack-C7YoLSyP.js";
|
|
5
5
|
import { addVitePlugin, addWebpackPlugin, defineNuxtModule } from "@nuxt/kit";
|
|
6
6
|
import "@nuxt/schema";
|
|
7
7
|
|
package/dist/plugins/rollup.d.ts
CHANGED
package/dist/plugins/rollup.js
CHANGED
package/dist/plugins/rspack.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../PluginExtension-DlhUTOLC.js";
|
|
2
|
-
import { t as WeslPluginOptions } from "../WeslPluginOptions-
|
|
2
|
+
import { t as WeslPluginOptions } from "../WeslPluginOptions-BljqDSO5.js";
|
|
3
3
|
|
|
4
4
|
//#region src/plugins/rspack.d.ts
|
|
5
5
|
declare const _default: (options: WeslPluginOptions) => RspackPluginInstance;
|
package/dist/plugins/rspack.js
CHANGED
package/dist/plugins/vite.d.ts
CHANGED
package/dist/plugins/vite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../WeslPlugin-
|
|
1
|
+
import "../WeslPlugin-JYxf2uLM.js";
|
|
2
2
|
import "../import-meta-resolve-CUFqnZwT.js";
|
|
3
|
-
import { t as vite_default } from "../vite-
|
|
3
|
+
import { t as vite_default } from "../vite-CE8Yhwk-.js";
|
|
4
4
|
|
|
5
5
|
export { vite_default as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../PluginExtension-DlhUTOLC.js";
|
|
2
|
-
import { t as WeslPluginOptions } from "../WeslPluginOptions-
|
|
2
|
+
import { t as WeslPluginOptions } from "../WeslPluginOptions-BljqDSO5.js";
|
|
3
3
|
import * as webpack0 from "webpack";
|
|
4
4
|
|
|
5
5
|
//#region src/plugins/webpack.d.ts
|
package/dist/plugins/webpack.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../WeslPlugin-
|
|
1
|
+
import "../WeslPlugin-JYxf2uLM.js";
|
|
2
2
|
import "../import-meta-resolve-CUFqnZwT.js";
|
|
3
|
-
import { t as webpack_default } from "../webpack-
|
|
3
|
+
import { t as webpack_default } from "../webpack-C7YoLSyP.js";
|
|
4
4
|
|
|
5
5
|
export { webpack_default as default };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wesl-plugin",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.49",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"src",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"unplugin": "^2.3.5",
|
|
28
|
-
"wesl": "0.6.
|
|
28
|
+
"wesl": "0.6.49"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@nuxt/kit": "^3.17.6",
|
package/src/WeslPlugin.ts
CHANGED
|
@@ -50,6 +50,8 @@ export interface PluginContext {
|
|
|
50
50
|
weslToml?: string;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
type DebugLog = (msg: string, data?: Record<string, unknown>) => void;
|
|
54
|
+
|
|
53
55
|
/**
|
|
54
56
|
* A bundler plugin for processing WESL files.
|
|
55
57
|
*
|
|
@@ -66,12 +68,16 @@ export function weslPlugin(
|
|
|
66
68
|
): UnpluginOptions {
|
|
67
69
|
const cache: PluginCache = {};
|
|
68
70
|
const context: PluginContext = { cache, meta, options };
|
|
71
|
+
const log = options.debug ? debugLog : noopLog;
|
|
72
|
+
|
|
73
|
+
log("init", { extensions: options.extensions?.map(e => e.extensionName) });
|
|
69
74
|
|
|
70
75
|
return {
|
|
71
76
|
name: "wesl-plugin",
|
|
72
|
-
resolveId: buildResolver(options, context),
|
|
73
|
-
load: buildLoader(context),
|
|
77
|
+
resolveId: buildResolver(options, context, log),
|
|
78
|
+
load: buildLoader(context, log),
|
|
74
79
|
watchChange(id, _change) {
|
|
80
|
+
log("watchChange", { id });
|
|
75
81
|
if (id.endsWith("wesl.toml")) {
|
|
76
82
|
// The cache is shared for multiple imports
|
|
77
83
|
cache.weslToml = undefined;
|
|
@@ -100,12 +106,15 @@ function pluginsByName(
|
|
|
100
106
|
* or
|
|
101
107
|
* foo/bar.wesl COND=false ?static
|
|
102
108
|
*
|
|
109
|
+
* Bundlers may add extra query params (e.g. Vite adds ?import for dynamic imports,
|
|
110
|
+
* ?t=123 for cache busting), so we capture the full query and search within it.
|
|
111
|
+
*
|
|
103
112
|
* someday it'd be nice to support import attributes like:
|
|
104
113
|
* import "foo.bar.wesl?static" with { COND: false};
|
|
105
114
|
* (but that doesn't seem supported to be supported in the the bundler plugins yet)
|
|
106
115
|
*/
|
|
107
116
|
const pluginMatch =
|
|
108
|
-
/(^^)?(?<baseId>.*\.w[eg]sl)(?<cond>(\s*\w+(=\w+)?\s*)*)\?(?<
|
|
117
|
+
/(^^)?(?<baseId>.*\.w[eg]sl)(?<cond>(\s*\w+(=\w+)?\s*)*)\?(?<query>.+)$/;
|
|
109
118
|
|
|
110
119
|
const resolvedPrefix = "^^";
|
|
111
120
|
|
|
@@ -114,6 +123,7 @@ const resolvedPrefix = "^^";
|
|
|
114
123
|
function buildResolver(
|
|
115
124
|
options: WeslPluginOptions,
|
|
116
125
|
context: PluginContext,
|
|
126
|
+
log: DebugLog,
|
|
117
127
|
): Resolver {
|
|
118
128
|
const suffixes = pluginNames(options);
|
|
119
129
|
return resolver;
|
|
@@ -141,6 +151,7 @@ function buildResolver(
|
|
|
141
151
|
return id;
|
|
142
152
|
}
|
|
143
153
|
const matched = pluginSuffixMatch(id, suffixes);
|
|
154
|
+
log("resolveId", { id, matched: !!matched, suffixes });
|
|
144
155
|
if (matched) {
|
|
145
156
|
const { importParams, baseId, pluginName } = matched;
|
|
146
157
|
|
|
@@ -149,6 +160,7 @@ function buildResolver(
|
|
|
149
160
|
const pathToShader = path.join(importerDir, baseId);
|
|
150
161
|
const result =
|
|
151
162
|
resolvedPrefix + pathToShader + importParams + "?" + pluginName;
|
|
163
|
+
log("resolveId resolved", { result });
|
|
152
164
|
return result;
|
|
153
165
|
}
|
|
154
166
|
return matched ? id : null; // this case doesn't happen AFAIK
|
|
@@ -161,20 +173,27 @@ interface PluginMatch {
|
|
|
161
173
|
pluginName: string;
|
|
162
174
|
}
|
|
163
175
|
|
|
176
|
+
/** Find matching plugin suffix in query string (handles ?import&static, ?t=123&static, etc.) */
|
|
164
177
|
function pluginSuffixMatch(id: string, suffixes: string[]): PluginMatch | null {
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
if (!
|
|
178
|
+
const match = id.match(pluginMatch);
|
|
179
|
+
const query = match?.groups?.query;
|
|
180
|
+
if (!query) return null;
|
|
181
|
+
|
|
182
|
+
// Query params are &-separated; find one that matches a configured suffix
|
|
183
|
+
const segments = query.split("&");
|
|
184
|
+
const pluginName = suffixes.find(s => segments.includes(s));
|
|
185
|
+
if (!pluginName) return null;
|
|
186
|
+
|
|
168
187
|
return {
|
|
169
188
|
pluginName,
|
|
170
|
-
baseId:
|
|
171
|
-
importParams:
|
|
189
|
+
baseId: match.groups!.baseId,
|
|
190
|
+
importParams: match.groups?.cond,
|
|
172
191
|
};
|
|
173
192
|
}
|
|
174
193
|
|
|
175
194
|
/** build plugin function for serving a javascript module in response to
|
|
176
195
|
* an import of of our virtual import modules. */
|
|
177
|
-
function buildLoader(context: PluginContext): Loader {
|
|
196
|
+
function buildLoader(context: PluginContext, log: DebugLog): Loader {
|
|
178
197
|
const { options } = context;
|
|
179
198
|
const suffixes = pluginNames(options);
|
|
180
199
|
const pluginsMap = pluginsByName(options);
|
|
@@ -185,6 +204,7 @@ function buildLoader(context: PluginContext): Loader {
|
|
|
185
204
|
id: string,
|
|
186
205
|
) {
|
|
187
206
|
const matched = pluginSuffixMatch(id, suffixes);
|
|
207
|
+
log("load", { id, matched: matched?.pluginName ?? null });
|
|
188
208
|
if (matched) {
|
|
189
209
|
const buildPluginApi = buildApi(context, this);
|
|
190
210
|
const plugin = pluginsMap[matched.pluginName];
|
|
@@ -194,6 +214,7 @@ function buildLoader(context: PluginContext): Loader {
|
|
|
194
214
|
? baseId.slice(resolvedPrefix.length)
|
|
195
215
|
: baseId;
|
|
196
216
|
|
|
217
|
+
log("load emitting", { shaderPath, conditions });
|
|
197
218
|
return await plugin.emitFn(shaderPath, buildPluginApi, conditions);
|
|
198
219
|
}
|
|
199
220
|
|
|
@@ -226,6 +247,16 @@ function importParamsToConditions(
|
|
|
226
247
|
return conditions;
|
|
227
248
|
}
|
|
228
249
|
|
|
250
|
+
function fmtDebugData(data?: Record<string, unknown>): string {
|
|
251
|
+
return data ? " " + JSON.stringify(data) : "";
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function debugLog(msg: string, data?: Record<string, unknown>): void {
|
|
255
|
+
console.error(`[wesl-plugin] ${msg}${fmtDebugData(data)}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function noopLog(): void {}
|
|
259
|
+
|
|
229
260
|
export const unplugin = createUnplugin(
|
|
230
261
|
(options: WeslPluginOptions, meta: UnpluginContextMeta) => {
|
|
231
262
|
return weslPlugin(options, meta);
|
package/src/WeslPluginOptions.ts
CHANGED
|
@@ -32,7 +32,7 @@ async function emitLinkJs(
|
|
|
32
32
|
.map((p, i) => `import ${sanitizedDeps[i]} from "${p}";`)
|
|
33
33
|
.join("\n");
|
|
34
34
|
|
|
35
|
-
const rootName = path.basename(rootModuleName);
|
|
35
|
+
const rootName = path.basename(rootModuleName).replace(/\W/g, "_");
|
|
36
36
|
const paramsName = `link${rootName}Config`;
|
|
37
37
|
|
|
38
38
|
const linkParams: LinkParams = {
|