Skip to content

Commit

Permalink
feat: add Nuxt v4 template (#18)
Browse files Browse the repository at this point in the history
* feat: add Nuxt v4 template

* chore: update nuxt pwa version

* chore: include pwa install prompt also for nuxt v4 temaplte

* chore: update dependencies

* chore: update readme and todo

* chore: update pending tasks
  • Loading branch information
userquin committed Jul 29, 2024
1 parent 337e427 commit 72b00a4
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 52 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Our plan is to release the first version when all Vite templates are ready:

Later we will add support for meta-frameworks:
- [x] `Nuxt 3` template (from `v0.1.0`)
- [x] `Nuxt 3 Compatibility Version 4 (Nuxt 4)` template (from `v0.4.0`)
- [x] `SvelteKit` template (from `v0.2.0`)
- [ ] `Astro` template
- [x] `Remix` template (from `v0.3.0`)
Expand Down
6 changes: 4 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
- [x] `react` and `react-ts` templates
- [x] `preact` and `preact-ts` templates
- [x] `solid` and `solid-ts` templates
- [x] `nuxt` template (from `v0.1.0`)
- [x] `nuxt 3` template (from `v0.1.0`)
- [x] `nuxt 3 v4-compat` template (from `v0.4.0`)
- [x] `sveltekit` template (from `v0.2.0`)
- [ ] `astro` template
- [x] `remix` template (from `v0.3.0`)
Expand All @@ -28,7 +29,8 @@
- [x] `react` and `react-ts` templates
- [x] `preact` and `preact-ts` templates
- [x] `solid` and `solid-ts` templates
- [x] `nuxt` template
- [x] `nuxt 3` template
- [x] `nuxt 3 v4-compat` template
- [x] `sveltekit` template
- [ ] `astro` template
- [x] `remix` template
Expand Down
5 changes: 4 additions & 1 deletion src/customize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ export async function customize(prompts: PromptsData) {
await import('./svelte').then(({ customize }) => customize(prompts))
break
case 'custom-nuxt':
await import('./nuxt').then(({ customize }) => customize(prompts))
await import('./nuxt').then(({ customize }) => customize(prompts, false))
break
case 'custom-nuxt-v4':
await import('./nuxt').then(({ customize }) => customize(prompts, true))
break
case 'custom-remix':
await import('./remix').then(({ customize }) => customize(prompts))
Expand Down
161 changes: 117 additions & 44 deletions src/customize/nuxt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@ import {
WorkboxVersion,
} from '../versions'

export async function customize(prompts: PromptsData) {
export async function customize(prompts: PromptsData, v4: boolean) {
const {
cdProjectName,
templateDir,
rootPath,
templateDir: templateDirFolder,
rootPath: outputRootPath,
customServiceWorker,
prompt,
pwaAssets,
} = prompts
const [rootPath, templateDir] = getPaths(outputRootPath, templateDirFolder, v4)
// cleanup target folder
fs.rmSync(path.join(rootPath, 'app.vue'), { recursive: true })
fs.rmSync(path.join(rootPath, 'nuxt.config.ts'), { recursive: true })
fs.rmSync(path.join(rootPath, 'public'), { recursive: true })
fs.rmSync(path.join(outputRootPath, 'nuxt.config.ts'), { recursive: true })
fs.rmSync(path.join(outputRootPath, 'public'), { recursive: true })
// extract template-nuxt folder
fs.copyFileSync(path.join(templateDir, 'app.vue'), path.join(rootPath, 'app.vue'))
fs.mkdirSync(path.join(rootPath, 'layouts'))
Expand All @@ -44,28 +45,51 @@ export async function customize(prompts: PromptsData) {
path.join(templateDir, 'pages', 'index.vue'),
path.join(rootPath, 'pages', 'index.vue'),
)
fs.mkdirSync(path.join(rootPath, 'public'))
fs.copyFileSync(path.join(templateDir, 'public', 'favicon.svg'), path.join(rootPath, 'public', 'favicon.svg'))
fs.copyFileSync(path.join(templateDir, 'pwa-assets.config.ts'), path.join(rootPath, 'pwa-assets.config.ts'))
fs.mkdirSync(path.join(outputRootPath, 'public'))
fs.copyFileSync(path.join(templateDir, 'public', 'favicon.svg'), path.join(outputRootPath, 'public', 'favicon.svg'))

// v4 root inside app: public folder on root
if (v4 && pwaAssets) {
const pwaAssets = fs.readFileSync(path.join(templateDir, 'pwa-assets.config.ts'), 'utf-8')
fs.writeFileSync(
path.join(outputRootPath, 'app/pwa-assets.config.ts'),
pwaAssets.replace('images: [\'public/favicon.svg\'],', 'images: [\'../public/favicon.svg\'],'),
'utf-8',
)
}
else {
fs.copyFileSync(path.join(templateDir, 'pwa-assets.config.ts'), path.join(outputRootPath, 'pwa-assets.config.ts'))
}

if (customServiceWorker) {
fs.mkdirSync(path.join(rootPath, 'service-worker'))
fs.copyFileSync(
path.join(templateDir, 'service-worker', `${prompt ? 'prompt' : 'claims'}-sw.ts`),
path.join(rootPath, 'service-worker', 'sw.ts'),
)
fs.copyFileSync(
path.join(templateDir, 'service-worker', 'tsconfig.json'),
path.join(rootPath, 'service-worker', 'tsconfig.json'),
)
if (v4) {
const tsConfig = fs.readFileSync(path.join(templateDir, 'service-worker', 'tsconfig.json'), 'utf-8')
fs.writeFileSync(
path.join(rootPath, 'service-worker', 'tsconfig.json'),
tsConfig.replace('"extends": "../tsconfig.json",', '"extends": "../../tsconfig.json",'),
'utf-8',
)
}
else {
fs.copyFileSync(
path.join(templateDir, 'service-worker', 'tsconfig.json'),
path.join(rootPath, 'service-worker', 'tsconfig.json'),
)
}
}

// create nuxt.config.ts
createNuxtConf(prompts)
createNuxtConf(prompts, v4)

// prepare package.json
const pkg = JSON.parse(fs.readFileSync(path.join(rootPath, 'package.json'), 'utf-8'))
const pkg = JSON.parse(fs.readFileSync(path.join(outputRootPath, 'package.json'), 'utf-8'))

const pkgManager = await detectPackageManager(rootPath).then(res => res?.name || 'npm')
const pkgManager = await detectPackageManager(outputRootPath).then(res => res?.name || 'npm')

// dependencies
pkg.dependencies ??= {}
Expand Down Expand Up @@ -95,10 +119,10 @@ export async function customize(prompts: PromptsData) {
includeDependencies(prompts, pkgManager === 'npm', pkg, true)

// save package.json
fs.writeFileSync(path.join(rootPath, 'package.json'), JSON.stringify(pkg, null, 2), 'utf-8')
fs.writeFileSync(path.join(outputRootPath, 'package.json'), JSON.stringify(pkg, null, 2), 'utf-8')

console.log('\n\nPWA configuration done. Now run:\n')
if (rootPath !== process.cwd()) {
if (outputRootPath !== process.cwd()) {
console.log(
` cd ${
cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName
Expand All @@ -122,7 +146,7 @@ export async function customize(prompts: PromptsData) {
console.log()
}

function createNuxtConf(prompts: PromptsData) {
function createNuxtConf(prompts: PromptsData, v4: boolean) {
const {
rootPath,
customServiceWorker,
Expand Down Expand Up @@ -157,32 +181,7 @@ function createNuxtConf(prompts: PromptsData) {
pwaOptions.client.installPrompt = true
}

const nuxtConf = customServiceWorker
? parseModule(`// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
typescript: {
tsConfig: {
exclude: ['../service-worker'],
},
},
devtools: { enabled: true },
nitro: {
prerender: {
routes: ['/'],
},
},
})
`)
: parseModule(`// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
nitro: {
prerender: {
routes: ['/'],
},
},
})
`)
const nuxtConf = prepareNuxtConf(customServiceWorker === true, v4)
addNuxtModule(nuxtConf, '@vite-pwa/nuxt', 'pwa', pwaOptions)
fs.writeFileSync(
path.join(rootPath, 'nuxt.config.ts'),
Expand Down Expand Up @@ -313,3 +312,77 @@ function createLayout(prompts: PromptsData) {

return content
}

function prepareNuxtConfV3(customServiceWorker: boolean): ReturnType<typeof parseModule> {
return customServiceWorker
? parseModule(`// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
typescript: {
tsConfig: {
exclude: ['../service-worker'],
},
},
devtools: { enabled: true },
nitro: {
prerender: {
routes: ['/'],
},
},
})
`)
: parseModule(`// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
nitro: {
prerender: {
routes: ['/'],
},
},
})
`)
}

function prepareNuxtConfV4(customServiceWorker: boolean): ReturnType<typeof parseModule> {
return customServiceWorker
? parseModule(`// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
future: {
compatibilityVersion: 4
},
typescript: {
tsConfig: {
exclude: ['../app/service-worker'],
},
},
devtools: { enabled: true },
nitro: {
prerender: {
routes: ['/'],
},
},
})
`)
: parseModule(`// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
future: {
compatibilityVersion: 4
},
devtools: { enabled: true },
nitro: {
prerender: {
routes: ['/'],
},
},
})
`)
}

function getPaths(rootPath: string, templateDir: string, v4: boolean): [rootPath: string, templateDir: string] {
return v4
? [path.join(rootPath, 'app'), templateDir.replace('template-custom-nuxt-v4', 'template-custom-nuxt')]
: [rootPath, templateDir]
}

function prepareNuxtConf(customSW: boolean, v4: boolean): ReturnType<typeof parseModule> {
return v4 ? prepareNuxtConfV4(customSW) : prepareNuxtConfV3(customSW)
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ async function init() {
inactive: 'no',
},
{
type: (_, { variant }) => variant === 'custom-nuxt' ? 'toggle' : null,
type: (_, { variant }) => variant === 'custom-nuxt' || variant === 'custom-nuxt-v4' ? 'toggle' : null,
name: 'installPWA',
message: reset('Add PWA Install Prompt?'),
initial: false,
Expand Down
7 changes: 7 additions & 0 deletions src/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ export const FRAMEWORKS = (<Framework[]>[
customCommand: 'npm exec nuxi init TARGET_DIR',
enabled: true,
},
{
name: 'custom-nuxt-v4',
display: 'Nuxt 4 ↗',
color: cyan,
customCommand: 'npx nuxi@latest init -t v4-compat TARGET_DIR',
enabled: true,
},
],
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface Framework {

export type FrameworkVariantKey =
| 'vanilla' | 'vanilla-ts'
| 'vue' | 'vue-ts' | 'custom-nuxt'
| 'vue' | 'vue-ts' | 'custom-nuxt' | 'custom-nuxt-v4'
| 'react' | 'react-ts'
| 'preact' | 'preact-ts'
| 'svelte' | 'svelte-ts' | 'custom-svelte-kit'
Expand Down
6 changes: 3 additions & 3 deletions src/versions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export const WorkboxVersion = '^7.1.0'
export const VitePluginPWAVersion = '^0.20.0'
export const VitePluginPWAVersion = '^0.20.1'
export const PWAAssetsVersion = '^0.2.4'
export const NuxtPWAModuleVersion = '^0.7.0'
export const SvelteKitPWAVersion = '^0.5.0'
export const NuxtPWAModuleVersion = '^0.9.1'
export const SvelteKitPWAVersion = '^0.6.0'
export const RemixPWAVersion = '^0.1.0'
export const TypeScriptVersion = '^5.4.5'
export const VueTscVersion = '^2.0.16'
Expand Down

0 comments on commit 72b00a4

Please sign in to comment.