@symbiote-native/vue 0.2.0 → 0.3.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/metro-css-parser.cjs +9 -4
- package/metro-vue-transformer.cjs +313 -0
- package/package.json +8 -4
package/metro-css-parser.cjs
CHANGED
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
// requiring FILE's own location, so this indirection is what actually removes the extra install
|
|
7
7
|
// step, not pnpm hoisting (which does not propagate this transitively across workspace packages
|
|
8
8
|
// the way a flat classic node_modules would). .cjs, not .js: this package is "type": "module",
|
|
9
|
-
// and Metro's babelTransformerPath loading expects a require()-able module. Used
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
|
|
9
|
+
// and Metro's babelTransformerPath loading expects a require()-able module. Used as
|
|
10
|
+
// vue-tsx's babelTransformerPath for standalone .css/.module.css file imports —
|
|
11
|
+
// metro-vue-transformer.cjs (the .vue SFC transformer) requires @symbiote-native/css-parser
|
|
12
|
+
// directly instead, since it needs the individual parse/compile functions, not a Metro
|
|
13
|
+
// transformer object. See the symbiote-sfc-style-compiler skill.
|
|
14
|
+
// createCssMetroTransformer is a factory, not a ready transformer — Metro's
|
|
15
|
+
// babelTransformerPath needs the actual {transform, getCacheKey} object it returns,
|
|
16
|
+
// not the css-parser package barrel.
|
|
17
|
+
module.exports = require('@symbiote-native/css-parser').createCssMetroTransformer();
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// Metro babel transformer that teaches the bundler to read Vue SFCs (.vue). Metro has no
|
|
2
|
+
// Vue plugin (unplugin-vue ships vite/webpack/esbuild/rollup adapters, not Metro), so we do
|
|
3
|
+
// the single-pass compile here: parse the SFC, compile <script setup> + <template> into one
|
|
4
|
+
// component module, then hand the JS to RN's own babel transformer. This is the Metro twin
|
|
5
|
+
// of what @vitejs/plugin-vue does for Vite; the 'vue'→runtime-core rewrite is wolf-tui's
|
|
6
|
+
// pattern (a custom, non-DOM renderer needs the compiler helpers from @vue/runtime-core,
|
|
7
|
+
// not from vue/runtime-dom).
|
|
8
|
+
//
|
|
9
|
+
// Retargeted at @symbiote-native/vue/runtime-helpers rather than bare @vue/runtime-core: that shim
|
|
10
|
+
// re-exports runtime-core verbatim PLUS supplies our own `vShow` (compiled v-show imports it by
|
|
11
|
+
// name, and only @vue/runtime-dom's DOM-based version exists otherwise — see the
|
|
12
|
+
// vue-adapter-directives skill).
|
|
13
|
+
//
|
|
14
|
+
// Ships as a package-level export (`@symbiote-native/vue/metro-vue-transformer`) rather than living
|
|
15
|
+
// in each consuming app: a consumer's own metro.config.js just points babelTransformerPath at it —
|
|
16
|
+
// see the symbiote-sfc-style-compiler skill.
|
|
17
|
+
|
|
18
|
+
const { parse, compileScript } = require('@vue/compiler-sfc');
|
|
19
|
+
const { createCompoundExpression } = require('@vue/compiler-core');
|
|
20
|
+
// @symbiote-native/css-parser is a real dependency of THIS package, so requiring it directly here
|
|
21
|
+
// (rather than through the ./metro-css-parser public subpath, which exists for CONSUMERS) resolves
|
|
22
|
+
// straight from this package's own node_modules under pnpm.
|
|
23
|
+
const {
|
|
24
|
+
compile: compilePreprocessor,
|
|
25
|
+
compileCssFile,
|
|
26
|
+
globalClassNamesIn,
|
|
27
|
+
hashFilePath,
|
|
28
|
+
isStyleFile,
|
|
29
|
+
kebabToCamel,
|
|
30
|
+
parseCSS,
|
|
31
|
+
resolveUpstreamTransformer,
|
|
32
|
+
} = require('@symbiote-native/css-parser');
|
|
33
|
+
|
|
34
|
+
const upstreamTransformer = resolveUpstreamTransformer();
|
|
35
|
+
|
|
36
|
+
// Rewrites a Vue template AST so every `class`/`:class` binding on an element resolves
|
|
37
|
+
// against this file's scoped class names at the compiled call site, via @symbiote-native/engine's
|
|
38
|
+
// scopeClassName(value, localNames, scopeId) — see the symbiote-sfc-style-compiler skill for
|
|
39
|
+
// the full design (why AST-level, not a raw-text regex: Vue itself merges a static `class=`
|
|
40
|
+
// and a dynamic `:class=` on the same element into ONE codegen entry, and text substitution
|
|
41
|
+
// can't reproduce that merge safely; letting Vue's own transformElement do the merge on our
|
|
42
|
+
// already-rewritten nodes reuses that logic instead of reimplementing it).
|
|
43
|
+
//
|
|
44
|
+
// A static class="foo bar" attribute is a plain AttributeNode (prop.type === 6): its value is
|
|
45
|
+
// resolved to the final string directly here, at compile time — no runtime call needed for the
|
|
46
|
+
// purely-static case, since every token is already known. Each token is normalized kebab->camel
|
|
47
|
+
// FIRST (kebabToCamel) — a template may write class="section-label" (idiomatic CSS) instead of
|
|
48
|
+
// class="sectionLabel"; the css-parser always registers the CAMEL form, and localNames (built
|
|
49
|
+
// from that same registration) is camelCase-keyed, so the scoping check below only recognizes a
|
|
50
|
+
// token once it is in that form. The emitted string is always camelCase, suffixed or not.
|
|
51
|
+
//
|
|
52
|
+
// A dynamic :class="expr" is a `bind` DirectiveNode (prop.type === 7) targeting the `class`
|
|
53
|
+
// arg. Vue's own transformExpression has ALREADY run by the time our transform sees it (node
|
|
54
|
+
// transforms are appended after the built-in preset, per @vue/compiler-core's TransformOptions
|
|
55
|
+
// merge order), so prop.exp is usually a COMPOUND_EXPRESSION (type 8, a `children` array mixing
|
|
56
|
+
// literal source chunks with resolved identifier nodes), not a plain string — a bare identifier
|
|
57
|
+
// binding (`:class="dynamicClass"`) is the one case that stays a SIMPLE_EXPRESSION (type 4).
|
|
58
|
+
// Either way, `createCompoundExpression` wraps the ORIGINAL exp node (whichever shape it is) as
|
|
59
|
+
// a single child inside `scopeClassName(<original>, __localScopedClassNames, __scopeId)`, so
|
|
60
|
+
// codegen emits the call with the original expression source reproduced unchanged inside it —
|
|
61
|
+
// this needs no per-shape branching, and correctly defers even a fully opaque runtime value
|
|
62
|
+
// (`:class="dynamicClass"`) to scopeClassName's own runtime token-matching, so there is no
|
|
63
|
+
// unresolved gap for dynamic scoped classes.
|
|
64
|
+
function createScopeClassNodeTransform(localNames, scopeId) {
|
|
65
|
+
return function scopeClassNodeTransform(node) {
|
|
66
|
+
if (node.type !== 1 /* NodeTypes.ELEMENT */) return;
|
|
67
|
+
|
|
68
|
+
for (const prop of node.props) {
|
|
69
|
+
if (prop.type === 6 /* NodeTypes.ATTRIBUTE */ && prop.name === 'class' && prop.value) {
|
|
70
|
+
prop.value.content = prop.value.content
|
|
71
|
+
.split(/\s+/)
|
|
72
|
+
.filter(Boolean)
|
|
73
|
+
.map((token) => {
|
|
74
|
+
const camelToken = kebabToCamel(token);
|
|
75
|
+
return localNames.has(camelToken) ? `${camelToken}__${scopeId}` : camelToken;
|
|
76
|
+
})
|
|
77
|
+
.join(' ');
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
prop.type === 7 /* NodeTypes.DIRECTIVE */ &&
|
|
83
|
+
prop.name === 'bind' &&
|
|
84
|
+
prop.arg &&
|
|
85
|
+
prop.arg.type === 4 /* NodeTypes.SIMPLE_EXPRESSION */ &&
|
|
86
|
+
prop.arg.content === 'class' &&
|
|
87
|
+
prop.exp
|
|
88
|
+
) {
|
|
89
|
+
prop.exp = createCompoundExpression(
|
|
90
|
+
['__scopeClass(', prop.exp, ', __localScopedClassNames, __scopeId)'],
|
|
91
|
+
prop.exp.loc,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// A short, stable id per file, used as the SFC scope id (compileScript wants one regardless of
|
|
99
|
+
// whether the file has scoped styles) — Vue's own `data-v-hash` naming convention, built on
|
|
100
|
+
// @symbiote-native/css-parser's shared hashFilePath so the algorithm isn't duplicated against the
|
|
101
|
+
// standalone .module.css compiler's identical need (metro-css-module.ts).
|
|
102
|
+
function scopeIdFor(filename) {
|
|
103
|
+
return 'data-v-' + hashFilePath(filename);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// An SFC style block's `lang` attribute names a preprocessor language directly (`lang="scss"`),
|
|
107
|
+
// unlike a standalone file, which is identified by its extension — so this is its own small
|
|
108
|
+
// lookup rather than reusing detectLanguage(), which is extension-keyed.
|
|
109
|
+
const SFC_STYLE_LANG_TO_PREPROCESSOR = new Map([
|
|
110
|
+
['scss', 'scss'],
|
|
111
|
+
['sass', 'scss'],
|
|
112
|
+
['less', 'less'],
|
|
113
|
+
['stylus', 'stylus'],
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
// Reduces one <style> block down to plain CSS text. A lang-less or lang="css" block passes
|
|
117
|
+
// through unchanged, exactly as before. Anything outside the four recognized preprocessor langs
|
|
118
|
+
// (a typo, or a genuinely unsupported lang) still throws, same message as before this feature
|
|
119
|
+
// existed.
|
|
120
|
+
async function compileStyleBlockContent(style, filename) {
|
|
121
|
+
if (style.lang == null || style.lang === 'css') return style.content;
|
|
122
|
+
|
|
123
|
+
const preprocessorLang = SFC_STYLE_LANG_TO_PREPROCESSOR.get(style.lang);
|
|
124
|
+
if (!preprocessorLang) {
|
|
125
|
+
throw new Error(`SFC style lang="${style.lang}" not supported yet — plain CSS only`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Sass' `.sass` indented syntax and `.scss` syntax share one compiler entry point that picks
|
|
129
|
+
// between them off the file extension (see preprocessors.ts's compileScss) — an inline SFC
|
|
130
|
+
// style block has no file of its own, so a synthetic `.sass`-suffixed path is the only way to
|
|
131
|
+
// select the indented syntax. Every other preprocessor only uses the path for relative-import
|
|
132
|
+
// resolution (dirname), where the real .vue file's own path is correct as-is.
|
|
133
|
+
const syntheticPath = style.lang === 'sass' ? `${filename}.sass` : filename;
|
|
134
|
+
return compilePreprocessor(style.content, preprocessorLang, syntheticPath);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function compileSfc(src, filename) {
|
|
138
|
+
const { descriptor, errors } = parse(src, { filename });
|
|
139
|
+
if (errors && errors.length > 0) {
|
|
140
|
+
throw new Error(`Vue SFC parse error in ${filename}:\n${errors.map(String).join('\n')}`);
|
|
141
|
+
}
|
|
142
|
+
if (descriptor.scriptSetup == null && descriptor.script == null) {
|
|
143
|
+
throw new Error(`Vue SFC ${filename} has no <script> / <script setup> block`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const scopeId = scopeIdFor(filename);
|
|
147
|
+
|
|
148
|
+
// `descriptor.styles` is already parsed by @vue/compiler-sfc itself (one entry per <style>
|
|
149
|
+
// block, `.content` pre-trimmed, `.scoped` already a plain boolean flag), so there's no need
|
|
150
|
+
// to re-extract style blocks with a regex the way wolf-tui's Vite plugin does.
|
|
151
|
+
//
|
|
152
|
+
// A scoped block's classes get their key SUFFIXED with this file's scopeId before
|
|
153
|
+
// registration (`card` -> `card__data-v-xxxxxxxx`), so two components can each define their
|
|
154
|
+
// own `.card` without colliding in the shared global registry — mirroring what Vue's own
|
|
155
|
+
// `data-v-hash` attribute does for DOM targets, just as a name suffix instead of an attribute
|
|
156
|
+
// selector (we have neither DOM nor attribute-selector matching). An unscoped block's classes
|
|
157
|
+
// register exactly as before: no suffix, globally shared. `:global(...)` selectors inside a
|
|
158
|
+
// scoped block are the one exception — @symbiote-native/css-parser already unwraps them to their
|
|
159
|
+
// plain class name (`:global(.reset)` parses like `.reset`), so `globalClassNamesIn` re-scans
|
|
160
|
+
// the block's own raw text to find which specific keys should be exempted from suffixing.
|
|
161
|
+
//
|
|
162
|
+
// Cascade multiple blocks last-block-wins, same as CSS — this holds across scoped/unscoped
|
|
163
|
+
// blocks too: only each block's OWN css-parser output is scoped independently, then merged.
|
|
164
|
+
//
|
|
165
|
+
// <style module> (CSS Modules) reuses this exact suffixing machinery instead of a separate
|
|
166
|
+
// pipeline: `.card` still goes through parseCSS unchanged and still registers via the same
|
|
167
|
+
// registerStyles() call, just under a suffixed key — the only new output is a plain name->
|
|
168
|
+
// scopedName object (`$style` by default, or the block's `module="name"` value) emitted as a
|
|
169
|
+
// preamble const, so `:class="$style.card"` passes the already-scoped string straight to
|
|
170
|
+
// resolveClassName's existing exact-match path (no registry changes needed, see the
|
|
171
|
+
// symbiote-sfc-style-compiler skill). Unlike `scoped`, a module block's classes are NEVER
|
|
172
|
+
// auto-applied to a literal class="..." attribute — CSS Modules is opt-in per usage via
|
|
173
|
+
// `$style.x`, so module classes are kept out of `localScopedNames` (the nodeTransform only
|
|
174
|
+
// rewrites literal class strings for `scoped` blocks). The registry key gets an extra
|
|
175
|
+
// `module` tag (`card__module__<scopeId>`, vs scoped's plain `card__<scopeId>`) so a file
|
|
176
|
+
// that happens to mix `<style scoped>` and `<style module>` with the same class name can't
|
|
177
|
+
// collide in the shared registry.
|
|
178
|
+
const styles = {};
|
|
179
|
+
const localScopedNames = new Set();
|
|
180
|
+
const cssModuleBindings = new Map();
|
|
181
|
+
|
|
182
|
+
for (const style of descriptor.styles) {
|
|
183
|
+
// Reduces a preprocessor block down to plain CSS text BEFORE any of the scoping logic
|
|
184
|
+
// below runs — that logic is entirely language-agnostic, it only ever sees parseCSS's
|
|
185
|
+
// plain-CSS output, same as it always did for a lang-less/lang="css" block. Anything other
|
|
186
|
+
// than the four recognized preprocessor langs (a typo, or a genuinely unsupported lang)
|
|
187
|
+
// still throws, unchanged from before.
|
|
188
|
+
const content = await compileStyleBlockContent(style, filename);
|
|
189
|
+
const parsed = parseCSS(content, { filename });
|
|
190
|
+
|
|
191
|
+
if (style.module) {
|
|
192
|
+
const bindingName = typeof style.module === 'string' ? style.module : '$style';
|
|
193
|
+
// Scanned against the COMPILED content, not style.content: :global(...) isn't native
|
|
194
|
+
// SCSS/Less/Stylus syntax (each preprocessor passes an unrecognized selector through
|
|
195
|
+
// unchanged), but scanning the compiler's actual output can't drift under nesting/
|
|
196
|
+
// interpolation the way assuming source-and-output stay textually identical could.
|
|
197
|
+
const exemptFromScope = globalClassNamesIn(content);
|
|
198
|
+
const classMap = cssModuleBindings.get(bindingName) ?? {};
|
|
199
|
+
for (const [className, props] of Object.entries(parsed)) {
|
|
200
|
+
const isExempt = exemptFromScope.has(className);
|
|
201
|
+
const registeredName = isExempt ? className : `${className}__module__${scopeId}`;
|
|
202
|
+
classMap[className] = registeredName;
|
|
203
|
+
styles[registeredName] = { ...styles[registeredName], ...props };
|
|
204
|
+
}
|
|
205
|
+
cssModuleBindings.set(bindingName, classMap);
|
|
206
|
+
} else if (style.scoped) {
|
|
207
|
+
const exemptFromScope = globalClassNamesIn(content);
|
|
208
|
+
for (const [className, props] of Object.entries(parsed)) {
|
|
209
|
+
const isExempt = exemptFromScope.has(className);
|
|
210
|
+
const registeredName = isExempt ? className : `${className}__${scopeId}`;
|
|
211
|
+
if (!isExempt) localScopedNames.add(className);
|
|
212
|
+
styles[registeredName] = { ...styles[registeredName], ...props };
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
for (const [className, props] of Object.entries(parsed)) {
|
|
216
|
+
styles[className] = { ...styles[className], ...props };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// The nodeTransform rewrites every class/:class binding's compiled output to route through
|
|
222
|
+
// scopeClassName() at the scoped names this file actually defines — skipped entirely (not
|
|
223
|
+
// even passed to the compiler) when nothing in this file is scoped, so a .vue with only
|
|
224
|
+
// unscoped/no styles compiles exactly as before, zero added runtime cost or behavior change.
|
|
225
|
+
const templateOptions =
|
|
226
|
+
localScopedNames.size > 0
|
|
227
|
+
? {
|
|
228
|
+
compilerOptions: {
|
|
229
|
+
nodeTransforms: [createScopeClassNodeTransform(localScopedNames, scopeId)],
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
: undefined;
|
|
233
|
+
|
|
234
|
+
// inlineTemplate folds the <template> render fn into setup(): one module, one `export
|
|
235
|
+
// default`. Only valid with <script setup>, which the canary uses.
|
|
236
|
+
const compiled = compileScript(descriptor, {
|
|
237
|
+
id: scopeId,
|
|
238
|
+
inlineTemplate: true,
|
|
239
|
+
templateOptions,
|
|
240
|
+
});
|
|
241
|
+
// Point every Vue import (the compiler's injected helpers AND the user's own
|
|
242
|
+
// `import { ref } from 'vue'`) at the runtime-helpers shim, which re-exports the same
|
|
243
|
+
// @vue/runtime-core singleton the @symbiote-native/vue adapter builds its custom renderer on, plus
|
|
244
|
+
// our own directive implementations. No vue/runtime-dom in a native bundle.
|
|
245
|
+
const code = compiled.content.replace(/from\s*(['"])vue\1/g, 'from "@symbiote-native/vue/runtime-helpers"');
|
|
246
|
+
|
|
247
|
+
if (Object.keys(styles).length === 0) return code;
|
|
248
|
+
|
|
249
|
+
// Only a scoped file needs scopeClassName + its two per-file constants — the nodeTransform
|
|
250
|
+
// above only ever emits calls to `__scopeClass`/`__localScopedClassNames`/`__scopeId` when
|
|
251
|
+
// localScopedNames is non-empty, so these stay unimported/undeclared (and absent from the
|
|
252
|
+
// bundle) for every non-scoped .vue file.
|
|
253
|
+
const engineImports =
|
|
254
|
+
localScopedNames.size > 0 ? 'registerStyles, scopeClassName as __scopeClass' : 'registerStyles';
|
|
255
|
+
|
|
256
|
+
const preamble = [`registerStyles(${JSON.stringify(styles)});`];
|
|
257
|
+
if (localScopedNames.size > 0) {
|
|
258
|
+
preamble.push(
|
|
259
|
+
`const __localScopedClassNames = new Set(${JSON.stringify([...localScopedNames])});`,
|
|
260
|
+
`const __scopeId = ${JSON.stringify(scopeId)};`,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
// Each <style module> binding becomes a plain top-level const holding its name->scopedName
|
|
264
|
+
// map. Placed before the compiled `export default {...}`, so it's just a closed-over module
|
|
265
|
+
// scope variable inside setup() — same trick registerStyles/__scopeId already rely on — and
|
|
266
|
+
// usable both from the inlined template (`:class="$style.card"`) and from <script setup> code
|
|
267
|
+
// itself (`$style.card`), no extra wiring needed on either side.
|
|
268
|
+
for (const [bindingName, classMap] of cssModuleBindings) {
|
|
269
|
+
preamble.push(`const ${bindingName} = ${JSON.stringify(classMap)};`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return [`import { ${engineImports} } from '@symbiote-native/engine';`, ...preamble, code].join('\n') + '\n';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Exported separately from `transform` so tests can assert on the compiled SFC output
|
|
276
|
+
// (imports, injected `registerStyles` call) without driving the full upstream RN Babel preset.
|
|
277
|
+
module.exports.compileSfc = compileSfc;
|
|
278
|
+
|
|
279
|
+
// Async uniformly, including the `.vue` and plain-passthrough branches that never touch a
|
|
280
|
+
// preprocessor: compileSfc() itself is async now (a scss/sass/less/stylus <style> block awaits
|
|
281
|
+
// preprocessors.ts's compile()), and Metro's own metro-transform-worker already
|
|
282
|
+
// `await transformer.transform(...)` before touching the result (confirmed by reading the
|
|
283
|
+
// installed metro-transform-worker source — see metro-transformer.ts for the fuller writeup),
|
|
284
|
+
// so returning a Promise here is a supported, exercised shape, not a hack. A sync fast-path for
|
|
285
|
+
// the no-preprocessor branches would fork this function into two shapes to save a single
|
|
286
|
+
// microtask on a call that only ever runs at Metro build time, content-hash-cached — not worth
|
|
287
|
+
// the duplication.
|
|
288
|
+
module.exports.transform = async function transform(params) {
|
|
289
|
+
if (params.filename.endsWith('.vue')) {
|
|
290
|
+
const code = await compileSfc(params.src, params.filename);
|
|
291
|
+
// Re-label as .tsx so RN's transformer strips any TS from <script setup lang="ts"> and
|
|
292
|
+
// processes the module exactly like app source. Metro tracks the real path separately.
|
|
293
|
+
return upstreamTransformer.transform({
|
|
294
|
+
...params,
|
|
295
|
+
src: code,
|
|
296
|
+
filename: params.filename + '.tsx',
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
// A standalone style file (as opposed to a `.vue` file's own inline <style> block above) —
|
|
300
|
+
// the framework-agnostic path (core/css-parser's compileCssFile), usable from this example's
|
|
301
|
+
// .vue files exactly like from any other adapter's example. isStyleFile recognizes
|
|
302
|
+
// .css/.scss/.sass/.less/.styl/.stylus (+ each .module.* twin) — see the
|
|
303
|
+
// symbiote-sfc-style-compiler skill.
|
|
304
|
+
if (isStyleFile(params.filename)) {
|
|
305
|
+
const { code } = await compileCssFile(params.src, params.filename);
|
|
306
|
+
return upstreamTransformer.transform({ ...params, src: code, filename: params.filename + '.js' });
|
|
307
|
+
}
|
|
308
|
+
return upstreamTransformer.transform(params);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// Surface the upstream cache key so RN preset changes still bust Metro's cache. The SFC
|
|
312
|
+
// step itself is invalidated by `--reset-cache` (mirrors the babel DEBUG-inline note).
|
|
313
|
+
module.exports.getCacheKey = upstreamTransformer.getCacheKey;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "SymbioteNative's Vue adapter — a @vue/runtime-core createRenderer driving real native iOS/Android views through the same engine as the React adapter.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,19 +29,23 @@
|
|
|
29
29
|
"types": "./build/runtime-helpers.d.ts",
|
|
30
30
|
"default": "./build/runtime-helpers.js"
|
|
31
31
|
},
|
|
32
|
-
"./metro-css-parser": "./metro-css-parser.cjs"
|
|
32
|
+
"./metro-css-parser": "./metro-css-parser.cjs",
|
|
33
|
+
"./metro-vue-transformer": "./metro-vue-transformer.cjs"
|
|
33
34
|
},
|
|
34
35
|
"files": [
|
|
35
36
|
"build",
|
|
36
|
-
"metro-css-parser.cjs"
|
|
37
|
+
"metro-css-parser.cjs",
|
|
38
|
+
"metro-vue-transformer.cjs"
|
|
37
39
|
],
|
|
38
40
|
"publishConfig": {
|
|
39
41
|
"access": "public"
|
|
40
42
|
},
|
|
41
43
|
"dependencies": {
|
|
44
|
+
"@vue/compiler-core": "^3.5.13",
|
|
45
|
+
"@vue/compiler-sfc": "^3.5.13",
|
|
42
46
|
"@vue/runtime-core": "^3.5.13",
|
|
43
|
-
"@symbiote-native/css-parser": "0.1.1",
|
|
44
47
|
"@symbiote-native/components": "0.2.0",
|
|
48
|
+
"@symbiote-native/css-parser": "0.2.0",
|
|
45
49
|
"@symbiote-native/engine": "0.1.1"
|
|
46
50
|
},
|
|
47
51
|
"peerDependencies": {
|