@plumeria/vite-plugin 3.0.0 → 3.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.
Files changed (2) hide show
  1. package/dist/index.js +325 -168
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -3,8 +3,8 @@ import { parseSync } from '@swc/core';
3
3
  import path from 'path';
4
4
  import { genBase36Hash } from 'zss-engine';
5
5
  import { tables, traverse, getStyleRecords, collectLocalConsts, objectExpressionToObject, scanForCreateStatic, scanForCreateTheme, scanForKeyframes, scanForViewTransition, t, extractOndemandStyles, } from '@plumeria/utils';
6
- const TARGET_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx', 'vue', 'svelte'];
7
- const EXTENSION_PATTERN = /\.(ts|tsx|js|jsx|vue|svelte)$/;
6
+ const TARGET_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx'];
7
+ const EXTENSION_PATTERN = /\.(ts|tsx|js|jsx)$/;
8
8
  export function plumeria(options = {}) {
9
9
  const { include, exclude } = options;
10
10
  const filter = createFilter(include, exclude);
@@ -53,21 +53,17 @@ export function plumeria(options = {}) {
53
53
  .filter((m) => !!m)
54
54
  .concat(ctx.modules);
55
55
  },
56
- transform(source, url) {
57
- const [id] = url.split('?', 1);
58
- if (id.includes('node_modules')) {
56
+ transform(source, id) {
57
+ if (id.includes('node_modules'))
59
58
  return null;
60
- }
61
- if (url.includes('?')) {
59
+ if (id.includes('?'))
62
60
  return null;
63
- }
64
61
  const ext = id.split('.').pop() || '';
65
- if (!TARGET_EXTENSIONS.includes(ext)) {
62
+ if (!TARGET_EXTENSIONS.includes(ext))
66
63
  return null;
67
- }
68
- if (!filter(id)) {
64
+ if (!filter(id))
69
65
  return null;
70
- }
66
+ const isTSFile = id.endsWith('.ts') && !id.endsWith('.tsx');
71
67
  const dependencies = [];
72
68
  const addDependency = (depPath) => {
73
69
  dependencies.push(depPath);
@@ -83,176 +79,347 @@ export function plumeria(options = {}) {
83
79
  const { themeTableLocal, createThemeObjectTableLocal } = scanForCreateTheme(addDependency);
84
80
  tables.themeTable = themeTableLocal;
85
81
  tables.createThemeObjectTable = createThemeObjectTableLocal;
86
- const extractedSheets = [];
87
- let ast;
88
- const scriptContents = getScriptContents(source, id);
82
+ const ast = parseSync(source, {
83
+ syntax: 'typescript',
84
+ tsx: true,
85
+ target: 'es2022',
86
+ });
87
+ const localConsts = collectLocalConsts(ast);
88
+ Object.assign(tables.staticTable, localConsts);
89
+ const localCreateStyles = {};
89
90
  const replacements = [];
90
- for (const content of scriptContents) {
91
- if (!content.trim())
92
- continue;
93
- try {
94
- ast = parseSync(content, {
95
- syntax: 'typescript',
96
- tsx: true,
97
- target: 'es2022',
98
- });
99
- }
100
- catch (err) {
101
- console.warn(`Zero Styled: Parse error in ${id}`, err);
102
- continue;
103
- }
104
- const localConsts = collectLocalConsts(ast);
105
- Object.assign(tables.staticTable, localConsts);
106
- const localCreateStyles = {};
107
- traverse(ast, {
108
- VariableDeclarator({ node }) {
109
- if (node.id.type === 'Identifier' &&
110
- node.init &&
111
- t.isCallExpression(node.init) &&
112
- t.isMemberExpression(node.init.callee) &&
113
- t.isIdentifier(node.init.callee.object, { name: 'css' }) &&
114
- t.isIdentifier(node.init.callee.property, { name: 'create' }) &&
115
- node.init.arguments.length === 1 &&
116
- t.isObjectExpression(node.init.arguments[0].expression)) {
117
- const obj = objectExpressionToObject(node.init.arguments[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
118
- if (obj) {
119
- localCreateStyles[node.id.value] = obj;
120
- const hashMap = {};
121
- Object.entries(obj).forEach(([key, style]) => {
122
- const records = getStyleRecords(key, style, 1);
123
- const propMap = {};
124
- extractOndemandStyles(style, extractedSheets);
125
- records.forEach((r) => {
126
- propMap[r.key] = r.hash;
127
- extractedSheets.push(r.sheet);
128
- });
129
- hashMap[key] = records.map((r) => r.hash).join(' ');
91
+ const extractedSheets = [];
92
+ const processedDecls = new Set();
93
+ const excludedSpans = new Set();
94
+ const idSpans = new Set();
95
+ const registerStyle = (node, declSpan, isExported) => {
96
+ if (t.isIdentifier(node.id) &&
97
+ node.init &&
98
+ t.isCallExpression(node.init) &&
99
+ t.isMemberExpression(node.init.callee) &&
100
+ t.isIdentifier(node.init.callee.object, { name: 'css' }) &&
101
+ t.isIdentifier(node.init.callee.property) &&
102
+ node.init.arguments.length >= 1) {
103
+ const propName = node.init.callee.property.value;
104
+ if (propName === 'create' &&
105
+ t.isObjectExpression(node.init.arguments[0].expression)) {
106
+ const obj = objectExpressionToObject(node.init.arguments[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
107
+ if (obj) {
108
+ const hashMap = {};
109
+ Object.entries(obj).forEach(([key, style]) => {
110
+ const records = getStyleRecords(key, style, 2);
111
+ extractOndemandStyles(style, extractedSheets);
112
+ records.forEach((r) => {
113
+ extractedSheets.push(r.sheet);
130
114
  });
131
- replacements.push({
115
+ const atomMap = {};
116
+ records.forEach((r) => (atomMap[r.key] = r.hash));
117
+ hashMap[key] = atomMap;
118
+ });
119
+ if (t.isIdentifier(node.id)) {
120
+ idSpans.add(node.id.span.start);
121
+ }
122
+ localCreateStyles[node.id.value] = {
123
+ name: node.id.value,
124
+ type: 'create',
125
+ obj,
126
+ hashMap,
127
+ hasDynamicAccess: false,
128
+ isExported,
129
+ initSpan: {
132
130
  start: node.init.span.start - ast.span.start,
133
131
  end: node.init.span.end - ast.span.start,
134
- content: JSON.stringify(hashMap),
135
- });
136
- }
132
+ },
133
+ declSpan: {
134
+ start: declSpan.start - ast.span.start,
135
+ end: declSpan.end - ast.span.start,
136
+ },
137
+ };
137
138
  }
138
- },
139
- CallExpression({ node }) {
140
- const callee = node.callee;
141
- if (t.isMemberExpression(callee) &&
142
- t.isIdentifier(callee.object, { name: 'css' }) &&
143
- t.isIdentifier(callee.property)) {
144
- const args = node.arguments;
145
- if (callee.property.value === 'props') {
146
- const merged = {};
147
- let allStatic = true;
148
- args.forEach((arg) => {
149
- const expr = arg.expression;
150
- if (t.isObjectExpression(expr)) {
151
- const obj = objectExpressionToObject(expr, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
152
- if (obj) {
153
- Object.assign(merged, obj);
154
- }
155
- else {
156
- allStatic = false;
157
- }
158
- }
159
- else if (t.isMemberExpression(expr)) {
160
- if (t.isIdentifier(expr.object) &&
161
- t.isIdentifier(expr.property)) {
162
- const varName = expr.object.value;
163
- const propName = expr.property.value;
164
- const styleSet = localCreateStyles[varName];
165
- if (styleSet && styleSet[propName]) {
166
- Object.assign(merged, styleSet[propName]);
167
- }
168
- else {
169
- allStatic = false;
170
- }
171
- }
172
- else {
173
- allStatic = false;
174
- }
175
- }
176
- else if (t.isIdentifier(expr)) {
177
- const obj = localCreateStyles[expr.value];
178
- if (obj) {
179
- Object.assign(merged, obj);
180
- }
181
- else {
182
- allStatic = false;
183
- }
184
- }
185
- else {
186
- allStatic = false;
187
- }
188
- });
189
- if (allStatic && Object.keys(merged).length > 0) {
190
- extractOndemandStyles(merged, extractedSheets);
191
- const hash = genBase36Hash(merged, 1, 8);
192
- const records = getStyleRecords(hash, merged);
193
- records.forEach((r) => extractedSheets.push(r.sheet));
194
- replacements.push({
195
- start: node.span.start - ast.span.start,
196
- end: node.span.end - ast.span.start,
197
- content: JSON.stringify(records.map((r) => r.hash).join(' ')),
198
- });
139
+ }
140
+ else if ((propName === 'createTheme' || propName === 'createStatic') &&
141
+ (t.isObjectExpression(node.init.arguments[0].expression) ||
142
+ t.isStringLiteral(node.init.arguments[0].expression))) {
143
+ localCreateStyles[node.id.value] = {
144
+ name: node.id.value,
145
+ type: 'constant',
146
+ obj: {},
147
+ hashMap: {},
148
+ hasDynamicAccess: false,
149
+ isExported,
150
+ initSpan: {
151
+ start: node.init.span.start - ast.span.start,
152
+ end: node.init.span.end - ast.span.start,
153
+ },
154
+ declSpan: {
155
+ start: declSpan.start - ast.span.start,
156
+ end: declSpan.end - ast.span.start,
157
+ },
158
+ };
159
+ }
160
+ }
161
+ };
162
+ traverse(ast, {
163
+ ExportDeclaration({ node }) {
164
+ if (t.isVariableDeclaration(node.declaration)) {
165
+ processedDecls.add(node.declaration);
166
+ node.declaration.declarations.forEach((decl) => {
167
+ registerStyle(decl, node.span, true);
168
+ });
169
+ }
170
+ },
171
+ VariableDeclaration({ node }) {
172
+ if (processedDecls.has(node))
173
+ return;
174
+ node.declarations.forEach((decl) => {
175
+ registerStyle(decl, node.span, false);
176
+ });
177
+ },
178
+ MemberExpression({ node }) {
179
+ if (t.isIdentifier(node.object)) {
180
+ const styleInfo = localCreateStyles[node.object.value];
181
+ if (styleInfo) {
182
+ if (t.isIdentifier(node.property)) {
183
+ const hash = styleInfo.hashMap[node.property.value];
184
+ if (!hash && styleInfo.type !== 'constant') {
185
+ styleInfo.hasDynamicAccess = true;
199
186
  }
200
187
  }
201
- else if (callee.property.value === 'keyframes' &&
202
- args.length > 0 &&
203
- t.isObjectExpression(args[0].expression)) {
204
- const obj = objectExpressionToObject(args[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
205
- const hash = genBase36Hash(obj, 1, 8);
206
- tables.keyframesObjectTable[hash] = obj;
207
- replacements.push({
208
- start: node.span.start - ast.span.start,
209
- end: node.span.end - ast.span.start,
210
- content: JSON.stringify(`kf-${hash}`),
211
- });
188
+ else {
189
+ styleInfo.hasDynamicAccess = true;
212
190
  }
213
- else if (callee.property.value === 'viewTransition' &&
214
- args.length > 0 &&
215
- t.isObjectExpression(args[0].expression)) {
216
- const obj = objectExpressionToObject(args[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
217
- const hash = genBase36Hash(obj, 1, 8);
218
- tables.viewTransitionObjectTable[hash] = obj;
191
+ }
192
+ }
193
+ },
194
+ CallExpression({ node }) {
195
+ const callee = node.callee;
196
+ if (t.isMemberExpression(callee) &&
197
+ t.isIdentifier(callee.object, { name: 'css' }) &&
198
+ t.isIdentifier(callee.property)) {
199
+ const propName = callee.property.value;
200
+ const args = node.arguments;
201
+ if (propName === 'keyframes' &&
202
+ args.length > 0 &&
203
+ t.isObjectExpression(args[0].expression)) {
204
+ const obj = objectExpressionToObject(args[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
205
+ const hash = genBase36Hash(obj, 1, 8);
206
+ tables.keyframesObjectTable[hash] = obj;
207
+ replacements.push({
208
+ start: node.span.start - ast.span.start,
209
+ end: node.span.end - ast.span.start,
210
+ content: JSON.stringify(`kf-${hash}`),
211
+ });
212
+ }
213
+ else if (propName === 'viewTransition' &&
214
+ args.length > 0 &&
215
+ t.isObjectExpression(args[0].expression)) {
216
+ const obj = objectExpressionToObject(args[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
217
+ const hash = genBase36Hash(obj, 1, 8);
218
+ tables.viewTransitionObjectTable[hash] = obj;
219
+ replacements.push({
220
+ start: node.span.start - ast.span.start,
221
+ end: node.span.end - ast.span.start,
222
+ content: JSON.stringify(`vt-${hash}`),
223
+ });
224
+ }
225
+ else if (propName === 'createTheme' &&
226
+ args.length > 0 &&
227
+ t.isObjectExpression(args[0].expression)) {
228
+ const obj = objectExpressionToObject(args[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
229
+ const hash = genBase36Hash(obj, 1, 8);
230
+ tables.createThemeObjectTable[hash] = obj;
231
+ }
232
+ }
233
+ },
234
+ });
235
+ traverse(ast, {
236
+ MemberExpression({ node }) {
237
+ if (excludedSpans.has(node.span.start))
238
+ return;
239
+ if (t.isIdentifier(node.object) && t.isIdentifier(node.property)) {
240
+ const styleInfo = localCreateStyles[node.object.value];
241
+ if (styleInfo && !styleInfo.hasDynamicAccess) {
242
+ const atomMap = styleInfo.hashMap[node.property.value];
243
+ if (atomMap) {
244
+ const combinedHash = Object.values(atomMap).join(' ');
219
245
  replacements.push({
220
246
  start: node.span.start - ast.span.start,
221
247
  end: node.span.end - ast.span.start,
222
- content: JSON.stringify(`vt-${hash}`),
248
+ content: JSON.stringify(combinedHash),
223
249
  });
224
250
  }
225
- else if (callee.property.value === 'createTheme' &&
226
- args.length > 0 &&
227
- t.isObjectExpression(args[0].expression)) {
228
- const obj = objectExpressionToObject(args[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
229
- const hash = genBase36Hash(obj, 1, 8);
230
- tables.createThemeObjectTable[hash] = obj;
231
- replacements.push({
232
- start: node.span.start - ast.span.start,
233
- end: node.span.end - ast.span.start,
234
- content: JSON.stringify(''),
235
- });
251
+ }
252
+ }
253
+ },
254
+ Identifier({ node }) {
255
+ if (excludedSpans.has(node.span.start))
256
+ return;
257
+ if (idSpans.has(node.span.start))
258
+ return;
259
+ const styleInfo = localCreateStyles[node.value];
260
+ if (styleInfo && !styleInfo.hasDynamicAccess) {
261
+ const fullHashMap = {};
262
+ Object.entries(styleInfo.hashMap).forEach(([key, atomMap]) => {
263
+ fullHashMap[key] = Object.values(atomMap).join(' ');
264
+ });
265
+ replacements.push({
266
+ start: node.span.start - ast.span.start,
267
+ end: node.span.end - ast.span.start,
268
+ content: JSON.stringify(fullHashMap),
269
+ });
270
+ }
271
+ },
272
+ CallExpression({ node }) {
273
+ const callee = node.callee;
274
+ if (t.isMemberExpression(callee) &&
275
+ t.isIdentifier(callee.object, { name: 'css' }) &&
276
+ t.isIdentifier(callee.property, { name: 'props' })) {
277
+ const args = node.arguments;
278
+ const checkStatic = (expr) => {
279
+ if (t.isObjectExpression(expr) ||
280
+ t.isStringLiteral(expr) ||
281
+ t.isNumericLiteral(expr) ||
282
+ t.isBooleanLiteral(expr) ||
283
+ t.isNullLiteral(expr))
284
+ return true;
285
+ if (t.isMemberExpression(expr) &&
286
+ t.isIdentifier(expr.object) &&
287
+ t.isIdentifier(expr.property)) {
288
+ const styleInfo = localCreateStyles[expr.object.value];
289
+ return !!(styleInfo &&
290
+ !styleInfo.hasDynamicAccess &&
291
+ styleInfo.hashMap[expr.property.value]);
236
292
  }
237
- else if (callee.property.value === 'createStatic' &&
238
- args.length > 0 &&
239
- t.isStringLiteral(args[0].expression)) {
293
+ if (t.isIdentifier(expr)) {
294
+ const styleInfo = localCreateStyles[expr.value];
295
+ return !!(styleInfo && !styleInfo.hasDynamicAccess);
296
+ }
297
+ return false;
298
+ };
299
+ const allStatic = args.every((arg) => checkStatic(arg.expression));
300
+ if (allStatic) {
301
+ const merged = {};
302
+ args.forEach((arg) => {
303
+ const expr = arg.expression;
304
+ if (t.isObjectExpression(expr)) {
305
+ excludedSpans.add(expr.span.start);
306
+ const obj = objectExpressionToObject(expr, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
307
+ obj && Object.assign(merged, obj);
308
+ }
309
+ else if (t.isMemberExpression(expr) &&
310
+ t.isIdentifier(expr.object) &&
311
+ t.isIdentifier(expr.property)) {
312
+ excludedSpans.add(expr.span.start);
313
+ const styleInfo = localCreateStyles[expr.object.value];
314
+ if (styleInfo) {
315
+ Object.assign(merged, styleInfo.obj[expr.property.value]);
316
+ }
317
+ }
318
+ else if (t.isIdentifier(expr)) {
319
+ excludedSpans.add(expr.span.start);
320
+ const styleInfo = localCreateStyles[expr.value];
321
+ if (styleInfo) {
322
+ Object.assign(merged, styleInfo.obj);
323
+ }
324
+ }
325
+ });
326
+ if (Object.keys(merged).length > 0) {
327
+ extractOndemandStyles(merged, extractedSheets);
328
+ const hash = genBase36Hash(merged, 1, 8);
329
+ const records = getStyleRecords(hash, merged, 2);
330
+ records.forEach((r) => extractedSheets.push(r.sheet));
331
+ const resultHash = records
332
+ .map((r) => r.hash)
333
+ .join(' ');
240
334
  replacements.push({
241
335
  start: node.span.start - ast.span.start,
242
336
  end: node.span.end - ast.span.start,
243
- content: JSON.stringify(''),
337
+ content: JSON.stringify(resultHash),
244
338
  });
245
339
  }
246
340
  }
247
- },
248
- });
249
- }
341
+ else {
342
+ const processExpr = (expr) => {
343
+ if (t.isMemberExpression(expr) &&
344
+ t.isIdentifier(expr.object) &&
345
+ t.isIdentifier(expr.property)) {
346
+ const info = localCreateStyles[expr.object.value];
347
+ if (info) {
348
+ const atomMap = info.hashMap[expr.property.value];
349
+ if (atomMap) {
350
+ excludedSpans.add(expr.span.start);
351
+ replacements.push({
352
+ start: expr.span.start - ast.span.start,
353
+ end: expr.span.end - ast.span.start,
354
+ content: JSON.stringify(atomMap),
355
+ });
356
+ }
357
+ }
358
+ }
359
+ else if (t.isIdentifier(expr)) {
360
+ const info = localCreateStyles[expr.value];
361
+ if (info) {
362
+ excludedSpans.add(expr.span.start);
363
+ replacements.push({
364
+ start: expr.span.start - ast.span.start,
365
+ end: expr.span.end - ast.span.start,
366
+ content: JSON.stringify(info.hashMap),
367
+ });
368
+ }
369
+ }
370
+ else if (t.isConditionalExpression(expr)) {
371
+ processExpr(expr.consequent);
372
+ processExpr(expr.alternate);
373
+ }
374
+ else if (t.isBinaryExpression(expr) &&
375
+ (expr.operator === '&&' ||
376
+ expr.operator === '||' ||
377
+ expr.operator === '??')) {
378
+ processExpr(expr.left);
379
+ processExpr(expr.right);
380
+ }
381
+ };
382
+ args.forEach((arg) => processExpr(arg.expression));
383
+ }
384
+ }
385
+ },
386
+ });
387
+ Object.values(localCreateStyles).forEach((info) => {
388
+ if (info.isExported) {
389
+ const content = isTSFile || info.hasDynamicAccess
390
+ ? JSON.stringify(info.hashMap)
391
+ : JSON.stringify('');
392
+ replacements.push({
393
+ start: info.initSpan.start,
394
+ end: info.initSpan.end,
395
+ content,
396
+ });
397
+ }
398
+ else {
399
+ if (info.hasDynamicAccess) {
400
+ replacements.push({
401
+ start: info.initSpan.start,
402
+ end: info.initSpan.end,
403
+ content: JSON.stringify(info.hashMap),
404
+ });
405
+ }
406
+ else {
407
+ replacements.push({
408
+ start: info.declSpan.start,
409
+ end: info.declSpan.end,
410
+ content: '',
411
+ });
412
+ }
413
+ }
414
+ });
250
415
  const buffer = Buffer.from(source);
251
416
  let offset = 0;
252
417
  const parts = [];
253
418
  replacements
254
- .sort((a, b) => a.start - b.start)
419
+ .sort((a, b) => a.start - b.start || b.end - a.end)
255
420
  .forEach((r) => {
421
+ if (r.start < offset)
422
+ return;
256
423
  parts.push(buffer.subarray(offset, r.start));
257
424
  parts.push(Buffer.from(r.content));
258
425
  offset = r.end;
@@ -293,17 +460,7 @@ export function plumeria(options = {}) {
293
460
  },
294
461
  };
295
462
  }
296
- function getScriptContents(code, id) {
297
- if (id.endsWith('.vue') || id.endsWith('.svelte')) {
298
- const matches = code.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g);
299
- return Array.from(matches).map((match) => match[1]);
300
- }
301
- return [code];
302
- }
303
- function injectImport(code, id, importPath) {
463
+ function injectImport(code, _id, importPath) {
304
464
  const importStmt = `\nimport ${JSON.stringify(importPath)};`;
305
- if (id.endsWith('.vue') || id.endsWith('.svelte')) {
306
- return code.replace(/(<script[^>]*>)([\s\S]*?)(<\/script>)/, (_match, open, content, close) => `${open}${content}${importStmt}\n${close}`);
307
- }
308
465
  return `${code}${importStmt}`;
309
466
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/vite-plugin",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "description": "Plumeria Vite plugin",
6
6
  "author": "Refirst 11",
@@ -22,7 +22,7 @@
22
22
  "dist/"
23
23
  ],
24
24
  "dependencies": {
25
- "@plumeria/utils": "^3.0.0"
25
+ "@plumeria/utils": "^3.1.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@swc/core": "1.15.2",