diff --git a/packages/vite/index.d.ts b/packages/vite/index.d.ts index aa7c16b58c..848505af54 100644 --- a/packages/vite/index.d.ts +++ b/packages/vite/index.d.ts @@ -4,4 +4,5 @@ export * from './src/hbs.js'; export * from './src/scripts.js'; export * from './src/template-tag.js'; export * from './src/optimize-deps.js'; +export * from './src/assets.js'; export * from './src/build.js'; diff --git a/packages/vite/index.mjs b/packages/vite/index.mjs index aa7c16b58c..01bbe49522 100644 --- a/packages/vite/index.mjs +++ b/packages/vite/index.mjs @@ -5,3 +5,4 @@ export * from './src/scripts.js'; export * from './src/template-tag.js'; export * from './src/optimize-deps.js'; export * from './src/build.js'; +export * from './src/assets.js'; diff --git a/packages/vite/package.json b/packages/vite/package.json index bbd085b1eb..70ad2f42ba 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -20,7 +20,8 @@ "fs-extra": "^10.0.0", "jsdom": "^16.6.0", "source-map-url": "^0.4.1", - "terser": "^5.7.0" + "terser": "^5.7.0", + "fast-glob": "^3.3.2" }, "devDependencies": { "@embroider/core": "workspace:^", diff --git a/packages/vite/src/assets.ts b/packages/vite/src/assets.ts new file mode 100644 index 0000000000..282225a147 --- /dev/null +++ b/packages/vite/src/assets.ts @@ -0,0 +1,40 @@ +import { ResolverLoader } from '@embroider/core'; +import type { Plugin } from 'vite'; +import * as process from 'process'; +import { dirname, join } from 'path'; +import { copyFileSync, mkdirpSync } from 'fs-extra'; +import glob from 'fast-glob'; + +export function assets(): Plugin { + const cwd = process.cwd(); + const resolverLoader = new ResolverLoader(cwd); + return { + name: 'assets', + enforce: 'pre', + outputOptions(options) { + options.dir = join(process.cwd(), 'dist'); + }, + async writeBundle(options) { + const engines = resolverLoader.resolver.options.engines; + const pubDir = join(process.cwd(), 'public'); + const publicAppFiles = glob.sync('**/*', { + cwd: pubDir, + }); + for (const publicAppFile of publicAppFiles) { + mkdirpSync(dirname(join(options.dir!, publicAppFile))); + copyFileSync(join(pubDir, publicAppFile), join(options.dir!, publicAppFile)); + } + for (const engine of engines) { + engine.activeAddons.forEach(addon => { + const pkg = resolverLoader.resolver.packageCache.ownerOfFile(addon.root); + if (!pkg || !pkg.isV2Addon()) return; + const assets = pkg.meta['public-assets'] || {}; + Object.entries(assets).forEach(([path, dest]) => { + mkdirpSync(dirname(join(options.dir!, dest))); + copyFileSync(join(pkg.root, path), join(options.dir!, dest)); + }); + }); + } + }, + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55706ec29c..2740124522 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -929,6 +929,9 @@ importers: esbuild: specifier: ^0.17.19 version: 0.17.19 + fast-glob: + specifier: ^3.3.2 + version: 3.3.2 fs-extra: specifier: ^10.0.0 version: 10.1.0 diff --git a/tests/scenarios/vite-app-test.ts b/tests/scenarios/vite-app-test.ts index 0943035564..7df07772ce 100644 --- a/tests/scenarios/vite-app-test.ts +++ b/tests/scenarios/vite-app-test.ts @@ -119,6 +119,8 @@ viteAppScenarios const distFiles = readdirSync(join(app.dir, 'dist')); assert.ok(distFiles.length > 1, 'should have created dist folder'); assert.ok(distFiles.includes('assets'), 'should have created assets folder'); + assert.ok(distFiles.includes('ember-welcome-page'), 'should have copied addon asset files'); + assert.ok(distFiles.includes('robots.txt'), 'should have copied app assets'); const assetFiles = readdirSync(join(app.dir, 'dist', 'assets')); assert.ok(assetFiles.length > 1, 'should have created asset files'); diff --git a/tests/vite-app/vite.config.mjs b/tests/vite-app/vite.config.mjs index 8d3a71d633..c1accdace8 100644 --- a/tests/vite-app/vite.config.mjs +++ b/tests/vite-app/vite.config.mjs @@ -6,6 +6,7 @@ import { templateTag, optimizeDeps, compatPrebuild, + assets, } from "@embroider/vite"; import { resolve } from "path"; import { babel } from "@rollup/plugin-babel"; @@ -23,6 +24,7 @@ export default defineConfig({ scripts(), resolver(), compatPrebuild(), + assets(), babel({ babelHelpers: "runtime",