@@ -5,34 +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
- 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' ] )
34
14
35
- return { insertPos, target }
15
+ interface Dependency {
16
+ locale : string
17
+ ftlPath : string
18
+ relativeFtlPath : string
19
+ importVariable : string
36
20
}
37
21
38
22
async function fileExists ( filename : string ) : Promise < boolean > {
@@ -49,17 +33,7 @@ function normalizePath(path: string) {
49
33
return path . replace ( / \\ / g, '/' )
50
34
}
51
35
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 ) => {
63
37
const resolvedOptions = {
64
38
checkSyntax : true ,
65
39
virtualModuleName : 'virtual:ftl-for-file' ,
@@ -76,38 +50,6 @@ export const unplugin = createUnplugin((options: ExternalPluginOptions, meta) =>
76
50
}
77
51
}
78
52
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
-
111
53
const getTranslationsForFile = async ( id : string ) => {
112
54
const dependencies : Dependency [ ] = [ ]
113
55
for ( const locale of options . locales ) {
@@ -130,13 +72,21 @@ if (${__HOT_API__}) {
130
72
return dependencies
131
73
}
132
74
75
+ const isFluentCustomBlock = ( id : string ) => {
76
+ const request = parseVueRequest ( id )
77
+ return isCustomBlock ( request . query , { blockType : 'fluent' } )
78
+ }
79
+
133
80
return {
134
81
name : 'unplugin-fluent-vue-external' ,
135
- enforce : meta . framework === 'webpack' ? 'post' : undefined ,
82
+ enforce : 'pre' ,
136
83
resolveId ( id , importer ) {
137
84
if ( id === resolvedOptions . virtualModuleName )
138
85
return `${ id } ?importer=${ importer } `
139
86
} ,
87
+ loadInclude ( id : string ) {
88
+ return id . startsWith ( resolvedOptions . virtualModuleName )
89
+ } ,
140
90
async load ( id ) {
141
91
if ( ! id . startsWith ( resolvedOptions . virtualModuleName ) )
142
92
return
@@ -159,29 +109,19 @@ if (${__HOT_API__}) {
159
109
return code
160
110
} ,
161
111
transformInclude ( id : string ) {
162
- return isVue ( id ) || isFtl ( id )
112
+ return isVue ( id ) || isFtl ( id ) || isFluentCustomBlock ( id )
163
113
} ,
164
114
async transform ( source : string , id : string ) {
165
115
if ( isVue ( id ) ) {
166
116
const magic = new MagicString ( source , { filename : id } )
167
117
168
- const { insertPos, target } = getInsertInfo ( source )
169
-
170
118
const translations = await getTranslationsForFile ( id )
171
119
172
120
if ( translations . length === 0 )
173
121
return
174
122
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` )
185
125
186
126
return {
187
127
code : magic . toString ( ) ,
@@ -198,10 +138,28 @@ if (${__HOT_API__}) {
198
138
199
139
return `
200
140
import { FluentResource } from '@fluent/bundle'
201
- export default new FluentResource(${ JSON . stringify ( source ) } )
141
+ export default /*#__PURE__*/ new FluentResource(${ JSON . stringify ( source ) } )
202
142
`
203
143
}
204
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
+
205
163
return undefined
206
164
} ,
207
165
}
0 commit comments