@plumeria/vite-plugin 3.0.1 → 4.0.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 +327 -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,349 @@ 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
+ extractOndemandStyles(obj, extractedSheets);
220
+ extractOndemandStyles({ vt: `vt-${hash}` }, extractedSheets);
221
+ replacements.push({
222
+ start: node.span.start - ast.span.start,
223
+ end: node.span.end - ast.span.start,
224
+ content: JSON.stringify(`vt-${hash}`),
225
+ });
226
+ }
227
+ else if (propName === 'createTheme' &&
228
+ args.length > 0 &&
229
+ t.isObjectExpression(args[0].expression)) {
230
+ const obj = objectExpressionToObject(args[0].expression, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
231
+ const hash = genBase36Hash(obj, 1, 8);
232
+ tables.createThemeObjectTable[hash] = obj;
233
+ }
234
+ }
235
+ },
236
+ });
237
+ traverse(ast, {
238
+ MemberExpression({ node }) {
239
+ if (excludedSpans.has(node.span.start))
240
+ return;
241
+ if (t.isIdentifier(node.object) && t.isIdentifier(node.property)) {
242
+ const styleInfo = localCreateStyles[node.object.value];
243
+ if (styleInfo && !styleInfo.hasDynamicAccess) {
244
+ const atomMap = styleInfo.hashMap[node.property.value];
245
+ if (atomMap) {
246
+ const combinedHash = Object.values(atomMap).join(' ');
219
247
  replacements.push({
220
248
  start: node.span.start - ast.span.start,
221
249
  end: node.span.end - ast.span.start,
222
- content: JSON.stringify(`vt-${hash}`),
250
+ content: JSON.stringify(combinedHash),
223
251
  });
224
252
  }
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
- });
253
+ }
254
+ }
255
+ },
256
+ Identifier({ node }) {
257
+ if (excludedSpans.has(node.span.start))
258
+ return;
259
+ if (idSpans.has(node.span.start))
260
+ return;
261
+ const styleInfo = localCreateStyles[node.value];
262
+ if (styleInfo && !styleInfo.hasDynamicAccess) {
263
+ const fullHashMap = {};
264
+ Object.entries(styleInfo.hashMap).forEach(([key, atomMap]) => {
265
+ fullHashMap[key] = Object.values(atomMap).join(' ');
266
+ });
267
+ replacements.push({
268
+ start: node.span.start - ast.span.start,
269
+ end: node.span.end - ast.span.start,
270
+ content: JSON.stringify(fullHashMap),
271
+ });
272
+ }
273
+ },
274
+ CallExpression({ node }) {
275
+ const callee = node.callee;
276
+ if (t.isMemberExpression(callee) &&
277
+ t.isIdentifier(callee.object, { name: 'css' }) &&
278
+ t.isIdentifier(callee.property, { name: 'props' })) {
279
+ const args = node.arguments;
280
+ const checkStatic = (expr) => {
281
+ if (t.isObjectExpression(expr) ||
282
+ t.isStringLiteral(expr) ||
283
+ t.isNumericLiteral(expr) ||
284
+ t.isBooleanLiteral(expr) ||
285
+ t.isNullLiteral(expr))
286
+ return true;
287
+ if (t.isMemberExpression(expr) &&
288
+ t.isIdentifier(expr.object) &&
289
+ t.isIdentifier(expr.property)) {
290
+ const styleInfo = localCreateStyles[expr.object.value];
291
+ return !!(styleInfo &&
292
+ !styleInfo.hasDynamicAccess &&
293
+ styleInfo.hashMap[expr.property.value]);
236
294
  }
237
- else if (callee.property.value === 'createStatic' &&
238
- args.length > 0 &&
239
- t.isStringLiteral(args[0].expression)) {
295
+ if (t.isIdentifier(expr)) {
296
+ const styleInfo = localCreateStyles[expr.value];
297
+ return !!(styleInfo && !styleInfo.hasDynamicAccess);
298
+ }
299
+ return false;
300
+ };
301
+ const allStatic = args.every((arg) => checkStatic(arg.expression));
302
+ if (allStatic) {
303
+ const merged = {};
304
+ args.forEach((arg) => {
305
+ const expr = arg.expression;
306
+ if (t.isObjectExpression(expr)) {
307
+ excludedSpans.add(expr.span.start);
308
+ const obj = objectExpressionToObject(expr, tables.staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.themeTable);
309
+ obj && Object.assign(merged, obj);
310
+ }
311
+ else if (t.isMemberExpression(expr) &&
312
+ t.isIdentifier(expr.object) &&
313
+ t.isIdentifier(expr.property)) {
314
+ excludedSpans.add(expr.span.start);
315
+ const styleInfo = localCreateStyles[expr.object.value];
316
+ if (styleInfo) {
317
+ Object.assign(merged, styleInfo.obj[expr.property.value]);
318
+ }
319
+ }
320
+ else if (t.isIdentifier(expr)) {
321
+ excludedSpans.add(expr.span.start);
322
+ const styleInfo = localCreateStyles[expr.value];
323
+ if (styleInfo) {
324
+ Object.assign(merged, styleInfo.obj);
325
+ }
326
+ }
327
+ });
328
+ if (Object.keys(merged).length > 0) {
329
+ extractOndemandStyles(merged, extractedSheets);
330
+ const hash = genBase36Hash(merged, 1, 8);
331
+ const records = getStyleRecords(hash, merged, 2);
332
+ records.forEach((r) => extractedSheets.push(r.sheet));
333
+ const resultHash = records
334
+ .map((r) => r.hash)
335
+ .join(' ');
240
336
  replacements.push({
241
337
  start: node.span.start - ast.span.start,
242
338
  end: node.span.end - ast.span.start,
243
- content: JSON.stringify(''),
339
+ content: JSON.stringify(resultHash),
244
340
  });
245
341
  }
246
342
  }
247
- },
248
- });
249
- }
343
+ else {
344
+ const processExpr = (expr) => {
345
+ if (t.isMemberExpression(expr) &&
346
+ t.isIdentifier(expr.object) &&
347
+ t.isIdentifier(expr.property)) {
348
+ const info = localCreateStyles[expr.object.value];
349
+ if (info) {
350
+ const atomMap = info.hashMap[expr.property.value];
351
+ if (atomMap) {
352
+ excludedSpans.add(expr.span.start);
353
+ replacements.push({
354
+ start: expr.span.start - ast.span.start,
355
+ end: expr.span.end - ast.span.start,
356
+ content: JSON.stringify(atomMap),
357
+ });
358
+ }
359
+ }
360
+ }
361
+ else if (t.isIdentifier(expr)) {
362
+ const info = localCreateStyles[expr.value];
363
+ if (info) {
364
+ excludedSpans.add(expr.span.start);
365
+ replacements.push({
366
+ start: expr.span.start - ast.span.start,
367
+ end: expr.span.end - ast.span.start,
368
+ content: JSON.stringify(info.hashMap),
369
+ });
370
+ }
371
+ }
372
+ else if (t.isConditionalExpression(expr)) {
373
+ processExpr(expr.consequent);
374
+ processExpr(expr.alternate);
375
+ }
376
+ else if (t.isBinaryExpression(expr) &&
377
+ (expr.operator === '&&' ||
378
+ expr.operator === '||' ||
379
+ expr.operator === '??')) {
380
+ processExpr(expr.left);
381
+ processExpr(expr.right);
382
+ }
383
+ };
384
+ args.forEach((arg) => processExpr(arg.expression));
385
+ }
386
+ }
387
+ },
388
+ });
389
+ Object.values(localCreateStyles).forEach((info) => {
390
+ if (info.isExported) {
391
+ const content = isTSFile || info.hasDynamicAccess
392
+ ? JSON.stringify(info.hashMap)
393
+ : JSON.stringify('');
394
+ replacements.push({
395
+ start: info.initSpan.start,
396
+ end: info.initSpan.end,
397
+ content,
398
+ });
399
+ }
400
+ else {
401
+ if (info.hasDynamicAccess) {
402
+ replacements.push({
403
+ start: info.initSpan.start,
404
+ end: info.initSpan.end,
405
+ content: JSON.stringify(info.hashMap),
406
+ });
407
+ }
408
+ else {
409
+ replacements.push({
410
+ start: info.declSpan.start,
411
+ end: info.declSpan.end,
412
+ content: '',
413
+ });
414
+ }
415
+ }
416
+ });
250
417
  const buffer = Buffer.from(source);
251
418
  let offset = 0;
252
419
  const parts = [];
253
420
  replacements
254
- .sort((a, b) => a.start - b.start)
421
+ .sort((a, b) => a.start - b.start || b.end - a.end)
255
422
  .forEach((r) => {
423
+ if (r.start < offset)
424
+ return;
256
425
  parts.push(buffer.subarray(offset, r.start));
257
426
  parts.push(Buffer.from(r.content));
258
427
  offset = r.end;
@@ -293,17 +462,7 @@ export function plumeria(options = {}) {
293
462
  },
294
463
  };
295
464
  }
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) {
465
+ function injectImport(code, _id, importPath) {
304
466
  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
467
  return `${code}${importStmt}`;
309
468
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/vite-plugin",
3
- "version": "3.0.1",
3
+ "version": "4.0.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.1"
25
+ "@plumeria/utils": "^4.0.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@swc/core": "1.15.2",