Skip to content

Commit

Permalink
add --external
Browse files Browse the repository at this point in the history
  • Loading branch information
remorses committed Jan 17, 2025
1 parent 966eb6d commit e1eb86f
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 31 deletions.
27 changes: 27 additions & 0 deletions remix-app/app/routes/workbase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client'

import '../../workbase-bugs/styles.css'

import { useLoaderData } from '@remix-run/react'
import TrainingsBreadcrumbsFramerComponent from 'workbase-bugs/trainings-breadcrumbs'
import TrainingsCollectionFramerComponent from 'workbase-bugs/trainings-collection'
import TrainingsHeroFramerComponent from 'workbase-bugs/trainings-hero'
import TrainingsLessonFramerComponent from 'workbase-bugs/trainings-lesson'

export function loader() {
return {}
}

export default function Home() {
const {} = useLoaderData() as any
return (
<div className='dark'>
<div className=' dark:bg-gray-900 '>
<TrainingsHeroFramerComponent />
<TrainingsBreadcrumbsFramerComponent />
<TrainingsLessonFramerComponent variant='Small' />
<TrainingsCollectionFramerComponent />
</div>
</div>
)
}
20 changes: 19 additions & 1 deletion unframer/src/cli.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,23 @@ let defaultOutDir = 'framer'

