Skip to content

Commit ebc62f2

Browse files
committed
fix: use the base path if specified in vite config
1 parent 720064b commit ebc62f2

File tree

2 files changed

+137
-6
lines changed

2 files changed

+137
-6
lines changed

packages/vite-plugin/src/__tests__/plugin.test.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe('Workerify Vite Plugin', () => {
2727

2828
expect(plugin.name).toBe('vite:workerify');
2929
expect(plugin.enforce).toBe('pre');
30+
expect(typeof plugin.configResolved).toBe('function');
3031
expect(typeof plugin.configureServer).toBe('function');
3132
expect(typeof plugin.generateBundle).toBe('function');
3233
expect(typeof plugin.resolveId).toBe('function');
@@ -81,6 +82,118 @@ describe('Workerify Vite Plugin', () => {
8182
});
8283
});
8384

85+
describe('Base path configuration', () => {
86+
it('should handle base path from Vite config', () => {
87+
const plugin = workerifyPlugin();
88+
89+
// Simulate Vite calling configResolved with a base path
90+
plugin.configResolved?.({ base: '/app/' });
91+
92+
// Load the virtual module and check it contains the correct URL
93+
const virtualModule = plugin.load?.('\0virtual:workerify-register');
94+
expect(virtualModule).toContain('/app/workerify-sw.js');
95+
});
96+
97+
it('should handle base path without trailing slash', () => {
98+
const plugin = workerifyPlugin();
99+
100+
plugin.configResolved?.({ base: '/myapp' });
101+
102+
const virtualModule = plugin.load?.('\0virtual:workerify-register');
103+
expect(virtualModule).toContain('/myapp/workerify-sw.js');
104+
});
105+
106+
it('should handle empty base path', () => {
107+
const plugin = workerifyPlugin();
108+
109+
plugin.configResolved?.({ base: '' });
110+
111+
const virtualModule = plugin.load?.('\0virtual:workerify-register');
112+
expect(virtualModule).toContain('/workerify-sw.js');
113+
});
114+
115+
it('should handle undefined base path', () => {
116+
const plugin = workerifyPlugin();
117+
118+
plugin.configResolved?.({});
119+
120+
const virtualModule = plugin.load?.('\0virtual:workerify-register');
121+
expect(virtualModule).toContain('/workerify-sw.js');
122+
});
123+
124+
it('should handle base path with custom SW filename', () => {
125+
const plugin = workerifyPlugin({ swFileName: 'custom-sw.js' });
126+
127+
plugin.configResolved?.({ base: '/my-app/' });
128+
129+
const virtualModule = plugin.load?.('\0virtual:workerify-register');
130+
expect(virtualModule).toContain('/my-app/custom-sw.js');
131+
});
132+
133+
it('should serve SW at correct URL with base path in dev', async () => {
134+
const plugin = workerifyPlugin({ swFileName: 'test-sw.js' });
135+
136+
// Set base path
137+
plugin.configResolved?.({ base: '/base/' });
138+
139+
// Configure server
140+
plugin.configureServer?.(mockServer);
141+
142+
const middleware = captureMockMiddleware(mockServer);
143+
144+
// Request with base path
145+
const req = createMockRequest('/base/test-sw.js');
146+
const res = createMockResponse();
147+
148+
const handled = await callMiddleware(middleware, req, res);
149+
150+
expect(handled).toBe(true);
151+
expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'application/javascript');
152+
expect(res.end).toHaveBeenCalledWith(expect.any(String));
153+
});
154+
155+
it('should not serve SW at wrong base path', async () => {
156+
const plugin = workerifyPlugin({ swFileName: 'test-sw.js' });
157+
158+
// Set base path
159+
plugin.configResolved?.({ base: '/correct-base/' });
160+
161+
// Configure server
162+
plugin.configureServer?.(mockServer);
163+
164+
const middleware = captureMockMiddleware(mockServer);
165+
166+
// Request without base path (wrong URL)
167+
const req = createMockRequest('/test-sw.js');
168+
const res = createMockResponse();
169+
170+
const handled = await callMiddleware(middleware, req, res);
171+
172+
expect(handled).toBe(false);
173+
expect(res.setHeader).not.toHaveBeenCalled();
174+
expect(res.end).not.toHaveBeenCalled();
175+
});
176+
177+
it('should handle complex base paths', () => {
178+
const plugin = workerifyPlugin();
179+
180+
plugin.configResolved?.({ base: '/path/to/app/' });
181+
182+
const virtualModule = plugin.load?.('\0virtual:workerify-register');
183+
expect(virtualModule).toContain('/path/to/app/workerify-sw.js');
184+
});
185+
186+
it('should handle root base path correctly', () => {
187+
const plugin = workerifyPlugin();
188+
189+
plugin.configResolved?.({ base: '/' });
190+
191+
const virtualModule = plugin.load?.('\0virtual:workerify-register');
192+
expect(virtualModule).toContain('/workerify-sw.js');
193+
expect(virtualModule).not.toContain('//workerify-sw.js');
194+
});
195+
});
196+
84197
describe('Development server middleware', () => {
85198
it('should register middleware with Vite server', () => {
86199
const plugin = workerifyPlugin();
@@ -256,12 +369,14 @@ describe('Workerify Vite Plugin', () => {
256369
const plugin = workerifyPlugin();
257370

258371
expect(plugin).toHaveProperty('name');
372+
expect(plugin).toHaveProperty('configResolved');
259373
expect(plugin).toHaveProperty('configureServer');
260374
expect(plugin).toHaveProperty('generateBundle');
261375
expect(plugin).toHaveProperty('resolveId');
262376
expect(plugin).toHaveProperty('load');
263377

264378
expect(typeof plugin.name).toBe('string');
379+
expect(typeof plugin.configResolved).toBe('function');
265380
expect(typeof plugin.configureServer).toBe('function');
266381
expect(typeof plugin.generateBundle).toBe('function');
267382
expect(typeof plugin.resolveId).toBe('function');

packages/vite-plugin/src/index.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SW_TEMPLATE } from './generated/service-worker-template.js';
55
interface Plugin {
66
name: string;
77
enforce?: 'pre' | 'post';
8+
configResolved?: (config: any) => void;
89
configureServer?: (server: any) => void;
910
generateBundle?: (this: PluginContext) => void;
1011
resolveId?: (id: string) => string | null;
@@ -28,17 +29,32 @@ export default function workerifyPlugin(
2829
: (opts.scope ?? '') + '/';
2930
const swFileName = opts.swFileName ?? 'workerify-sw.js';
3031

31-
// on garde le contenu en mémoire, pas besoin de fichier sur disque
32+
// keep content in memory, no need for file on disk
3233
const swSource = SW_TEMPLATE;
3334

34-
// URL publique finale du SW (ex: /workerify-sw.js)
35-
const publicSwUrl = '/' + swFileName.replace(/^\//, '');
35+
// Variable to store Vite's base path
36+
let viteBasePath = '/';
37+
38+
// Final public SW URL will be calculated with the base path
39+
let publicSwUrl = '/' + swFileName.replace(/^\//, '');
3640

3741
return {
3842
name: 'vite:workerify',
3943
enforce: 'pre',
4044

41-
// Dev server: servir le fichier SW en mémoire
45+
// Hook into Vite config to get base path
46+
configResolved(config: any) {
47+
// Get the base path from Vite config (defaults to '/')
48+
viteBasePath = config.base || '/';
49+
// Ensure base path ends with '/'
50+
if (!viteBasePath.endsWith('/')) {
51+
viteBasePath = viteBasePath + '/';
52+
}
53+
// Update the public SW URL with the base path
54+
publicSwUrl = viteBasePath + swFileName.replace(/^\//, '');
55+
},
56+
57+
// Dev server: serve the SW file from memory
4258
configureServer(server: any) {
4359
server.middlewares.use((req: any, res: any, next: any) => {
4460
if (req.url === publicSwUrl) {
@@ -50,7 +66,7 @@ export default function workerifyPlugin(
5066
});
5167
},
5268

53-
// Build: émettre l'asset SW dans dist/
69+
// Build: emit the SW asset to dist/
5470
generateBundle() {
5571
this.emitFile({
5672
type: 'asset',
@@ -59,7 +75,7 @@ export default function workerifyPlugin(
5975
});
6076
},
6177

62-
// Module virtuel pour l'enregistrement
78+
// Virtual module for registration
6379
resolveId(id: string) {
6480
if (id === 'virtual:workerify-register') {
6581
return '\0virtual:workerify-register';

0 commit comments

Comments
 (0)