2022-09-29 11:25:45 +08:00
import type { Options as VueOptions } from '@vitejs/plugin-vue' ;
2022-09-29 03:28:21 +00:00
import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx' ;
2023-12-06 04:07:28 +08:00
import type { AstroIntegration , AstroIntegrationLogger , AstroRenderer } from 'astro' ;
2023-12-05 18:38:29 -06:00
import type { UserConfig , Plugin } from 'vite' ;
2023-12-06 04:07:28 +08:00
import { fileURLToPath } from 'node:url' ;
import vue from '@vitejs/plugin-vue' ;
2022-03-18 15:35:45 -07:00
2022-09-29 11:25:45 +08:00
interface Options extends VueOptions {
jsx? : boolean | VueJsxOptions ;
2022-10-13 14:15:57 -05:00
appEntrypoint? : string ;
2022-09-29 11:25:45 +08:00
}
2023-12-06 04:07:28 +08:00
interface ViteOptions extends Options {
root : URL ;
logger : AstroIntegrationLogger ;
}
2022-03-18 15:35:45 -07:00
function getRenderer ( ) : AstroRenderer {
return {
name : '@astrojs/vue' ,
clientEntrypoint : '@astrojs/vue/client.js' ,
serverEntrypoint : '@astrojs/vue/server.js' ,
} ;
}
2022-09-29 11:25:45 +08:00
function getJsxRenderer ( ) : AstroRenderer {
2022-03-18 15:35:45 -07:00
return {
2022-09-29 11:25:45 +08:00
name : '@astrojs/vue (jsx)' ,
clientEntrypoint : '@astrojs/vue/client.js' ,
serverEntrypoint : '@astrojs/vue/server.js' ,
jsxImportSource : 'vue' ,
jsxTransformOptions : async ( ) = > {
const jsxPlugin = ( await import ( '@vue/babel-plugin-jsx' ) ) . default ;
return {
plugins : [ jsxPlugin ] ,
} ;
} ,
} ;
}
2023-12-06 04:07:28 +08:00
function virtualAppEntrypoint ( options : ViteOptions ) {
2022-10-13 14:15:57 -05:00
const virtualModuleId = 'virtual:@astrojs/vue/app' ;
const resolvedVirtualModuleId = '\0' + virtualModuleId ;
2023-12-05 18:38:29 -06:00
let getExports : ( id : string ) = > Promise < string [ ] > ;
2022-10-13 14:15:57 -05:00
return {
name : '@astrojs/vue/virtual-app' ,
2023-12-05 18:38:29 -06:00
buildStart() {
if ( ! getExports ) {
getExports = async ( id : string ) = > {
const info = await this . load . call ( this , { id } ) ;
return info . exports ? ? [ ] ;
2023-12-06 00:39:39 +00:00
} ;
2023-12-05 18:38:29 -06:00
}
} ,
configureServer ( server ) {
if ( ! getExports ) {
getExports = async ( id : string ) = > {
const mod = await server . ssrLoadModule ( id ) ;
return Object . keys ( mod ) ? ? [ ] ;
2023-12-06 00:39:39 +00:00
} ;
2023-12-05 18:38:29 -06:00
}
} ,
2022-10-13 14:15:57 -05:00
resolveId ( id : string ) {
if ( id == virtualModuleId ) {
return resolvedVirtualModuleId ;
}
} ,
2023-12-06 04:07:28 +08:00
async load ( id : string ) {
2023-12-05 18:38:29 -06:00
const noop = ` export const setup = (app) => app; ` ;
2022-10-13 14:15:57 -05:00
if ( id === resolvedVirtualModuleId ) {
2023-12-06 04:07:28 +08:00
if ( options . appEntrypoint ) {
try {
let resolved ;
if ( options . appEntrypoint . startsWith ( '.' ) ) {
2023-12-05 20:08:47 +00:00
resolved = await this . resolve (
fileURLToPath ( new URL ( options . appEntrypoint , options . root ) )
) ;
2023-12-06 04:07:28 +08:00
} else {
resolved = await this . resolve ( options . appEntrypoint , fileURLToPath ( options . root ) ) ;
}
if ( ! resolved ) {
// This error is handled below, the message isn't shown to the user
throw new Error ( 'Unable to resolve appEntrypoint' ) ;
}
2023-12-05 18:38:29 -06:00
const exports = await getExports ( resolved . id ) ;
if ( ! exports . includes ( 'default' ) ) {
2023-12-06 04:07:28 +08:00
options . logger . warn (
` appEntrypoint \` ${ options . appEntrypoint } \` does not export a default function. Check out https://docs.astro.build/en/guides/integrations-guide/vue/#appentrypoint. `
) ;
return noop ;
}
return ` export { default as setup } from " ${ resolved . id } "; ` ;
} catch {
2023-12-05 20:08:47 +00:00
options . logger . warn (
` Unable to resolve appEntrypoint \` ${ options . appEntrypoint } \` . Does the file exist? `
) ;
2023-12-06 04:07:28 +08:00
}
2022-10-13 14:15:57 -05:00
}
2023-12-06 04:07:28 +08:00
return noop ;
2022-10-13 14:15:57 -05:00
}
2023-12-05 20:08:47 +00:00
} ,
2023-12-05 18:38:29 -06:00
} satisfies Plugin ;
2022-10-13 14:15:57 -05:00
}
2023-12-06 04:07:28 +08:00
async function getViteConfiguration ( options : ViteOptions ) : Promise < UserConfig > {
2022-09-29 11:25:45 +08:00
const config : UserConfig = {
2022-03-18 15:35:45 -07:00
optimizeDeps : {
include : [ '@astrojs/vue/client.js' , 'vue' ] ,
2022-10-13 19:17:42 +00:00
exclude : [ '@astrojs/vue/server.js' , 'virtual:@astrojs/vue/app' ] ,
2022-03-18 15:35:45 -07:00
} ,
2022-10-13 14:15:57 -05:00
plugins : [ vue ( options ) , virtualAppEntrypoint ( options ) ] ,
2022-03-18 15:35:45 -07:00
ssr : {
external : [ '@vue/server-renderer' ] ,
2022-12-09 11:46:21 -05:00
noExternal : [ 'vuetify' , 'vueperslides' , 'primevue' ] ,
2022-03-18 15:35:45 -07:00
} ,
} ;
2022-09-29 11:25:45 +08:00
if ( options ? . jsx ) {
const vueJsx = ( await import ( '@vitejs/plugin-vue-jsx' ) ) . default ;
const jsxOptions = typeof options . jsx === 'object' ? options.jsx : undefined ;
config . plugins ? . push ( vueJsx ( jsxOptions ) ) ;
}
return config ;
2022-03-18 15:35:45 -07:00
}
2022-04-19 16:31:32 +00:00
export default function ( options? : Options ) : AstroIntegration {
2022-03-18 15:35:45 -07:00
return {
name : '@astrojs/vue' ,
hooks : {
2023-12-06 04:07:28 +08:00
'astro:config:setup' : async ( { addRenderer , updateConfig , config , logger } ) = > {
2022-03-18 15:35:45 -07:00
addRenderer ( getRenderer ( ) ) ;
2022-09-29 11:25:45 +08:00
if ( options ? . jsx ) {
addRenderer ( getJsxRenderer ( ) ) ;
}
2023-12-06 04:07:28 +08:00
updateConfig ( {
vite : await getViteConfiguration ( { . . . options , root : config.root , logger } ) ,
} ) ;
2022-03-18 15:35:45 -07:00
} ,
} ,
} ;
}