From 1c512eb65a0d9b421d4931e4f935d08c7cbf1dd1 Mon Sep 17 00:00:00 2001 From: Patrick Pircher Date: Tue, 5 Nov 2024 14:36:52 +0100 Subject: [PATCH] fix custom base --- packages/vite/src/assets.ts | 5 +- packages/vite/src/scripts.ts | 20 ++++- test-packages/support/testem-proxy.ts | 7 +- tests/scenarios/vite-internals-test.ts | 115 ++++++++++++++++++++++++- 4 files changed, 137 insertions(+), 10 deletions(-) diff --git a/packages/vite/src/assets.ts b/packages/vite/src/assets.ts index c9a9635554..8319b2471f 100644 --- a/packages/vite/src/assets.ts +++ b/packages/vite/src/assets.ts @@ -43,8 +43,9 @@ export function assets(): Plugin { configureServer(server) { return () => { server.middlewares.use((req, res, next) => { - if (req.originalUrl && req.originalUrl.length > 1) { - const assetUrl = findPublicAsset(req.originalUrl.split('?')[0], resolverLoader.resolver); + const originalUrl = req.originalUrl!.slice((server.config.base.length || 1) - 1); + if (originalUrl && originalUrl.length > 1) { + const assetUrl = findPublicAsset(originalUrl.split('?')[0], resolverLoader.resolver); if (assetUrl) { return send(req, assetUrl).pipe(res as unknown as NodeJS.WritableStream); } diff --git a/packages/vite/src/scripts.ts b/packages/vite/src/scripts.ts index de6e991b6d..6bdb9281ea 100644 --- a/packages/vite/src/scripts.ts +++ b/packages/vite/src/scripts.ts @@ -26,11 +26,14 @@ export function scripts(params?: { include?: string[]; exclude?: string[] }): Pl } }); + let config: any = null; + return { name: 'embroider-scripts', enforce: 'pre', configResolved(resolvedConfig) { + config = resolvedConfig; optimizer = new ScriptOptimizer(resolvedConfig.root); }, @@ -47,7 +50,7 @@ export function scripts(params?: { include?: string[]; exclude?: string[] }): Pl // we don't do anything in `vite dev`, we only need to work in `vite // build` if (!context.server) { - return optimizer.transformHTML(htmlIn); + return optimizer.transformHTML(htmlIn, config.base); } }, }; @@ -123,16 +126,29 @@ class ScriptOptimizer { return fileParts.join('.'); } - transformHTML(htmlIn: string) { + transformHTML(htmlIn: string, baseUrl: string) { if (this.transformState?.htmlIn !== htmlIn) { + const appName = readJSONSync(resolve(process.cwd(), 'package.json')).name; let parsed = new JSDOM(htmlIn); let scriptTags = [...parsed.window.document.querySelectorAll('script')] as HTMLScriptElement[]; + let linkTags = [...parsed.window.document.querySelectorAll('link')] as HTMLLinkElement[]; + for (const linkTag of linkTags) { + if (linkTag.href.startsWith('/@embroider/virtual')) { + linkTag.href = baseUrl + linkTag.href.slice(1); + } + if (linkTag.href === `/assets/${appName}.css`) { + linkTag.href = baseUrl + linkTag.href.slice(1); + } + } for (let scriptTag of scriptTags) { if (scriptTag.type !== 'module') { let fingerprinted = this.emitted.get(scriptTag.src); if (fingerprinted) { scriptTag.src = fingerprinted; } + if (scriptTag.src.startsWith('/@embroider/virtual')) { + scriptTag.src = baseUrl + scriptTag.src.slice(1); + } } } let htmlOut = parsed.serialize(); diff --git a/test-packages/support/testem-proxy.ts b/test-packages/support/testem-proxy.ts index 13507afb32..324ce58a6c 100644 --- a/test-packages/support/testem-proxy.ts +++ b/test-packages/support/testem-proxy.ts @@ -10,7 +10,7 @@ import type { Application } from 'express'; "/tests/index.html" URL. */ -export function testemProxy(targetURL: string) { +export function testemProxy(targetURL: string, base = '/') { return function testemProxyHandler(app: Application) { const proxy = httpProxy.createProxyServer({ changeOrigin: true, @@ -23,10 +23,11 @@ export function testemProxy(targetURL: string) { app.all('*', (req, res, next) => { let url = req.url; - if (url === '/testem.js' || url.startsWith('/testem/')) { + if (url === `${base}testem.js` || url.startsWith('/testem/')) { + req.url = req.url.replace(base, '/'); return next(); } - let m = /^(\/\d+)\/tests\/index.html/.exec(url); + let m = /^(\/\d+).*\/tests\/index.html/.exec(url); if (m) { url = url.slice(m[1].length); } diff --git a/tests/scenarios/vite-internals-test.ts b/tests/scenarios/vite-internals-test.ts index e95d63c199..499d2cad21 100644 --- a/tests/scenarios/vite-internals-test.ts +++ b/tests/scenarios/vite-internals-test.ts @@ -4,10 +4,12 @@ import QUnit from 'qunit'; import fetch from 'node-fetch'; import CommandWatcher from './helpers/command-watcher'; import { setupAuditTest } from '@embroider/test-support/audit-assertions'; +import { mkdirSync, moveSync, readFileSync, writeFileSync } from 'fs-extra'; +import { resolve } from 'path'; const { module: Qmodule, test } = QUnit; -function buildViteInternalsTest(testNonColocatedTemplates: boolean, app: Project) { +function buildViteInternalsTest(testNonColocatedTemplates: boolean, app: Project, customBase = '/') { // These are for a custom testem setup that will let us do runtime tests // inside `vite dev` rather than only against the output of `vite build`. // @@ -25,7 +27,7 @@ function buildViteInternalsTest(testNonColocatedTemplates: boolean, app: Project 'use strict'; module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: '${customBase}tests/index.html?hidepassed', disable_watching: true, launch_in_ci: ['Chrome'], launch_in_dev: ['Chrome'], @@ -45,11 +47,66 @@ function buildViteInternalsTest(testNonColocatedTemplates: boolean, app: Project }, }, middleware: [ - require('@embroider/test-support/testem-proxy').testemProxy('http://localhost:4200') + require('@embroider/test-support/testem-proxy').testemProxy('http://localhost:4200', '${customBase}') ], }; `, + config: customBase + ? { + 'environment.js': ` + 'use strict'; + + module.exports = function (environment) { + const ENV = { + modulePrefix: 'ts-app-template', + environment, + rootURL: '${customBase}', + locationType: 'history', + EmberENV: { + EXTEND_PROTOTYPES: false, + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true + }, + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + }, + }; + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + // ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + // ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + // Testem prefers this... + ENV.locationType = 'none'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; + ENV.APP.autoboot = false; + } + + if (environment === 'production') { + // here you can enable a production-specific feature + } + + return ENV; + }; + `, + } + : {}, + app: { components: { 'fancy-gts.gts': ` @@ -354,3 +411,55 @@ tsAppScenarios buildViteInternalsTest(false, app); }) .forEachScenario(runViteInternalsTest); + +tsAppScenarios + .skip('lts_5_12') + .map('vite-with-base-internals', app => { + buildViteInternalsTest(false, app, '/sub-dir/'); + }) + .forEachScenario(runViteInternalsTestWithBase); + +function runViteInternalsTestWithBase(scenario: Scenario) { + Qmodule(scenario.name, function (hooks) { + let app: PreparedApp; + let server: CommandWatcher; + + hooks.before(async () => { + app = await scenario.prepare(); + }); + + Qmodule('vite dev', function (hooks) { + hooks.before(async () => { + server = CommandWatcher.launch('vite', ['--clearScreen', 'false', '--base', '/sub-dir/'], { cwd: app.dir }); + const [, appURL] = await server.waitFor(/Local:\s+(https?:\/\/.*)\//g); + let testem = readFileSync(resolve(app.dir, 'testem-dev.js')).toString(); + testem = testem.replace('http://localhost:4200', appURL.replace('/sub-dir', '')); + writeFileSync(resolve(app.dir, 'testem-dev.js'), testem); + }); + + hooks.after(async () => { + await server?.shutdown(); + }); + + test('run test suite against vite dev', async function (assert) { + let result = await app.execute('pnpm testem --file testem-dev.js ci'); + assert.equal(result.exitCode, 0, result.output); + }); + }); + + Qmodule('vite build', function (hooks) { + hooks.before(async () => { + await app.execute('pnpm vite build --mode test --base /sub-dir/'); + mkdirSync(resolve(app.dir, './sub-dir'), { recursive: true }); + moveSync(resolve(app.dir, './dist'), resolve(app.dir, './sub-dir'), { overwrite: true }); + mkdirSync(resolve(app.dir, './dist/sub-dir'), { recursive: true }); + moveSync(resolve(app.dir, './sub-dir'), resolve(app.dir, './dist/sub-dir'), { overwrite: true }); + }); + + test('run test suite against vite dist with sub-dir', async function (assert) { + let result = await app.execute('ember test --path dist/sub-dir'); + assert.equal(result.exitCode, 0, result.output); + }); + }); + }); +}