cli.command('[projectId]', 'Run unframer with optional project ID')
.option('--outDir <dir>', 'Output directory', { default: defaultOutDir })
.option(
'--external [package]',
'Make some package external, do not pass a package name to make all packages external',
{
default: false,
},
)
.option('--watch', 'Watch for changes and rebuild', { default: false })
.option('--debug', 'Enable debug logging', { default: false })
.action(async function main(projectId, options) {
const external_ = options.external
const allExternal = external_ === true
const externalPackages: string[] = Array.isArray(external_)
? external_.filter((x) => x.trim())
: typeof external_ === 'string'
? [external_]
: []
try {
if (options.debug) {
logger.debug = true
Expand Down Expand Up @@ -55,6 +69,8 @@ cli.command('[projectId]', 'Run unframer with optional project ID')
const { rebuild, buildContext } = await bundle({
config: {
outDir,
externalPackages,
allExternal,
projectId: data?.project?.projectId,
projectName,
fullFramerProjectId:
Expand Down Expand Up @@ -133,7 +149,7 @@ cli.command('[projectId]', 'Run unframer with optional project ID')

setMaxListeners(0, controller.signal)
const { buildContext } = await bundle({
config,
config: { ...config, externalPackages, allExternal },
watch: false,
signal: controller.signal,
cwd: path.resolve(process.cwd(), config.outDir || 'framer'),
Expand Down Expand Up @@ -216,6 +232,8 @@ export type Config = {
components: {
[name: string]: string
}
externalPackages?: string[]
allExternal?: boolean
projectId?: string
fullFramerProjectId?: string
projectName?: string
Expand Down
49 changes: 44 additions & 5 deletions unframer/src/esbuild.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { logger } from './utils'
import { createSpinner } from 'nanospinner'

import { Plugin, transform } from 'esbuild'
import { Plugin, transform, type OnResolveArgs } from 'esbuild'
import { cwd } from 'process'
import { resolvePackage } from './exporter'

export const externalPackages = [
export const defaultExternalPackages = [
'react',
'react-dom',
'framer',
Expand All @@ -21,7 +23,8 @@ export const replaceWebPageIds = ({
code: string
}) => {
// Match webPageId pattern with optional trailing comma
const pattern = /{[\s\n]*webPageId[\s\n]*:[\s\n]*(['"])(.*?)\1[\s\n]*,?[\s\n]*}/g
const pattern =
/{[\s\n]*webPageId[\s\n]*:[\s\n]*(['"])(.*?)\1[\s\n]*,?[\s\n]*}/g

return code.replace(pattern, (match, quote, id) => {
const path = elements.find((e) => e.webPageId === id)?.path
Expand All @@ -36,15 +39,20 @@ export const replaceWebPageIds = ({

export function esbuildPluginBundleDependencies({
signal = undefined as AbortSignal | undefined,
externalPackages = [] as string[],
externalizeNpm = false,
outDir,
}) {
externalPackages = [...defaultExternalPackages, ...externalPackages]
// console.log(externalPackages)
const codeCache = new Map()
const spinner = createSpinner('Fetching Framer Components Modules')
spinner.start()

const plugin: Plugin = {
name: 'esbuild-plugin',
setup(build) {
const namespace = 'https '
const namespace = '/'
build.onResolve({ filter: /^https?:\/\// }, (args) => {
const url = new URL(args.path)
return {
Expand All @@ -54,7 +62,7 @@ export function esbuildPluginBundleDependencies({
namespace,
}
})
const resolveDep = (args) => {
const resolveDep = async (args: OnResolveArgs) => {
if (signal?.aborted) {
throw new Error('aborted')
}
Expand Down Expand Up @@ -83,6 +91,16 @@ export function esbuildPluginBundleDependencies({
(x) => x === args.path || args.path.startsWith(x + '/'),
)
) {
const pkg = getPackageName(args.path)
const installedVersion = await resolvePackage({
cwd: outDir,
pkg,
}).catch(() => '')
if (!installedVersion) {
spinner.error(
`${pkg} not found: install it with \`npm i ${pkg}\``,
)
}
return {
path: args.path,
external: true,
Expand All @@ -99,6 +117,16 @@ export function esbuildPluginBundleDependencies({
}
}
if (externalizeNpm) {
const pkg = getPackageName(args.path)
const installedVersion = await resolvePackage({
cwd: outDir,
pkg,
}).catch(() => '')
if (!installedVersion) {
spinner.error(
`${pkg} not found: install it with \`npm i ${pkg}\``,
)
}
return {
path: args.path,
external: true,
Expand Down Expand Up @@ -263,3 +291,14 @@ export function retryTwice<F extends Function>(fn: Function): Function {
}
}
}

export function getPackageName(importPath: string): string {
// Handle scoped packages
if (importPath.startsWith('@')) {
const [scope, rest] = importPath.split('/')
if (!rest) return importPath
return `${scope}/${rest.split('/')[0]}`
}
// Handle regular packages
return importPath.split('/')[0]
}
73 changes: 48 additions & 25 deletions unframer/src/exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from './css.js'
import {
esbuildPluginBundleDependencies,
externalPackages,
defaultExternalPackages,
replaceWebPageIds,
resolveRedirect,
} from './esbuild'
Expand All @@ -34,14 +34,6 @@ import {
} from './framer.js'
import { kebabCase, logger, spinner, terminalMarkdown } from './utils.js'

function validateUrl(url: string) {
try {
const u = new URL(url)
} catch (e) {
throw new Error(`Invalid URL: ${url}`)
}
}

export type StyleToken = {
id: string
name?: string | null
Expand Down Expand Up @@ -77,6 +69,7 @@ export async function bundle({
)
const buildContext = await context({
absWorkingDir: out,

entryPoints: Object.keys(components).map((name) => {
return {
in: `virtual:${name}`,
Expand All @@ -93,10 +86,14 @@ export async function bundle({
splitting: true,
logLevel: 'error',
pure: ['addPropertyControls'],
external: externalPackages,
external: defaultExternalPackages,
chunkNames: 'chunks/[name]-[hash]',
plugins: [
esbuildPluginBundleDependencies({
signal,
externalPackages: config.externalPackages,
externalizeNpm: config.allExternal,
outDir: config.outDir,
}),
nodeModulesPolyfillPlugin({}),
{
Expand All @@ -108,6 +105,7 @@ export async function bundle({
namespace: 'virtual',
}
})

build.onLoad(
{ filter: /.*/, namespace: 'virtual' },
async (args) => {
Expand Down Expand Up @@ -183,7 +181,18 @@ export async function bundle({

async function rebuild() {
const prevFiles = recursiveReaddir(out)
const buildResult = await buildContext.rebuild()
const buildResult = await buildContext.rebuild().catch((e) => {
if (e.message.includes('No matching export ')) {
spinner.error(
`esbuild failed to import from an external package, this usually means that the npm package version in Framer is older than the latest.`,
)
spinner.error(
`Use --external to make all npm packagess external, then install the right version`,
)
process.exit(1)
}
throw e
})

for (let file of buildResult.outputFiles!) {
const resultPathAbs = path.resolve(out, file.path)
Expand Down Expand Up @@ -584,31 +593,45 @@ export async function bundle({
// }
// return res
}

export function checkUnframerVersion({ cwd }) {
const currentVersion = packageJson.version
try {
const code = `import('unframer/package.json', { with: { type: 'json' } }).then(pkg => console.log(pkg.version || pkg.default?.version));`
export function resolvePackage({ cwd, pkg }) {
return new Promise<string>((resolve, reject) => {
const code = `import('${pkg}/package.json', { with: { type: 'json' } }).then(pkg => console.log(pkg.version || pkg.default?.version));`

const command = [
JSON.stringify(nodePath),
'-e',
JSON.stringify(code),
].join(' ')
const installedVersion = execSync(command, {
stdio: ['pipe', 'pipe', 'pipe'],
cwd,
})
.toString()
.trim()

exec(
command,
{
cwd,
},
(error, stdout, stderr) => {
if (error) {
logger.log(stderr)
reject(
new Error('Unframer is not installed in your project'),
)
return
}
resolve(stdout.trim())
},
)
})
}

export async function checkUnframerVersion({ cwd }: { cwd: string }) {
const currentVersion = packageJson.version
try {
const installedVersion = await resolvePackage({ cwd, pkg: 'unframer' })
if (installedVersion !== currentVersion) {
spinner.error(
`Unframer version mismatch. Please run: npm update unframer@latest`,
)
}
} catch (e: any) {
logger.log(e.stderr.toString())
} catch (e) {
spinner.error(
'Unframer is not installed in your project. Please run: npm install unframer',
)
Expand Down Expand Up @@ -867,7 +890,7 @@ export async function extractPropControlsUnsafe(
clearTimeout(timer)
if (err) {
spinner.error(`error extracting types for ${name}`)
spinner.error(stderr)
console.error(stderr)
return rej(err)
}

Expand Down

0 comments on commit e1eb86f

Please sign in to comment.