Permalink
Browse files

feat: Add data option to allow prepending style block content

Related #93
  • Loading branch information...
znck committed Feb 5, 2019
1 parent c61e6d6 commit a5711f6af1706da955ad23d79b6690f3296ffebf
Showing with 141 additions and 15 deletions.
  1. +23 −9 docs/options.md
  2. +1 −0 package.json
  3. +66 −5 src/index.ts
  4. +43 −0 test/options/data.spec.ts
  5. +8 −1 yarn.lock
@@ -29,19 +29,26 @@ e.g.: `defaultLang: { script: 'ts' }` would set default `<script>` block languag
`defaultLang` does not set default language in templates for your editor/IDE.
:::

## `blackListCustomBlocks`

- type: `string[]`
- default: `['*']`
## `customBlocks`

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

## `whiteListCustomBlocks`
Include/exclude custom block in final bundle.
e.g.

- type: `string[]`
- default: `[]`

Include custom block in final bundle.
``` js
...
VuePlugin({
customBlocks: [
'!docs', // exclude <docs>
'gql', // include <gql>
'!*', // exclude everything else
]
})
...
```

## `css`

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

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

## `data`

- type: `{ [lang: string]: string | (() => string)}`
- default: `{}`

Prepend content to `<style>` blocks in `.vue` files.

## `compiler`

- type: [VueTemplateCompiler](https://github.com/vuejs/component-compiler-utils#parseparseoptions-sfcdescriptor)
@@ -49,6 +49,7 @@
"@vue/component-compiler-utils": "^2.1.0",
"debug": "^4.1.1",
"hash-sum": "^1.0.2",
"magic-string": "^0.25.2",
"querystring": "^0.2.0",
"rollup-pluginutils": "^2.0.1",
"source-map": "0.7.3",
@@ -15,6 +15,7 @@ import {
StyleCompileResult,
DescriptorCompileResult
} from '@vue/component-compiler'
import MagicString from 'magic-string'
import { Plugin, RawSourceMap } from 'rollup'
import * as path from 'path'
import { parse, SFCDescriptor, SFCBlock } from '@vue/component-compiler-utils'
@@ -33,6 +34,15 @@ const dR = debug('rollup-plugin-vue:resolve')
const dL = debug('rollup-plugin-vue:load')
const dT = debug('rollup-plugin-vue:transform')

export interface VuePluginOptionsData {
css: string | (() => string)
less: string | (() => string)
postcss: string | (() => string)
sass: string | (() => string)
scss: string | (() => string)
stylus: string | (() => string)
}

export interface VuePluginOptions {
/**
* Include files or directories.
@@ -65,6 +75,17 @@ export interface VuePluginOptions {
* ```
*/
customBlocks?: string[] | ((tag: string) => boolean)

/**
* Prepend CSS.
* @default `undefined`
* @example
* ```js
* VuePlugin({ data: { scss: '$color: red;' } }) // to extract css
* ```
*/
data?: Partial<VuePluginOptionsData>

/**
* Inject CSS in JavaScript.
* @default `true`
@@ -153,6 +174,9 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
const exposeFilename =
typeof opts.exposeFilename === 'boolean' ? opts.exposeFilename : false

const data: VuePluginOptionsData = (opts.data || {}) as any

delete opts.data
delete opts.beforeAssemble
delete opts.css
delete opts.exposeFilename
@@ -180,6 +204,26 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {

if (opts.css === false) d('Running in CSS extract mode')

function prependStyle(
id: string,
lang: string,
code: string,
map: any
): { code: string } {
if (!(lang in data)) return { code }
const ms = new MagicString(code, {
filename: id,
indentExclusionRanges: []
})

const value: string | (() => string) = (data as any)[lang]
const fn = typeof value === 'function' ? value : () => value

ms.prepend(fn())

return { code: ms.toString() }
}

return {
name: 'VuePlugin',

@@ -193,6 +237,7 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
if (!isVuePartRequest(id)) return
id = path.resolve(path.dirname(importer), id)
const ref = parseVuePartRequest(id)

if (ref) {
const element = resolveVuePart(descriptors, ref)
const src = (element as SFCBlock).src
@@ -217,11 +262,15 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {
if (!request) return null

const element = resolveVuePart(descriptors, request)
const code =
let code =
'code' in element
? ((element as any).code as string) // .code is set when extract styles is used. { css: false }
: element.content
const map = element.map as RawSourceMap
let map = element.map as RawSourceMap

if (request.meta.type === 'styles') {
code = prependStyle(id, request.meta.lang, code, map).code
}

dL(`id: ${id}\ncode: \n${code}\nmap: ${JSON.stringify(map, null, 2)}\n\n`)

@@ -254,6 +303,15 @@ export default function vue(opts: VuePluginOptions = {}): Plugin {

const styles = await Promise.all(
descriptor.styles.map(async style => {
if (style.content) {
style.content = prependStyle(
filename,
style.lang || 'css',
style.content,
style.map
).code
}

const compiled = await compiler.compileStyleAsync(
filename,
scopeId,
@@ -382,7 +440,10 @@ function createCustomBlockFilter(
customBlocks.filter(tag => tag.startsWith('!')).map(tag => tag.substr(1))
)

return tag =>
(allowed.has('*') || allowed.has(tag)) &&
!(notAllowed.has('*') || notAllowed.has(tag))
return tag => {
if (allowed.has(tag)) return true
if (notAllowed.has(tag)) return false
if (notAllowed.has('*')) return false
return allowed.has('*')
}
}
@@ -0,0 +1,43 @@
import vue, { VuePluginOptions } from '../../src'
import { pluginInline } from '../setup/plugins'
import { rollup } from 'rollup'

describe('data', () => {
async function setup(options?: Partial<VuePluginOptions>) {
return rollup({
input: '/entry.vue',
plugins: [
pluginInline(
'/entry.vue',
`
<template>
<div>Hello, world</div>
</template>
<style scoped>
div {
color: red;
}
</style>
`
),
vue({
...options,
normalizer: 'vue-runtime-helpers/dist/normalize-component.mjs',
styleInjector: 'vue-runtime-helpers/dist/inject-style/browser.mjs',
})
]
})
.then(bundle => bundle.generate({ format: 'es' }))
.then(generated => generated.output[0])
}

it('prefix', async () => {
const { code } = await setup({
data: {
css: '/*! © 2019 Jane Doe */\n'
}
})

expect(code).toEqual(expect.stringContaining('© 2019 Jane Doe'))
})
})

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

0 comments on commit a5711f6

Please sign in to comment.