Skip to content
This repository was archived by the owner on Jan 18, 2022. It is now read-only.

Commit a5711f6

Browse files
committed
feat: Add data option to allow prepending style block content
Related #93
1 parent c61e6d6 commit a5711f6

File tree

5 files changed

+141
-15
lines changed

5 files changed

+141
-15
lines changed

docs/options.md

+23-9
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,26 @@ e.g.: `defaultLang: { script: 'ts' }` would set default `<script>` block languag
2929
`defaultLang` does not set default language in templates for your editor/IDE.
3030
:::
3131

32-
## `blackListCustomBlocks`
3332

34-
- type: `string[]`
35-
- default: `['*']`
33+
## `customBlocks`
3634

37-
Exclude custom block from final bundle.
35+
- type: `string[] | ((tag: string) => boolean)`
36+
- default: `() => false`
3837

39-
## `whiteListCustomBlocks`
38+
Include/exclude custom block in final bundle.
39+
e.g.
4040

41-
- type: `string[]`
42-
- default: `[]`
43-
44-
Include custom block in final bundle.
41+
``` js
42+
...
43+
VuePlugin({
44+
customBlocks: [
45+
'!docs', // exclude <docs>
46+
'gql', // include <gql>
47+
'!*', // exclude everything else
48+
]
49+
})
50+
...
51+
```
4552

4653
## `css`
4754

@@ -50,6 +57,13 @@ Include custom block in final bundle.
5057

5158
Inject CSS in JavaScript. Setting `css: false` would extract styles in a `.css` file.
5259

60+
## `data`
61+
62+
- type: `{ [lang: string]: string | (() => string)}`
63+
- default: `{}`
64+
65+
Prepend content to `<style>` blocks in `.vue` files.
66+
5367
## `compiler`
5468

5569
- type: [VueTemplateCompiler](https://github.com/vuejs/component-compiler-utils#parseparseoptions-sfcdescriptor)

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@vue/component-compiler-utils": "^2.1.0",
5050
"debug": "^4.1.1",
5151
"hash-sum": "^1.0.2",
52+
"magic-string": "^0.25.2",
5253
"querystring": "^0.2.0",
5354
"rollup-pluginutils": "^2.0.1",
5455
"source-map": "0.7.3",

src/index.ts

+66-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
StyleCompileResult,
1616
DescriptorCompileResult
1717
} from '@vue/component-compiler'
18+
import MagicString from 'magic-string'
1819
import { Plugin, RawSourceMap } from 'rollup'
1920
import * as path from 'path'
2021
import { parse, SFCDescriptor, SFCBlock } from '@vue/component-compiler-utils'
@@ -33,6 +34,15 @@ const dR = debug('rollup-plugin-vue:resolve')
3334
const dL = debug('rollup-plugin-vue:load')
3435
const 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+
3646
export 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
}

test/options/data.spec.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import vue, { VuePluginOptions } from '../../src'
2+
import { pluginInline } from '../setup/plugins'
3+
import { rollup } from 'rollup'
4+
5+
describe('data', () => {
6+
async function setup(options?: Partial<VuePluginOptions>) {
7+
return rollup({
8+
input: '/entry.vue',
9+
plugins: [
10+
pluginInline(
11+
'/entry.vue',
12+
`
13+
<template>
14+
<div>Hello, world</div>
15+
</template>
16+
<style scoped>
17+
div {
18+
color: red;
19+
}
20+
</style>
21+
`
22+
),
23+
vue({
24+
...options,
25+
normalizer: 'vue-runtime-helpers/dist/normalize-component.mjs',
26+
styleInjector: 'vue-runtime-helpers/dist/inject-style/browser.mjs',
27+
})
28+
]
29+
})
30+
.then(bundle => bundle.generate({ format: 'es' }))
31+
.then(generated => generated.output[0])
32+
}
33+
34+
it('prefix', async () => {
35+
const { code } = await setup({
36+
data: {
37+
css: '/*! © 2019 Jane Doe */\n'
38+
}
39+
})
40+
41+
expect(code).toEqual(expect.stringContaining('© 2019 Jane Doe'))
42+
})
43+
})

yarn.lock

+8-1
Original file line numberDiff line numberDiff line change
@@ -6604,6 +6604,13 @@ magic-string@^0.25.1:
66046604
dependencies:
66056605
sourcemap-codec "^1.4.1"
66066606

6607+
magic-string@^0.25.2:
6608+
version "0.25.2"
6609+
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.2.tgz#139c3a729515ec55e96e69e82a11fe890a293ad9"
6610+
integrity sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==
6611+
dependencies:
6612+
sourcemap-codec "^1.4.4"
6613+
66076614
make-dir@^1.0.0:
66086615
version "1.3.0"
66096616
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
@@ -9330,7 +9337,7 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, sour
93309337
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
93319338
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
93329339

9333-
sourcemap-codec@^1.4.1:
9340+
sourcemap-codec@^1.4.1, sourcemap-codec@^1.4.4:
93349341
version "1.4.4"
93359342
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f"
93369343
integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg==

0 commit comments

Comments
 (0)