migration to vite/playwright

This commit is contained in:
JFH
2025-11-29 11:31:34 +01:00
parent babd3490c9
commit a37fbac749
186 changed files with 2699 additions and 13224 deletions

View File

@@ -0,0 +1,83 @@
import { readdir, stat } from 'node:fs/promises'
import { join, resolve } from 'node:path'
import { build } from 'vite'
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars'
import string from 'vite-plugin-string'
const root = process.cwd()
const extensionsRoot = resolve(root, 'src/editor/extensions')
const outDir = resolve(root, 'dist/editor')
const htmlStringPlugin = string({
include: [
'src/editor/dialogs/**/*.html',
'src/editor/panels/*.html',
'src/editor/templates/*.html',
'src/editor/extensions/*/*.html'
]
})
htmlStringPlugin.enforce = 'post'
const entries = []
for (const dirent of await readdir(extensionsRoot, { withFileTypes: true })) {
if (!dirent.isDirectory() || !dirent.name.startsWith('ext-')) continue
const entryPath = join(extensionsRoot, dirent.name, `${dirent.name}.js`)
try {
const st = await stat(entryPath)
if (st.isFile()) entries.push(entryPath)
} catch (_err) {
// no entry file, skip
}
}
if (!entries.length) {
console.info('No extension entries found')
process.exit(0)
}
await build({
// Use isolated config to avoid inheriting the main lib/iife build.
configFile: false,
root,
base: './',
logLevel: 'info',
plugins: [
{
name: 'svgedit-skip-vite-build-html',
apply: 'build',
enforce: 'pre',
configResolved (config) {
config.plugins = config.plugins.filter(plugin => plugin.name !== 'vite:build-html')
}
},
htmlStringPlugin,
{
...dynamicImportVars({
include: ['src/editor/extensions/*/*.js']
}),
apply: 'build'
}
],
build: {
outDir,
emptyOutDir: false, // main build already wrote Editor.js, keep it
sourcemap: true,
minify: false, // keep exports intact
rollupOptions: {
treeshake: false,
preserveEntrySignatures: 'strict',
input: entries,
output: {
format: 'es',
inlineDynamicImports: false,
preserveModules: true,
preserveModulesRoot: extensionsRoot,
entryFileNames: '[name].js',
chunkFileNames: 'extensions/_chunks/[name]-[hash].js',
assetFileNames: 'extensions/_assets/[name]-[hash][extname]'
}
}
}
})
console.info(`Bundled ${entries.length} extensions`)

25
scripts/copy-static.mjs Normal file
View File

@@ -0,0 +1,25 @@
import { cp, mkdir } from 'node:fs/promises'
import { resolve } from 'node:path'
const root = process.cwd()
const outDir = resolve(root, 'dist/editor')
await mkdir(outDir, { recursive: true })
const targets = [
['src/editor/index.html', 'index.html'],
['src/editor/xdomain-index.html', 'xdomain-index.html'],
['src/editor/iife-index.html', 'iife-index.html'],
['src/editor/browser-not-supported.html', 'browser-not-supported.html'],
['src/editor/browser-not-supported.js', 'browser-not-supported.js'],
['src/editor/svgedit.css', 'svgedit.css'],
['src/editor/images', 'images'],
['src/editor/components/jgraduate/images', 'components/jgraduate/images'],
['src/editor/extensions', 'extensions']
]
for (const [src, dest] of targets) {
await cp(resolve(root, src), resolve(outDir, dest), { recursive: true })
}
console.info('Copied static editor assets to dist/editor')

44
scripts/run-e2e.mjs Normal file
View File

@@ -0,0 +1,44 @@
import { spawn } from 'node:child_process'
import { join } from 'node:path'
import { existsSync } from 'node:fs'
// Always instrument the build for coverage and ensure Playwright can launch.
process.env.COVERAGE = 'true'
// Put Playwright browsers inside the project so CI without sudo/system cache still works.
const playwrightCache = process.env.PLAYWRIGHT_BROWSERS_PATH ||
join(process.cwd(), 'node_modules', '.cache', 'ms-playwright')
process.env.PLAYWRIGHT_BROWSERS_PATH = playwrightCache
const sanitizedEnv = { ...process.env, PLAYWRIGHT_BROWSERS_PATH: playwrightCache }
delete sanitizedEnv.ELECTRON_RUN_AS_NODE
delete process.env.ELECTRON_RUN_AS_NODE
const run = (cmd, args, opts = {}) => new Promise((resolve, reject) => {
const child = spawn(cmd, args, { stdio: 'inherit', shell: false, env: sanitizedEnv, ...opts })
child.on('exit', code => (code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${code}`))))
child.on('error', reject)
})
const hasPlaywright = async () => {
try {
await run('npx', ['playwright', '--version'], { timeout: 30000 })
return true
} catch (error) {
console.warn('Skipping e2e tests because Playwright is unavailable or failed to verify.')
console.warn(error.message || error)
return false
}
}
const ensureBrowser = async () => {
// Download Chromium to the project cache if it's missing.
if (!existsSync(playwrightCache)) {
await run('npx', ['playwright', 'install', 'chromium'])
}
}
if (await hasPlaywright()) {
await ensureBrowser()
await run('rimraf', ['.nyc_output/*'], { shell: true })
await run('npx', ['playwright', 'test'])
await run('npx', ['nyc', 'report', '--reporter', 'text-summary', '--reporter', 'json-summary'])
}