@@ -15,6 +15,7 @@ import {
1515 StyleCompileResult ,
1616 DescriptorCompileResult
1717} from '@vue/component-compiler'
18+ import MagicString from 'magic-string'
1819import { Plugin , RawSourceMap } from 'rollup'
1920import * as path from 'path'
2021import { parse , SFCDescriptor , SFCBlock } from '@vue/component-compiler-utils'
@@ -33,6 +34,15 @@ const dR = debug('rollup-plugin-vue:resolve')
3334const dL = debug ( 'rollup-plugin-vue:load' )
3435const dT = debug ( 'rollup-plugin-vue:transform' )
3536
37+ export interface VuePluginOptionsData {
38+ css : string | ( ( ) => string )
39+ less : string | ( ( ) => string )
40+ postcss : string | ( ( ) => string )
41+ sass : string | ( ( ) => string )
42+ scss : string | ( ( ) => string )
43+ stylus : string | ( ( ) => string )
44+ }
45+
3646export interface VuePluginOptions {
3747 /**
3848 * Include files or directories.
@@ -65,6 +75,17 @@ export interface VuePluginOptions {
6575 * ```
6676 */
6777 customBlocks ?: string [ ] | ( ( tag : string ) => boolean )
78+
79+ /**
80+ * Prepend CSS.
81+ * @default `undefined`
82+ * @example
83+ * ```js
84+ * VuePlugin({ data: { scss: '$color: red;' } }) // to extract css
85+ * ```
86+ */
87+ data ?: Partial < VuePluginOptionsData >
88+
6889 /**
6990 * Inject CSS in JavaScript.
7091 * @default `true`
@@ -153,6 +174,9 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
153174 const exposeFilename =
154175 typeof opts . exposeFilename === 'boolean' ? opts . exposeFilename : false
155176
177+ const data : VuePluginOptionsData = ( opts . data || { } ) as any
178+
179+ delete opts . data
156180 delete opts . beforeAssemble
157181 delete opts . css
158182 delete opts . exposeFilename
@@ -180,6 +204,26 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
180204
181205 if ( opts . css === false ) d ( 'Running in CSS extract mode' )
182206
207+ function prependStyle (
208+ id : string ,
209+ lang : string ,
210+ code : string ,
211+ map : any
212+ ) : { code : string } {
213+ if ( ! ( lang in data ) ) return { code }
214+ const ms = new MagicString ( code , {
215+ filename : id ,
216+ indentExclusionRanges : [ ]
217+ } )
218+
219+ const value : string | ( ( ) => string ) = ( data as any ) [ lang ]
220+ const fn = typeof value === 'function' ? value : ( ) => value
221+
222+ ms . prepend ( fn ( ) )
223+
224+ return { code : ms . toString ( ) }
225+ }
226+
183227 return {
184228 name : 'VuePlugin' ,
185229
@@ -193,6 +237,7 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
193237 if ( ! isVuePartRequest ( id ) ) return
194238 id = path . resolve ( path . dirname ( importer ) , id )
195239 const ref = parseVuePartRequest ( id )
240+
196241 if ( ref ) {
197242 const element = resolveVuePart ( descriptors , ref )
198243 const src = ( element as SFCBlock ) . src
@@ -217,11 +262,15 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
217262 if ( ! request ) return null
218263
219264 const element = resolveVuePart ( descriptors , request )
220- const code =
265+ let code =
221266 'code' in element
222267 ? ( ( element as any ) . code as string ) // .code is set when extract styles is used. { css: false }
223268 : element . content
224- const map = element . map as RawSourceMap
269+ let map = element . map as RawSourceMap
270+
271+ if ( request . meta . type === 'styles' ) {
272+ code = prependStyle ( id , request . meta . lang , code , map ) . code
273+ }
225274
226275 dL ( `id: ${ id } \ncode: \n${ code } \nmap: ${ JSON . stringify ( map , null , 2 ) } \n\n` )
227276
@@ -254,6 +303,15 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
254303
255304 const styles = await Promise . all (
256305 descriptor . styles . map ( async style => {
306+ if ( style . content ) {
307+ style . content = prependStyle (
308+ filename ,
309+ style . lang || 'css' ,
310+ style . content ,
311+ style . map
312+ ) . code
313+ }
314+
257315 const compiled = await compiler . compileStyleAsync (
258316 filename ,
259317 scopeId ,
@@ -382,7 +440,10 @@ function createCustomBlockFilter(
382440 customBlocks . filter ( tag => tag . startsWith ( '!' ) ) . map ( tag => tag . substr ( 1 ) )
383441 )
384442
385- return tag =>
386- ( allowed . has ( '*' ) || allowed . has ( tag ) ) &&
387- ! ( notAllowed . has ( '*' ) || notAllowed . has ( tag ) )
443+ return tag => {
444+ if ( allowed . has ( tag ) ) return true
445+ if ( notAllowed . has ( tag ) ) return false
446+ if ( notAllowed . has ( '*' ) ) return false
447+ return allowed . has ( '*' )
448+ }
388449}
0 commit comments