880f82e658
Right now this examples app looks exactly the same as our old examples app, but there are a couple of tiny differences: - We use `vite` instead of our own esbuild setup for development and bundling - We use `@tldraw/assets` for smart asset hashing instead of copying the assets to a public folder You can use `@tldraw/assets` with vite with a bunch of extra config, but it (plus a bunch of other bundlers) also support a special syntax for specifying asset urls: `new URL('./my/asset.svg', import.meta.url).href`. This approach is more standards-complient, but doesn't work with every bundler just yet. This diff also adds a url-based version of `@tldraw/assets`, although I'd like to tweak the entry point - right now you need to import from `@tldraw/assets/lib/urls`, but i'd like to find a way to get this to `@tldraw/assets/urls` or something at some point. There are a couple other extra fixes in here: - vscode builds were broken, they're fixed now! - there's also a little tweak to the `getBundlerAssetUrls` API to allow passing in a function instead of an object for URL formatting - there are new internal-only functions for injecting asset urls globally instead of passing them in via react props. this means we can get the benefits of cacheable URLs without having to clutter our examples by passing them in
82 lines
2.3 KiB
TypeScript
82 lines
2.3 KiB
TypeScript
import { readFile, writeFile as writeFileUnchecked } from 'fs/promises'
|
|
import json5 from 'json5'
|
|
import { basename, dirname, join, relative } from 'path'
|
|
import prettier from 'prettier'
|
|
import { fileURLToPath } from 'url'
|
|
|
|
const __filename = fileURLToPath(import.meta.url)
|
|
const __dirname = dirname(__filename)
|
|
const isBublic = basename(join(__dirname, '../..')) === 'bublic'
|
|
export const REPO_ROOT = join(__dirname, isBublic ? '../../..' : '../..')
|
|
export const BUBLIC_ROOT = join(__dirname, '../..')
|
|
|
|
export async function readJsonIfExists(file: string) {
|
|
const fileContents = await readFileIfExists(file)
|
|
if (fileContents === null) {
|
|
return null
|
|
}
|
|
return json5.parse(fileContents)
|
|
}
|
|
|
|
export async function readFileIfExists(file: string) {
|
|
try {
|
|
return await readFile(file, 'utf8')
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
const prettierConfigPromise = prettier.resolveConfig(__dirname)
|
|
export async function writeTypescriptFile(filePath: string, code: string) {
|
|
const formattedCode = prettier.format(
|
|
`
|
|
// This file is automatically generated by scripts/refresh-assets.ts.
|
|
// Do not edit manually.
|
|
|
|
${code}
|
|
`,
|
|
{
|
|
...(await prettierConfigPromise),
|
|
parser: 'typescript',
|
|
}
|
|
)
|
|
await writeStringFile(filePath, formattedCode)
|
|
}
|
|
|
|
export async function writeStringFile(filePath: string, contents: string) {
|
|
await writeFile(filePath, Buffer.from(contents, 'utf-8'))
|
|
}
|
|
|
|
export async function writeFile(filePath: string, contents: Buffer) {
|
|
if (process.env.CI) {
|
|
let existingContents: Buffer | null = null
|
|
try {
|
|
existingContents = await readFile(filePath)
|
|
} catch {
|
|
// Ignore
|
|
}
|
|
if (existingContents && !existingContents.equals(contents)) {
|
|
console.log(
|
|
`Asset file ${relative(
|
|
REPO_ROOT,
|
|
filePath
|
|
)} has changed. Please run this script again and commit the changes.`
|
|
)
|
|
console.log('Contents before:')
|
|
console.log(existingContents.toString('utf-8'))
|
|
console.log('\nContents after:')
|
|
console.log(contents.toString('utf-8'))
|
|
|
|
process.exit(1)
|
|
}
|
|
}
|
|
await writeFileUnchecked(filePath, contents, 'utf-8')
|
|
}
|
|
|
|
export async function writeJsonFile(filePath: string, contents: unknown) {
|
|
const formattedJson = prettier.format(JSON.stringify(contents, null, '\t'), {
|
|
...(await prettierConfigPromise),
|
|
parser: 'json',
|
|
})
|
|
await writeStringFile(filePath, formattedJson)
|
|
}
|