Skip to content

Commit 3676296

Browse files
authored
feat: add configurable dev-dist folder and buildBase option (#461)
* feat: add configurable `dev-dist` folder and `buildBase` option * chore: update `buildBase` type jsdoc * chore: .
1 parent cd14a85 commit 3676296

File tree

7 files changed

+45
-15
lines changed

7 files changed

+45
-15
lines changed

info.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ declare module 'virtual:pwa-info' {
22
export interface PwaInfo {
33
pwaInDevEnvironment: boolean
44
/**
5-
* The webmanifest will be always here.
5+
* The web manifest will be always here.
66
*/
77
webManifest: {
88
href: string
99
useCredentials: boolean
1010
/**
1111
* The link tag with or without `crossorigin`:
1212
* - `<link rel="manifest" href="<webManifestUrl>" />`.
13-
* - `<link rel="manifest" href="<webManifestUrl>" crossorigin=use-credentials" />`.
13+
* - `<link rel="manifest" href="<webManifestUrl>" crossorigin="use-credentials" />`.
1414
*/
1515
linkTag: string
1616
}

src/api.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export function _generateBundle({ options, viteConfig, useImportRegister }: PWAP
2929

3030
if (options.manifest) {
3131
bundle[options.manifestFilename] = {
32+
// @ts-expect-error: for Vite 3 support, Vite 4 has removed `isAsset` property
3233
isAsset: true,
3334
type: 'asset',
3435
name: undefined,
@@ -43,6 +44,7 @@ export function _generateBundle({ options, viteConfig, useImportRegister }: PWAP
4344

4445
if (options.injectRegister === 'script' && !existsSync(resolve(viteConfig.publicDir, FILE_SW_REGISTER))) {
4546
bundle[FILE_SW_REGISTER] = {
47+
// @ts-expect-error: for Vite 3 support, Vite 4 has removed `isAsset` property
4648
isAsset: true,
4749
type: 'asset',
4850
name: undefined,
@@ -77,7 +79,7 @@ export function createAPI(ctx: PWAPluginContext): VitePluginPWAAPI {
7779
}
7880

7981
return {
80-
href: `${options.base}${url}`,
82+
href: `${ctx.devEnvironment ? options.base : options.buildBase}${url}`,
8183
useCredentials: ctx.options.useCredentials,
8284
toLinkTag() {
8385
return manifest
@@ -109,13 +111,15 @@ export function createAPI(ctx: PWAPluginContext): VitePluginPWAAPI {
109111
script = generateRegisterSW(options, false)
110112
}
111113

114+
const base = ctx.devEnvironment ? options.base : options.buildBase
115+
112116
return {
113117
// hint when required
114118
shouldRegisterSW,
115119
inline: options.injectRegister === 'inline',
116120
scope: options.scope,
117-
inlinePath: `${options.base}${ctx.devEnvironment ? DEV_SW_NAME : options.filename}`,
118-
registerPath: `${options.base}${FILE_SW_REGISTER}`,
121+
inlinePath: `${base}${ctx.devEnvironment ? DEV_SW_NAME : options.filename}`,
122+
registerPath: `${base}${FILE_SW_REGISTER}`,
119123
type,
120124
toScriptTag() {
121125
return script

src/html.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
import type { ResolvedVitePWAOptions } from './types'
99

1010
export function generateSimpleSWRegister(options: ResolvedVitePWAOptions, dev: boolean) {
11-
const path = dev ? `${options.base}${DEV_SW_NAME}` : `${options.base}${options.filename}`
11+
const path = dev ? `${options.base}${DEV_SW_NAME}` : `${options.buildBase}${options.filename}`
1212

1313
// we are using HMR to load this script: DO NOT ADD window::load event listener
1414
if (dev) {
@@ -50,15 +50,15 @@ export function generateWebManifest(options: ResolvedVitePWAOptions, dev: boolea
5050
return options.manifest ? `<link rel="manifest" href="${name}"${crossorigin}>` : ''
5151
}
5252
else {
53-
return options.manifest ? `<link rel="manifest" href="${options.base}${options.manifestFilename}"${crossorigin}>` : ''
53+
return options.manifest ? `<link rel="manifest" href="${options.buildBase}${options.manifestFilename}"${crossorigin}>` : ''
5454
}
5555
}
5656

5757
export function generateRegisterSW(options: ResolvedVitePWAOptions, dev: boolean) {
5858
if (options.injectRegister === 'inline')
5959
return `<script id="vite-plugin-pwa:inline-sw">${generateSimpleSWRegister(options, dev)}</script>`
6060
else if (options.injectRegister === 'script')
61-
return `<script id="vite-plugin-pwa:register-sw" src="${options.base}${FILE_SW_REGISTER}"></script>`
61+
return `<script id="vite-plugin-pwa:register-sw" src="${dev ? options.base : options.buildBase}${FILE_SW_REGISTER}"></script>`
6262

6363
return undefined
6464
}

src/options.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { ResolvedConfig } from 'vite'
44
import type { GenerateSWOptions, InjectManifestOptions } from 'workbox-build'
55
import type { ManifestOptions, ResolvedVitePWAOptions, VitePWAOptions } from './types'
66
import { configureStaticAssets } from './assets'
7-
import { resolveBathPath } from './utils'
7+
import { resolveBasePath } from './utils'
88
import { defaultInjectManifestVitePlugins } from './constants'
99

1010
function resolveSwPaths(injectManifest: boolean, root: string, srcDir: string, outDir: string, filename: string): {
@@ -57,9 +57,10 @@ export async function resolveOptions(options: Partial<VitePWAOptions>, viteConfi
5757
devOptions = { enabled: false, type: 'classic' },
5858
selfDestroying = false,
5959
integration = {},
60+
buildBase,
6061
} = options
6162

62-
const basePath = resolveBathPath(base)
63+
const basePath = resolveBasePath(base)
6364
// check typescript service worker for injectManifest strategy
6465
const { swSrc, swDest, useFilename } = resolveSwPaths(
6566
strategies === 'injectManifest',
@@ -157,6 +158,7 @@ export async function resolveOptions(options: Partial<VitePWAOptions>, viteConfi
157158
rollupFormat,
158159
vitePlugins,
159160
selfDestroying,
161+
buildBase: buildBase ?? basePath,
160162
}
161163

162164
await configureStaticAssets(resolvedVitePWAOptions, viteConfig)

src/plugins/dev.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ export function DevPlugin(ctx: PWAPluginContext): Plugin {
114114
return undefined
115115
}
116116
if (id.endsWith(swDevOptions.swUrl)) {
117-
const globDirectory = resolve(viteConfig.root, 'dev-dist')
117+
const globDirectory = await resolveDevDistFolder(options, viteConfig)
118118
if (!existsSync(globDirectory))
119-
mkdirSync(globDirectory)
119+
mkdirSync(globDirectory, { recursive: true })
120120

121121
const swDest = resolve(globDirectory, 'sw.js')
122122
if (!swDevOptions.swDevGenerated || !existsSync(swDest)) {
@@ -155,7 +155,7 @@ export function DevPlugin(ctx: PWAPluginContext): Plugin {
155155
}
156156
return await fs.readFile(swDest, 'utf-8')
157157
}
158-
158+
159159
const key = normalizePath(`${options.base}${id.startsWith('/') ? id.slice(1) : id}`)
160160

161161
if (swDevOptions.workboxPaths.has(key))
@@ -165,9 +165,15 @@ export function DevPlugin(ctx: PWAPluginContext): Plugin {
165165
}
166166
}
167167

168+
async function resolveDevDistFolder(options: ResolvedVitePWAOptions, viteConfig: ResolvedConfig) {
169+
return options.devOptions.resolveTempFolder
170+
? await options.devOptions.resolveTempFolder()
171+
: resolve(viteConfig.root, 'dev-dist')
172+
}
173+
168174
async function createDevRegisterSW(options: ResolvedVitePWAOptions, viteConfig: ResolvedConfig) {
169175
if (options.injectRegister === 'script') {
170-
const devDist = resolve(viteConfig.root, 'dev-dist')
176+
const devDist = await resolveDevDistFolder(options, viteConfig)
171177
if (!existsSync(devDist))
172178
mkdirSync(devDist)
173179

src/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,18 @@ export interface VitePWAOptions {
155155
* @default false
156156
*/
157157
selfDestroying?: boolean
158+
/**
159+
* When Vite's build folder is not the same as your base root folder, configure it here.
160+
*
161+
* This option will be useful for integrations like `vite-plugin-laravel` where Vite's build folder is `public/build` but Laravel's base path is `public`.
162+
*
163+
* This option will be used to configure the path for the `service worker`, `registerSW.js` and the web manifest assets.
164+
*
165+
* For example, if your base path is `/`, then, in your Laravel PWA configuration use `buildPath: '/build/'`.
166+
*
167+
* By default: `vite.base`.
168+
*/
169+
buildBase?: string
158170
}
159171

160172
export interface ResolvedVitePWAOptions extends Required<VitePWAOptions> {
@@ -426,4 +438,10 @@ export interface DevOptions {
426438
* @see navigateFallbackAllowlist
427439
*/
428440
webManifestUrl?: string
441+
/**
442+
* Where to store generated service worker in development when using `generateSW` strategy.
443+
*
444+
* Use it with caution, it should be used only by framework integrations.
445+
*/
446+
resolveTempFolder?: () => string | Promise<string>
429447
}

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export function slash(str: string) {
22
return str.replace(/\\/g, '/')
33
}
44

5-
export function resolveBathPath(base: string) {
5+
export function resolveBasePath(base: string) {
66
if (isAbsolute(base))
77
return base
88
return !base.startsWith('/') && !base.startsWith('./')

0 commit comments

Comments
 (0)