@@ -5,34 +5,18 @@ import { createUnplugin } from 'unplugin'
55import MagicString from 'magic-string'
66import { createFilter , makeLegalIdentifier } from '@rollup/pluginutils'
77
8- import type { ExternalPluginOptions , InsertInfo } from '../types'
8+ import type { ExternalPluginOptions } from '../types'
9+ import { isCustomBlock , parseVueRequest } from '../loader-query'
910import { getSyntaxErrors } from './ftl/parse'
1011
11- function getInsertInfo ( source : string ) : InsertInfo {
12- let target = null
13-
14- // vite-plugin-vue2
15- if ( source . includes ( '__component__' ) )
16- target = '__component__'
17-
18- // rollup-plugin-vue
19- if ( source . includes ( 'export default script' ) )
20- target = 'script'
21-
22- // @vitejs /plugin-vue
23- if ( source . includes ( '_sfc_main' ) )
24- target = '_sfc_main'
25-
26- // vue-loader
27- if ( source . includes ( '__exports__' ) )
28- target = '__exports__'
29-
30- const insertPos = source . indexOf ( 'export default' )
31-
32- if ( insertPos === - 1 || target === null )
33- throw new Error ( 'Could not parse vue component. This is the issue with unplugin-fluent-vue.\nPlease report this issue to the unplugin-fluent-vue repository.' )
12+ const isVue = createFilter ( [ '**/*.vue' ] )
13+ const isFtl = createFilter ( [ '**/*.ftl' ] )
3414
35- return { insertPos, target }
15+ interface Dependency {
16+ locale : string
17+ ftlPath : string
18+ relativeFtlPath : string
19+ importVariable : string
3620}
3721
3822async function fileExists ( filename : string ) : Promise < boolean > {
@@ -49,17 +33,7 @@ function normalizePath(path: string) {
4933 return path . replace ( / \\ / g, '/' )
5034}
5135
52- const isVue = createFilter ( [ '**/*.vue' ] )
53- const isFtl = createFilter ( [ '**/*.ftl' ] )
54-
55- interface Dependency {
56- locale : string
57- ftlPath : string
58- relativeFtlPath : string
59- importVariable : string
60- }
61-
62- export const unplugin = createUnplugin ( ( options : ExternalPluginOptions , meta ) => {
36+ export const unplugin = createUnplugin ( ( options : ExternalPluginOptions ) => {
6337 const resolvedOptions = {
6438 checkSyntax : true ,
6539 virtualModuleName : 'virtual:ftl-for-file' ,
@@ -76,38 +50,6 @@ export const unplugin = createUnplugin((options: ExternalPluginOptions, meta) =>
7650 }
7751 }
7852
79- const insertFtlImports = ( magic : MagicString , translations : Dependency [ ] ) => {
80- for ( const dep of translations )
81- magic . prepend ( `import ${ dep . importVariable } from '${ dep . relativeFtlPath } ';\n` )
82- }
83-
84- const insertHotCode = ( magic : MagicString , translations : Dependency [ ] , target : string , insertPos : number ) => {
85- const __HOT_API__ = meta . framework === 'webpack' ? 'import.meta.webpackHot' : 'import.meta.hot'
86-
87- magic . appendLeft ( insertPos , `
88- if (${ __HOT_API__ } ) {
89- ${ __HOT_API__ } .accept([${ translations . map ( dep => `'${ dep . relativeFtlPath } '` ) . join ( ', ' ) } ], (mods) => {
90- ${ translations . map ( ( { locale, importVariable } ) => `${ target } .fluent['${ locale } '] = ${ importVariable } ` ) . join ( '\n' ) }
91-
92- if (mods) {
93- ${ translations . map ( ( { locale } , index ) => `if (mods['${ index } ']) ${ target } .fluent['${ locale } '] = mods['${ index } '].default` ) . join ( '\n' ) }
94- }
95-
96- delete ${ target } ._fluent
97- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
98- // Vue 3
99- __VUE_HMR_RUNTIME__.reload(${ target } .__hmrId, ${ target } )
100- } else {
101- // Vue 2
102- // There is no proper api to access HMR for component from custom block
103- // so use this magic
104- delete ${ target } ._Ctor
105- }
106- })
107- }
108- ` )
109- }
110-
11153 const getTranslationsForFile = async ( id : string ) => {
11254 const dependencies : Dependency [ ] = [ ]
11355 for ( const locale of options . locales ) {
@@ -130,13 +72,21 @@ if (${__HOT_API__}) {
13072 return dependencies
13173 }
13274
75+ const isFluentCustomBlock = ( id : string ) => {
76+ const request = parseVueRequest ( id )
77+ return isCustomBlock ( request . query , { blockType : 'fluent' } )
78+ }
79+
13380 return {
13481 name : 'unplugin-fluent-vue-external' ,
135- enforce : meta . framework === 'webpack' ? 'post' : undefined ,
82+ enforce : 'pre' ,
13683 resolveId ( id , importer ) {
13784 if ( id === resolvedOptions . virtualModuleName )
13885 return `${ id } ?importer=${ importer } `
13986 } ,
87+ loadInclude ( id : string ) {
88+ return id . startsWith ( resolvedOptions . virtualModuleName )
89+ } ,
14090 async load ( id ) {
14191 if ( ! id . startsWith ( resolvedOptions . virtualModuleName ) )
14292 return
@@ -159,29 +109,19 @@ if (${__HOT_API__}) {
159109 return code
160110 } ,
161111 transformInclude ( id : string ) {
162- return isVue ( id ) || isFtl ( id )
112+ return isVue ( id ) || isFtl ( id ) || isFluentCustomBlock ( id )
163113 } ,
164114 async transform ( source : string , id : string ) {
165115 if ( isVue ( id ) ) {
166116 const magic = new MagicString ( source , { filename : id } )
167117
168- const { insertPos, target } = getInsertInfo ( source )
169-
170118 const translations = await getTranslationsForFile ( id )
171119
172120 if ( translations . length === 0 )
173121 return
174122
175- for ( const { ftlPath } of translations )
176- this . addWatchFile ( ftlPath )
177-
178- insertFtlImports ( magic , translations )
179-
180- magic . appendLeft ( insertPos , `${ target } .fluent = ${ target } .fluent || {};\n` )
181- for ( const dep of translations )
182- magic . appendLeft ( insertPos , `${ target } .fluent['${ dep . locale } '] = ${ dep . importVariable } \n` )
183-
184- insertHotCode ( magic , translations , target , insertPos )
123+ for ( const { relativeFtlPath, locale } of translations )
124+ magic . append ( `<fluent locale="${ locale } " src="${ relativeFtlPath } "></fluent>\n` )
185125
186126 return {
187127 code : magic . toString ( ) ,
@@ -198,10 +138,28 @@ if (${__HOT_API__}) {
198138
199139 return `
200140import { FluentResource } from '@fluent/bundle'
201- export default new FluentResource(${ JSON . stringify ( source ) } )
141+ export default /*#__PURE__*/ new FluentResource(${ JSON . stringify ( source ) } )
202142`
203143 }
204144
145+ const query = parseVueRequest ( id ) . query
146+ if ( isFluentCustomBlock ( id ) ) {
147+ if ( options . checkSyntax ) {
148+ const errorsText = getSyntaxErrors ( source )
149+ if ( errorsText )
150+ this . error ( errorsText )
151+ }
152+
153+ return `
154+ import { FluentResource } from '@fluent/bundle'
155+
156+ export default function (Component) {
157+ const target = Component.options || Component
158+ target.fluent = target.fluent || {}
159+ target.fluent['${ query . locale } '] = new FluentResource(${ JSON . stringify ( source ) } )
160+ }`
161+ }
162+
205163 return undefined
206164 } ,
207165 }
0 commit comments