@@ -5,39 +5,18 @@ import { createUnplugin } from 'unplugin'
5
5
import MagicString from 'magic-string'
6
6
import { createFilter , makeLegalIdentifier } from '@rollup/pluginutils'
7
7
8
- import type { ExternalPluginOptions , InsertInfo } from '../types'
8
+ import type { ExternalPluginOptions } from '../types'
9
+ import { isCustomBlock , parseVueRequest } from '../loader-query'
9
10
import { getSyntaxErrors } from './ftl/parse'
10
11
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
- return {
25
- target : '_sfc_main' ,
26
- insertPos : source . indexOf ( 'export default' ) ,
27
- usePos : source . indexOf ( '_export_sfc(_sfc_main, [' ) + 24 ,
28
- }
29
- }
30
-
31
- // vue-loader
32
- if ( source . includes ( '__exports__' ) )
33
- target = '__exports__'
34
-
35
- const insertPos = source . indexOf ( 'export default' )
36
-
37
- if ( insertPos === - 1 || target === null )
38
- 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' ] )
39
14
40
- return { insertPos, target }
15
+ interface Dependency {
16
+ locale : string
17
+ ftlPath : string
18
+ relativeFtlPath : string
19
+ importVariable : string
41
20
}
42
21
43
22
async function fileExists ( filename : string ) : Promise < boolean > {
@@ -54,17 +33,7 @@ function normalizePath(path: string) {
54
33
return path . replace ( / \\ / g, '/' )
55
34
}
56
35
57
- const isVue = createFilter ( [ '**/*.vue' ] )
58
- const isFtl = createFilter ( [ '**/*.ftl' ] )
59
-
60
- interface Dependency {
61
- locale : string
62
- ftlPath : string
63
- relativeFtlPath : string
64
- importVariable : string
65
- }
66
-
67
- export const unplugin = createUnplugin ( ( options : ExternalPluginOptions , meta ) => {
36
+ export const unplugin = createUnplugin ( ( options : ExternalPluginOptions ) => {
68
37
const resolvedOptions = {
69
38
checkSyntax : true ,
70
39
virtualModuleName : 'virtual:ftl-for-file' ,
@@ -81,38 +50,6 @@ export const unplugin = createUnplugin((options: ExternalPluginOptions, meta) =>
81
50
}
82
51
}
83
52
84
- const insertFtlImports = ( magic : MagicString , translations : Dependency [ ] ) => {
85
- for ( const dep of translations )
86
- magic . prepend ( `import ${ dep . importVariable } from '${ dep . relativeFtlPath } ';\n` )
87
- }
88
-
89
- const insertHotCode = ( magic : MagicString , translations : Dependency [ ] , target : string , insertPos : number ) => {
90
- const __HOT_API__ = meta . framework === 'webpack' ? 'import.meta.webpackHot' : 'import.meta.hot'
91
-
92
- magic . appendLeft ( insertPos , `
93
- if (${ __HOT_API__ } ) {
94
- ${ __HOT_API__ } .accept([${ translations . map ( dep => `'${ dep . relativeFtlPath } '` ) . join ( ', ' ) } ], (mods) => {
95
- ${ translations . map ( ( { locale, importVariable } ) => `${ target } .fluent['${ locale } '] = ${ importVariable } ` ) . join ( '\n' ) }
96
-
97
- if (mods) {
98
- ${ translations . map ( ( { locale } , index ) => `if (mods['${ index } ']) ${ target } .fluent['${ locale } '] = mods['${ index } '].default` ) . join ( '\n' ) }
99
- }
100
-
101
- delete ${ target } ._fluent
102
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
103
- // Vue 3
104
- __VUE_HMR_RUNTIME__.reload(${ target } .__hmrId, ${ target } )
105
- } else {
106
- // Vue 2
107
- // There is no proper api to access HMR for component from custom block
108
- // so use this magic
109
- delete ${ target } ._Ctor
110
- }
111
- })
112
- }
113
- ` )
114
- }
115
-
116
53
const getTranslationsForFile = async ( id : string ) => {
117
54
const dependencies : Dependency [ ] = [ ]
118
55
for ( const locale of options . locales ) {
@@ -135,13 +72,21 @@ if (${__HOT_API__}) {
135
72
return dependencies
136
73
}
137
74
75
+ const isFluentCustomBlock = ( id : string ) => {
76
+ const request = parseVueRequest ( id )
77
+ return isCustomBlock ( request . query , { blockType : 'fluent' } )
78
+ }
79
+
138
80
return {
139
81
name : 'unplugin-fluent-vue-external' ,
140
- enforce : meta . framework === 'webpack' ? 'post' : undefined ,
82
+ enforce : 'pre' ,
141
83
resolveId ( id , importer ) {
142
84
if ( id === resolvedOptions . virtualModuleName )
143
85
return `${ id } ?importer=${ importer } `
144
86
} ,
87
+ loadInclude ( id : string ) {
88
+ return id . startsWith ( resolvedOptions . virtualModuleName )
89
+ } ,
145
90
async load ( id ) {
146
91
if ( ! id . startsWith ( resolvedOptions . virtualModuleName ) )
147
92
return
@@ -164,34 +109,19 @@ if (${__HOT_API__}) {
164
109
return code
165
110
} ,
166
111
transformInclude ( id : string ) {
167
- return isVue ( id ) || isFtl ( id )
112
+ return isVue ( id ) || isFtl ( id ) || isFluentCustomBlock ( id )
168
113
} ,
169
114
async transform ( source : string , id : string ) {
170
115
if ( isVue ( id ) ) {
171
116
const magic = new MagicString ( source , { filename : id } )
172
117
173
- const { insertPos, target, usePos } = getInsertInfo ( source )
174
-
175
118
const translations = await getTranslationsForFile ( id )
176
119
177
120
if ( translations . length === 0 )
178
121
return
179
122
180
- for ( const { ftlPath } of translations )
181
- this . addWatchFile ( ftlPath )
182
-
183
- insertFtlImports ( magic , translations )
184
-
185
- if ( usePos == null ) {
186
- magic . appendLeft ( insertPos , `${ target } .fluent = ${ target } .fluent || {};\n` )
187
- for ( const dep of translations )
188
- magic . appendLeft ( insertPos , `${ target } .fluent['${ dep . locale } '] = ${ dep . importVariable } \n` )
189
- }
190
- else {
191
- magic . appendRight ( usePos , `['fluent',{${ translations . map ( dep => `'${ dep . locale } ':${ dep . importVariable } ` ) . join ( ',' ) } }],` )
192
- }
193
-
194
- insertHotCode ( magic , translations , target , insertPos )
123
+ for ( const { relativeFtlPath, locale } of translations )
124
+ magic . append ( `<fluent locale="${ locale } " src="${ relativeFtlPath } "></fluent>\n` )
195
125
196
126
return {
197
127
code : magic . toString ( ) ,
@@ -212,6 +142,24 @@ export default /*#__PURE__*/ new FluentResource(${JSON.stringify(source)})
212
142
`
213
143
}
214
144
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
+
215
163
return undefined
216
164
} ,
217
165
}
0 commit comments