unframer 2.9.2 → 2.10.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/exporter.d.ts.map +1 -1
- package/dist/exporter.js +74 -85
- package/dist/exporter.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -1
- package/dist/utils.js.map +1 -1
- package/esm/cli.d.ts.map +1 -1
- package/esm/cli.js +4 -0
- package/esm/cli.js.map +1 -1
- package/esm/exporter.d.ts.map +1 -1
- package/esm/exporter.js +75 -86
- package/esm/exporter.js.map +1 -1
- package/esm/utils.d.ts +1 -0
- package/esm/utils.d.ts.map +1 -1
- package/esm/utils.js +2 -1
- package/esm/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.tsx +4 -0
- package/src/exporter.ts +86 -104
- package/src/utils.ts +2 -1
package/src/exporter.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { build, BuildResult } from 'esbuild'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
babelPluginDeduplicateImports,
|
|
5
|
-
babelPluginJsxTransform,
|
|
6
|
-
} from './babel-plugin-imports.js'
|
|
7
|
-
|
|
8
|
-
import { Config } from './cli'
|
|
9
3
|
import url from 'url'
|
|
4
|
+
import { Config } from './cli'
|
|
10
5
|
|
|
11
6
|
import { Sema } from 'async-sema'
|
|
12
7
|
import dprint from 'dprint-node'
|
|
@@ -14,11 +9,10 @@ import dprint from 'dprint-node'
|
|
|
14
9
|
import { nodeModulesPolyfillPlugin } from 'esbuild-plugins-node-modules-polyfill'
|
|
15
10
|
|
|
16
11
|
import { exec } from 'child_process'
|
|
17
|
-
import dedent from 'string-dedent'
|
|
18
12
|
import fs from 'fs'
|
|
19
13
|
import path from 'path'
|
|
14
|
+
import dedent from 'string-dedent'
|
|
20
15
|
import {
|
|
21
|
-
BreakpointSizes,
|
|
22
16
|
ComponentFontBundle,
|
|
23
17
|
breakpointsStyles,
|
|
24
18
|
getFontsStyles,
|
|
@@ -38,7 +32,6 @@ import {
|
|
|
38
32
|
combinedCSSRules,
|
|
39
33
|
} from './framer.js'
|
|
40
34
|
import { logger, spinner, terminalMarkdown } from './utils.js'
|
|
41
|
-
import { transform } from '@babel/core'
|
|
42
35
|
|
|
43
36
|
function validateUrl(url: string) {
|
|
44
37
|
try {
|
|
@@ -66,7 +59,7 @@ export async function bundle({
|
|
|
66
59
|
watch?: boolean
|
|
67
60
|
signal?: AbortSignal
|
|
68
61
|
}) {
|
|
69
|
-
const { components, breakpoints, tokens,
|
|
62
|
+
const { components, breakpoints, tokens, framerWebPages } = config
|
|
70
63
|
out ||= path.resolve(process.cwd(), 'example')
|
|
71
64
|
out = path.resolve(out)
|
|
72
65
|
try {
|
|
@@ -74,10 +67,7 @@ export async function bundle({
|
|
|
74
67
|
} catch (e) {}
|
|
75
68
|
|
|
76
69
|
spinner.start()
|
|
77
|
-
const
|
|
78
|
-
// entryPoints: {
|
|
79
|
-
// index: url,
|
|
80
|
-
// },
|
|
70
|
+
const buildResult = await build({
|
|
81
71
|
absWorkingDir: out,
|
|
82
72
|
entryPoints: Object.keys(components).map((name) => {
|
|
83
73
|
const url = components[name]
|
|
@@ -98,7 +88,6 @@ export async function bundle({
|
|
|
98
88
|
|
|
99
89
|
treeShaking: true,
|
|
100
90
|
splitting: true,
|
|
101
|
-
// splitting: true,
|
|
102
91
|
logLevel: 'error',
|
|
103
92
|
|
|
104
93
|
pure: ['addPropertyControls'],
|
|
@@ -190,23 +179,19 @@ export async function bundle({
|
|
|
190
179
|
],
|
|
191
180
|
write: false,
|
|
192
181
|
|
|
193
|
-
// outfile: 'dist/example.js',
|
|
194
182
|
outdir: out,
|
|
195
|
-
// outfile: path.resolve(cwd, sourcefile),
|
|
196
183
|
})
|
|
197
184
|
const doNotEditComment = `/* This file was generated by Unframer for Framer project ${
|
|
198
185
|
config.projectId || ''
|
|
199
186
|
} "${config.projectName}", do not edit manually */\n`
|
|
200
187
|
async function rebuild() {
|
|
201
188
|
const prevFiles = recursiveReaddir(out)
|
|
202
|
-
const result = await buildContext.rebuild()
|
|
203
189
|
|
|
204
|
-
for (let file of
|
|
190
|
+
for (let file of buildResult.outputFiles!) {
|
|
205
191
|
const resultPathAbs = path.resolve(out, file.path)
|
|
206
192
|
const existing = await fs.promises
|
|
207
193
|
.readFile(file.path, 'utf-8')
|
|
208
194
|
.catch(() => null)
|
|
209
|
-
|
|
210
195
|
// let res = transform(file.text || '', {
|
|
211
196
|
// babelrc: false,
|
|
212
197
|
// sourceType: 'module',
|
|
@@ -220,6 +205,7 @@ export async function bundle({
|
|
|
220
205
|
// sourceMaps: false,
|
|
221
206
|
// })
|
|
222
207
|
// let inputCode = res!.code!
|
|
208
|
+
|
|
223
209
|
let inputCode = file.text
|
|
224
210
|
|
|
225
211
|
let codeNew =
|
|
@@ -265,14 +251,14 @@ export async function bundle({
|
|
|
265
251
|
JSON.stringify({ type: 'module' }),
|
|
266
252
|
'utf-8',
|
|
267
253
|
)
|
|
268
|
-
if (!
|
|
254
|
+
if (!buildResult?.outputFiles) {
|
|
269
255
|
throw new Error('Failed to generate result')
|
|
270
256
|
}
|
|
271
257
|
const sema = new Sema(5)
|
|
272
258
|
spinner.start('Extracting types')
|
|
273
259
|
logger.log(`using node path`, nodePath)
|
|
274
260
|
const propControlsData = await Promise.all(
|
|
275
|
-
|
|
261
|
+
buildResult?.outputFiles.map(async (file) => {
|
|
276
262
|
try {
|
|
277
263
|
await sema.acquire()
|
|
278
264
|
const name = path
|
|
@@ -301,15 +287,12 @@ export async function bundle({
|
|
|
301
287
|
fileName: name,
|
|
302
288
|
config,
|
|
303
289
|
})
|
|
304
|
-
// name = 'framer-' + name
|
|
305
|
-
// logger.log('name', name)
|
|
306
290
|
fs.mkdirSync(out, { recursive: true })
|
|
307
291
|
fs.writeFileSync(path.resolve(out, `${name}.d.ts`), types)
|
|
308
292
|
return {
|
|
309
293
|
propertyControls,
|
|
310
294
|
fonts,
|
|
311
295
|
name,
|
|
312
|
-
// componentPath: file.path,
|
|
313
296
|
}
|
|
314
297
|
} finally {
|
|
315
298
|
sema.release()
|
|
@@ -336,7 +319,7 @@ export async function bundle({
|
|
|
336
319
|
.split('\n')
|
|
337
320
|
.forEach((x) => logger.log(x))
|
|
338
321
|
|
|
339
|
-
const outFiles =
|
|
322
|
+
const outFiles = buildResult.outputFiles
|
|
340
323
|
.map((x) => path.resolve(out, x.path))
|
|
341
324
|
.concat([
|
|
342
325
|
path.resolve(out, 'meta.json'),
|
|
@@ -344,7 +327,7 @@ export async function bundle({
|
|
|
344
327
|
path.resolve(out, 'styles.css'),
|
|
345
328
|
])
|
|
346
329
|
.concat(
|
|
347
|
-
|
|
330
|
+
buildResult.outputFiles.map((x) =>
|
|
348
331
|
path.resolve(out, x.path.replace('.js', '.d.ts')),
|
|
349
332
|
),
|
|
350
333
|
)
|
|
@@ -356,14 +339,13 @@ export async function bundle({
|
|
|
356
339
|
|
|
357
340
|
fs.writeFileSync(
|
|
358
341
|
path.resolve(out, 'meta.json'),
|
|
359
|
-
JSON.stringify(
|
|
342
|
+
JSON.stringify(buildResult.metafile, null, 2),
|
|
360
343
|
'utf-8',
|
|
361
344
|
)
|
|
362
345
|
|
|
363
346
|
if (signal?.aborted) {
|
|
364
347
|
throw new Error('aborted')
|
|
365
348
|
}
|
|
366
|
-
// logger.log('result', result)
|
|
367
349
|
|
|
368
350
|
if (watch) {
|
|
369
351
|
logger.log('waiting for components or config changes')
|
|
@@ -372,7 +354,7 @@ export async function bundle({
|
|
|
372
354
|
const tokensCss =
|
|
373
355
|
"/* This css file contains your color variables, sometimes these get desynced when updated in Framer so it's good that you copy and paste this snippet into your app css */\n" +
|
|
374
356
|
'/* Bug: https://www.framer.community/c/bugs/color-style-unlinks-when-copying-component-between-projects-resulting-in-potential-value-discrepancy */\n' +
|
|
375
|
-
getTokensCss({ out, result })
|
|
357
|
+
getTokensCss({ out, result: buildResult })
|
|
376
358
|
fs.writeFileSync(
|
|
377
359
|
path.resolve(out, 'tokens.css'),
|
|
378
360
|
tokensCss,
|
|
@@ -398,82 +380,83 @@ export async function bundle({
|
|
|
398
380
|
return res
|
|
399
381
|
}
|
|
400
382
|
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
`No example component found with breakpoints, using random example`,
|
|
425
|
-
)
|
|
426
|
-
// Create an example component if none found with breakpoints
|
|
427
|
-
exampleComponent = {
|
|
428
|
-
path: 'hero',
|
|
429
|
-
componentName: 'HeroFramerComponent',
|
|
430
|
-
propertyControls: {
|
|
431
|
-
variant: {
|
|
432
|
-
type: ControlType.Enum,
|
|
433
|
-
options: ['Desktop', 'Tablet', 'Mobile'],
|
|
434
|
-
optionTitles: ['Desktop', 'Tablet', 'Mobile'],
|
|
435
|
-
},
|
|
436
|
-
} as any,
|
|
437
|
-
name: 'Hero',
|
|
438
|
-
url: '',
|
|
439
|
-
}
|
|
440
|
-
if (!exampleComponent) {
|
|
441
|
-
return
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
const variants = getVariantsFromPropControls(
|
|
445
|
-
exampleComponent?.propertyControls,
|
|
446
|
-
)
|
|
447
|
-
const outDir = path.posix.relative(process.cwd(), out)
|
|
383
|
+
if (watch) {
|
|
384
|
+
throw new Error('--watch is not supported yet')
|
|
385
|
+
}
|
|
386
|
+
const result = await rebuild()
|
|
387
|
+
console.log()
|
|
388
|
+
console.log()
|
|
389
|
+
|
|
390
|
+
let exampleComponent = result?.components?.sort((a, b) => {
|
|
391
|
+
const aVariants = getVariantsFromPropControls(a.propertyControls)
|
|
392
|
+
const bVariants = getVariantsFromPropControls(b.propertyControls)
|
|
393
|
+
const aHasBreakpoints = (aVariants?.breakpoints?.length || 0) >= 2
|
|
394
|
+
const bHasBreakpoints = (bVariants?.breakpoints?.length || 0) >= 2
|
|
395
|
+
|
|
396
|
+
// Sort components with breakpoints first
|
|
397
|
+
if (aHasBreakpoints && !bHasBreakpoints) return -1
|
|
398
|
+
if (!aHasBreakpoints && bHasBreakpoints) return 1
|
|
399
|
+
|
|
400
|
+
// Within each group, prefer components with example properties
|
|
401
|
+
const aProp = findExampleProperty(a.propertyControls)
|
|
402
|
+
const bProp = findExampleProperty(b.propertyControls)
|
|
403
|
+
return (bProp ? 1 : 0) - (aProp ? 1 : 0)
|
|
404
|
+
})?.[0]
|
|
405
|
+
if (!exampleComponent) {
|
|
448
406
|
logger.log(
|
|
449
|
-
|
|
450
|
-
exampleComponent?.propertyControls,
|
|
407
|
+
`No example component found with breakpoints, using random example`,
|
|
451
408
|
)
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
'
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
409
|
+
// Create an example component if none found with breakpoints
|
|
410
|
+
exampleComponent = {
|
|
411
|
+
path: 'hero',
|
|
412
|
+
componentName: 'HeroFramerComponent',
|
|
413
|
+
propertyControls: {
|
|
414
|
+
variant: {
|
|
415
|
+
type: ControlType.Enum,
|
|
416
|
+
options: ['Desktop', 'Tablet', 'Mobile'],
|
|
417
|
+
optionTitles: ['Desktop', 'Tablet', 'Mobile'],
|
|
418
|
+
},
|
|
419
|
+
} as any,
|
|
420
|
+
name: 'Hero',
|
|
421
|
+
url: '',
|
|
422
|
+
}
|
|
423
|
+
if (!exampleComponent) {
|
|
424
|
+
return
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const variants = getVariantsFromPropControls(
|
|
428
|
+
exampleComponent?.propertyControls,
|
|
429
|
+
)
|
|
430
|
+
const outDirNice = path.posix.relative(process.cwd(), out)
|
|
431
|
+
logger.log(
|
|
432
|
+
'exampleComponent?.propertyControls',
|
|
433
|
+
exampleComponent?.propertyControls,
|
|
434
|
+
)
|
|
435
|
+
const prop =
|
|
436
|
+
findExampleProperty(exampleComponent?.propertyControls) ||
|
|
437
|
+
'exampleFramerVariable'
|
|
438
|
+
const responsiveComponent = (() => {
|
|
439
|
+
const breakpoints = variants?.breakpoints
|
|
440
|
+
if (!breakpoints?.length) {
|
|
441
|
+
return ''
|
|
442
|
+
}
|
|
443
|
+
const variantsExample = {
|
|
444
|
+
lg: breakpoints[1],
|
|
445
|
+
base: breakpoints[0],
|
|
446
|
+
}
|
|
464
447
|
|
|
465
|
-
|
|
448
|
+
return dedent`
|
|
466
449
|
<${exampleComponent?.componentName}.Responsive
|
|
467
450
|
${prop}='example'
|
|
468
451
|
variants={${JSON.stringify(variantsExample || {})}}
|
|
469
452
|
/>
|
|
470
453
|
`
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
454
|
+
})()
|
|
455
|
+
console.log(
|
|
456
|
+
terminalMarkdown(dedent`
|
|
474
457
|
# How to use the Framer components
|
|
475
458
|
|
|
476
|
-
Your components are exported to \`${
|
|
459
|
+
Your components are exported to \`${outDirNice}\` folder. Now please install the \`unframer\` runtime dependency:
|
|
477
460
|
|
|
478
461
|
\`\`\`sh
|
|
479
462
|
npm install unframer
|
|
@@ -484,10 +467,10 @@ export async function bundle({
|
|
|
484
467
|
You can use the components like this (try copy pasting the code below into your React app):
|
|
485
468
|
|
|
486
469
|
\`\`\`jsx
|
|
487
|
-
import './${
|
|
488
|
-
import ${exampleComponent?.componentName} from './${
|
|
489
|
-
|
|
490
|
-
|
|
470
|
+
import './${outDirNice}/styles.css'
|
|
471
|
+
import ${exampleComponent?.componentName} from './${outDirNice}/${
|
|
472
|
+
exampleComponent?.path
|
|
473
|
+
}'
|
|
491
474
|
|
|
492
475
|
export default function App() {
|
|
493
476
|
return (
|
|
@@ -512,9 +495,8 @@ export async function bundle({
|
|
|
512
495
|
Read more on GitHub: https://github.com/remorses/unframer
|
|
513
496
|
|
|
514
497
|
`),
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
498
|
+
)
|
|
499
|
+
return result
|
|
518
500
|
|
|
519
501
|
// // when user press ctrl+c dispose
|
|
520
502
|
// process.on('SIGINT', async () => {
|
package/src/utils.ts
CHANGED
|
@@ -17,8 +17,9 @@ const shouldDebugUnframer = !!process.env.DEBUG_UNFRAMER
|
|
|
17
17
|
|
|
18
18
|
const prefix = '[unframer]'
|
|
19
19
|
export const logger = {
|
|
20
|
+
debug: shouldDebugUnframer,
|
|
20
21
|
log(...args) {
|
|
21
|
-
if (!
|
|
22
|
+
if (!logger.debug) {
|
|
22
23
|
return
|
|
23
24
|
}
|
|
24
25
|
console.log(prefix, ...args)
|