unframer 2.9.2 → 2.10.1

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/src/exporter.ts CHANGED
@@ -1,12 +1,7 @@
1
- import { BuildResult, context } from 'esbuild'
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, outDir, framerWebPages } = config
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 buildContext = await context({
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 result.outputFiles!) {
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,18 +205,31 @@ export async function bundle({
220
205
  // sourceMaps: false,
221
206
  // })
222
207
  // let inputCode = res!.code!
223
- let inputCode = file.text
224
208
 
225
- let codeNew =
226
- `// @ts-nocheck\n` +
227
- `/* eslint-disable */\n` +
228
- doNotEditComment +
229
- dprint.format('file.jsx', inputCode, {
209
+ const twoMb = 2 * 1024 * 1024
210
+
211
+ let formatted = file.text
212
+ if (file.text.length < twoMb) {
213
+ formatted = dprint.format('file.jsx', file.text, {
230
214
  lineWidth: 140,
231
215
  quoteStyle: 'alwaysSingle',
232
216
  trailingCommas: 'always',
233
217
  semiColons: 'always',
234
218
  })
219
+ } else {
220
+ spinner.info(
221
+ `skipping formatting ${path.relative(
222
+ out,
223
+ file.path,
224
+ )}, too big`,
225
+ )
226
+ }
227
+
228
+ let codeNew =
229
+ `// @ts-nocheck\n` +
230
+ `/* eslint-disable */\n` +
231
+ doNotEditComment +
232
+ formatted
235
233
  if (framerWebPages?.length) {
236
234
  codeNew = replaceWebPageIds({
237
235
  code: codeNew,
@@ -265,14 +263,14 @@ export async function bundle({
265
263
  JSON.stringify({ type: 'module' }),
266
264
  'utf-8',
267
265
  )
268
- if (!result?.outputFiles) {
266
+ if (!buildResult?.outputFiles) {
269
267
  throw new Error('Failed to generate result')
270
268
  }
271
269
  const sema = new Sema(5)
272
270
  spinner.start('Extracting types')
273
271
  logger.log(`using node path`, nodePath)
274
272
  const propControlsData = await Promise.all(
275
- result?.outputFiles.map(async (file) => {
273
+ buildResult?.outputFiles.map(async (file) => {
276
274
  try {
277
275
  await sema.acquire()
278
276
  const name = path
@@ -301,15 +299,12 @@ export async function bundle({
301
299
  fileName: name,
302
300
  config,
303
301
  })
304
- // name = 'framer-' + name
305
- // logger.log('name', name)
306
302
  fs.mkdirSync(out, { recursive: true })
307
303
  fs.writeFileSync(path.resolve(out, `${name}.d.ts`), types)
308
304
  return {
309
305
  propertyControls,
310
306
  fonts,
311
307
  name,
312
- // componentPath: file.path,
313
308
  }
314
309
  } finally {
315
310
  sema.release()
@@ -336,7 +331,7 @@ export async function bundle({
336
331
  .split('\n')
337
332
  .forEach((x) => logger.log(x))
338
333
 
339
- const outFiles = result.outputFiles
334
+ const outFiles = buildResult.outputFiles
340
335
  .map((x) => path.resolve(out, x.path))
341
336
  .concat([
342
337
  path.resolve(out, 'meta.json'),
@@ -344,7 +339,7 @@ export async function bundle({
344
339
  path.resolve(out, 'styles.css'),
345
340
  ])
346
341
  .concat(
347
- result.outputFiles.map((x) =>
342
+ buildResult.outputFiles.map((x) =>
348
343
  path.resolve(out, x.path.replace('.js', '.d.ts')),
349
344
  ),
350
345
  )
@@ -356,14 +351,13 @@ export async function bundle({
356
351
 
357
352
  fs.writeFileSync(
358
353
  path.resolve(out, 'meta.json'),
359
- JSON.stringify(result.metafile, null, 2),
354
+ JSON.stringify(buildResult.metafile, null, 2),
360
355
  'utf-8',
361
356
  )
362
357
 
363
358
  if (signal?.aborted) {
364
359
  throw new Error('aborted')
365
360
  }
366
- // logger.log('result', result)
367
361
 
368
362
  if (watch) {
369
363
  logger.log('waiting for components or config changes')
@@ -372,7 +366,7 @@ export async function bundle({
372
366
  const tokensCss =
373
367
  "/* 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
368
  '/* 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 })
369
+ getTokensCss({ out, result: buildResult })
376
370
  fs.writeFileSync(
377
371
  path.resolve(out, 'tokens.css'),
378
372
  tokensCss,
@@ -398,82 +392,83 @@ export async function bundle({
398
392
  return res
399
393
  }
400
394
 
401
- if (!watch) {
402
- const result = await rebuild()
403
- await buildContext.dispose()
404
- console.log()
405
- console.log()
406
-
407
- let exampleComponent = result?.components?.sort((a, b) => {
408
- const aVariants = getVariantsFromPropControls(a.propertyControls)
409
- const bVariants = getVariantsFromPropControls(b.propertyControls)
410
- const aHasBreakpoints = (aVariants?.breakpoints?.length || 0) >= 2
411
- const bHasBreakpoints = (bVariants?.breakpoints?.length || 0) >= 2
412
-
413
- // Sort components with breakpoints first
414
- if (aHasBreakpoints && !bHasBreakpoints) return -1
415
- if (!aHasBreakpoints && bHasBreakpoints) return 1
416
-
417
- // Within each group, prefer components with example properties
418
- const aProp = findExampleProperty(a.propertyControls)
419
- const bProp = findExampleProperty(b.propertyControls)
420
- return (bProp ? 1 : 0) - (aProp ? 1 : 0)
421
- })?.[0]
422
- if (!exampleComponent) {
423
- logger.log(
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)
395
+ if (watch) {
396
+ throw new Error('--watch is not supported yet')
397
+ }
398
+ const result = await rebuild()
399
+ console.log()
400
+ console.log()
401
+
402
+ let exampleComponent = result?.components?.sort((a, b) => {
403
+ const aVariants = getVariantsFromPropControls(a.propertyControls)
404
+ const bVariants = getVariantsFromPropControls(b.propertyControls)
405
+ const aHasBreakpoints = (aVariants?.breakpoints?.length || 0) >= 2
406
+ const bHasBreakpoints = (bVariants?.breakpoints?.length || 0) >= 2
407
+
408
+ // Sort components with breakpoints first
409
+ if (aHasBreakpoints && !bHasBreakpoints) return -1
410
+ if (!aHasBreakpoints && bHasBreakpoints) return 1
411
+
412
+ // Within each group, prefer components with example properties
413
+ const aProp = findExampleProperty(a.propertyControls)
414
+ const bProp = findExampleProperty(b.propertyControls)
415
+ return (bProp ? 1 : 0) - (aProp ? 1 : 0)
416
+ })?.[0]
417
+ if (!exampleComponent) {
448
418
  logger.log(
449
- 'exampleComponent?.propertyControls',
450
- exampleComponent?.propertyControls,
419
+ `No example component found with breakpoints, using random example`,
451
420
  )
452
- const prop =
453
- findExampleProperty(exampleComponent?.propertyControls) ||
454
- 'exampleFramerVariable'
455
- const responsiveComponent = (() => {
456
- const breakpoints = variants?.breakpoints
457
- if (!breakpoints?.length) {
458
- return ''
459
- }
460
- const variantsExample = {
461
- lg: breakpoints[1],
462
- base: breakpoints[0],
463
- }
421
+ // Create an example component if none found with breakpoints
422
+ exampleComponent = {
423
+ path: 'hero',
424
+ componentName: 'HeroFramerComponent',
425
+ propertyControls: {
426
+ variant: {
427
+ type: ControlType.Enum,
428
+ options: ['Desktop', 'Tablet', 'Mobile'],
429
+ optionTitles: ['Desktop', 'Tablet', 'Mobile'],
430
+ },
431
+ } as any,
432
+ name: 'Hero',
433
+ url: '',
434
+ }
435
+ if (!exampleComponent) {
436
+ return
437
+ }
438
+ }
439
+ const variants = getVariantsFromPropControls(
440
+ exampleComponent?.propertyControls,
441
+ )
442
+ const outDirNice = path.posix.relative(process.cwd(), out)
443
+ logger.log(
444
+ 'exampleComponent?.propertyControls',
445
+ exampleComponent?.propertyControls,
446
+ )
447
+ const prop =
448
+ findExampleProperty(exampleComponent?.propertyControls) ||
449
+ 'exampleFramerVariable'
450
+ const responsiveComponent = (() => {
451
+ const breakpoints = variants?.breakpoints
452
+ if (!breakpoints?.length) {
453
+ return ''
454
+ }
455
+ const variantsExample = {
456
+ lg: breakpoints[1],
457
+ base: breakpoints[0],
458
+ }
464
459
 
465
- return dedent`
460
+ return dedent`
466
461
  <${exampleComponent?.componentName}.Responsive
467
462
  ${prop}='example'
468
463
  variants={${JSON.stringify(variantsExample || {})}}
469
464
  />
470
465
  `
471
- })()
472
- console.log(
473
- terminalMarkdown(dedent`
466
+ })()
467
+ console.log(
468
+ terminalMarkdown(dedent`
474
469
  # How to use the Framer components
475
470
 
476
- Your components are exported to \`${outDir}\` folder. Now please install the \`unframer\` runtime dependency:
471
+ Your components are exported to \`${outDirNice}\` folder. Now please install the \`unframer\` runtime dependency:
477
472
 
478
473
  \`\`\`sh
479
474
  npm install unframer
@@ -484,10 +479,10 @@ export async function bundle({
484
479
  You can use the components like this (try copy pasting the code below into your React app):
485
480
 
486
481
  \`\`\`jsx
487
- import './${outDir}/styles.css'
488
- import ${exampleComponent?.componentName} from './${outDir}/${
489
- exampleComponent?.path
490
- }'
482
+ import './${outDirNice}/styles.css'
483
+ import ${exampleComponent?.componentName} from './${outDirNice}/${
484
+ exampleComponent?.path
485
+ }'
491
486
 
492
487
  export default function App() {
493
488
  return (
@@ -512,9 +507,8 @@ export async function bundle({
512
507
  Read more on GitHub: https://github.com/remorses/unframer
513
508
 
514
509
  `),
515
- )
516
- return result
517
- }
510
+ )
511
+ return result
518
512
 
519
513
  // // when user press ctrl+c dispose
520
514
  // 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 (!shouldDebugUnframer) {
22
+ if (!logger.debug) {
22
23
  return
23
24
  }
24
25
  console.log(prefix, ...args)