Skip to content

Commit

Permalink
feat: support generated JS imports for external scoped style (#196)
Browse files Browse the repository at this point in the history
Co-authored-by: Haoqun Jiang <haoqunjiang@gmail.com>
  • Loading branch information
Jinjiang and sodatea committed Oct 1, 2023
1 parent 5b2f9c8 commit bd5055d
Show file tree
Hide file tree
Showing 11 changed files with 236 additions and 3 deletions.
14 changes: 11 additions & 3 deletions packages/plugin-vue/src/index.ts
Expand Up @@ -13,7 +13,11 @@ import type * as _compiler from 'vue/compiler-sfc'
import { version } from '../package.json'
import { resolveCompiler } from './compiler'
import { parseVueRequest } from './utils/query'
import { getDescriptor, getSrcDescriptor } from './utils/descriptorCache'
import {
getDescriptor,
getSrcDescriptor,
getTempSrcDescriptor,
} from './utils/descriptorCache'
import { getResolvedScript, typeDepToSFCMap } from './script'
import { transformMain } from './main'
import { handleHotUpdate, handleTypeDepChange } from './handleHotUpdate'
Expand Down Expand Up @@ -219,6 +223,7 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
}

const { filename, query } = parseVueRequest(id)

// select corresponding block for sub-part virtual modules
if (query.vue) {
if (query.src) {
Expand Down Expand Up @@ -248,9 +253,11 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
transform(code, id, opt) {
const ssr = opt?.ssr === true
const { filename, query } = parseVueRequest(id)

if (query.raw || query.url) {
return
}

if (!filter(filename) && !query.vue) {
if (
!query.vue &&
Expand Down Expand Up @@ -278,7 +285,8 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
} else {
// sub block request
const descriptor = query.src
? getSrcDescriptor(filename, query)!
? getSrcDescriptor(filename, query) ||
getTempSrcDescriptor(filename, query)
: getDescriptor(filename, options)!

if (query.type === 'template') {
Expand All @@ -287,7 +295,7 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
return transformStyle(
code,
descriptor,
Number(query.index),
Number(query.index || 0),
options,
this,
filename,
Expand Down
19 changes: 19 additions & 0 deletions packages/plugin-vue/src/utils/descriptorCache.ts
Expand Up @@ -81,6 +81,25 @@ export function getSrcDescriptor(
return cache.get(filename)!
}

export function getTempSrcDescriptor(
filename: string,
query: VueQuery,
): SFCDescriptor {
// this is only used for pre-compiled <style src> with scoped flag
return {
filename,
id: query.id || '',
styles: [
{
scoped: query.scoped,
loc: {
start: { line: 0, column: 0 },
},
},
],
} as SFCDescriptor
}

export function setSrcDescriptor(
filename: string,
entry: SFCDescriptor,
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-vue/src/utils/query.ts
Expand Up @@ -7,6 +7,7 @@ export interface VueQuery {
raw?: boolean
url?: boolean
scoped?: boolean
id?: string
}

export function parseVueRequest(id: string): {
Expand Down
6 changes: 6 additions & 0 deletions playground/vue/Main.vue
Expand Up @@ -30,6 +30,9 @@
<Url />
<TsGeneric msg="hello" />
<DefaultLangs />
<PreCompiled />
<PreCompiledExternalScoped />
<PreCompiledExternalCssModules />
</template>

<script setup lang="ts">
Expand All @@ -54,6 +57,9 @@ import { ref } from 'vue'
import Url from './Url.vue'
import TypeProps from './TypeProps.vue'
import DefaultLangs from './DefaultLangs.vue'
import PreCompiled from './pre-compiled/foo.vue'
import PreCompiledExternalScoped from './pre-compiled/external-scoped.vue'
import PreCompiledExternalCssModules from './pre-compiled/external-cssmodules.vue'
const TsGeneric = defineAsyncComponent(() => import('./TsGeneric.vue'))
Expand Down
12 changes: 12 additions & 0 deletions playground/vue/__tests__/vue.spec.ts
Expand Up @@ -344,3 +344,15 @@ describe('default langs', () => {
expect(await getColor('.default-langs')).toBe('blue')
})
})

describe('pre-compiled components', () => {
test('should work', async () => {
expect(await getColor('.pre-compiled-title')).toBe('red')
})
test('should work with external scoped style', async () => {
expect(await getColor('.pre-compiled-external-scoped-title')).toBe('red')
})
test('should work with external css modules', async () => {
expect(await getColor('.pre-compiled-external-cssmodules')).toBe('red')
})
})
59 changes: 59 additions & 0 deletions playground/vue/pre-compiled/external-cssmodules.vue.js
@@ -0,0 +1,59 @@
import {
Fragment as _Fragment,
createElementBlock as _createElementBlock,
createElementVNode as _createElementVNode,
normalizeClass as _normalizeClass,
openBlock as _openBlock,
} from 'vue'

import style0 from './external.module.css?module=true&lang.module.css'

const __sfc__ = {
data() {
return {
isRed: true,
}
},
}

function render(_ctx, _cache, $props, $setup, $data, $options) {
return (
_openBlock(),
_createElementBlock(
_Fragment,
null,
[
_createElementVNode(
'p',
{
class: _normalizeClass({
[_ctx.$style.red]: $data.isRed,
'pre-compiled-external-cssmodules': true,
}),
},
' Am I red? ',
2 /* CLASS */,
),
_createElementVNode(
'p',
{
class: _normalizeClass([
_ctx.$style.red,
_ctx.$style.bold,
'pre-compiled-external-cssmodules',
]),
},
' Red and bold ',
2 /* CLASS */,
),
],
64 /* STABLE_FRAGMENT */,
)
)
}
__sfc__.render = render
const cssModules = {}
cssModules['$style'] = style0
__sfc__.__cssModules = cssModules
__sfc__.__file = 'external-cssmodules.vue'
export default __sfc__
61 changes: 61 additions & 0 deletions playground/vue/pre-compiled/external-scoped.vue.js
@@ -0,0 +1,61 @@
import './external.css?vue&type=style&scoped=true&id=0d49ede6&src=0d49ede6&lang.css'

import {
Fragment as _Fragment,
createElementBlock as _createElementBlock,
createElementVNode as _createElementVNode,
openBlock as _openBlock,
popScopeId as _popScopeId,
pushScopeId as _pushScopeId,
toDisplayString as _toDisplayString,
vModelText as _vModelText,
withDirectives as _withDirectives,
ref,
} from 'vue'
const __sfc__ = {
setup() {
const msg = ref('Hello World!')
return { msg }
},
}

const _withScopeId = (n) => (
_pushScopeId('data-v-0d49ede6'), (n = n()), _popScopeId(), n
)
const _hoisted_1 = { class: 'pre-compiled-external-scoped-title' }

function render(_ctx, _cache, $props, $setup, $data, $options) {
return (
_openBlock(),
_createElementBlock(
_Fragment,
null,
[
_createElementVNode(
'h6',
_hoisted_1,
_toDisplayString($setup.msg),
1 /* TEXT */,
),
_withDirectives(
_createElementVNode(
'input',
{
'onUpdate:modelValue':
_cache[0] || (_cache[0] = ($event) => ($setup.msg = $event)),
},
null,
512 /* NEED_PATCH */,
),
[[_vModelText, $setup.msg]],
),
],
64 /* STABLE_FRAGMENT */,
)
)
}
__sfc__.render = render

__sfc__.__scopeId = 'data-v-0d49ede6'
__sfc__.__file = 'external-scoped.vue'
export default __sfc__
3 changes: 3 additions & 0 deletions playground/vue/pre-compiled/external.css
@@ -0,0 +1,3 @@
.pre-compiled-external-scoped-title {
color: red;
}
6 changes: 6 additions & 0 deletions playground/vue/pre-compiled/external.module.css
@@ -0,0 +1,6 @@
.red {
color: red;
}
.bold {
font-weight: bold;
}
55 changes: 55 additions & 0 deletions playground/vue/pre-compiled/foo.vue.js
@@ -0,0 +1,55 @@
import './foo.vue__0.css'

import {
Fragment as _Fragment,
createElementBlock as _createElementBlock,
createElementVNode as _createElementVNode,
openBlock as _openBlock,
toDisplayString as _toDisplayString,
vModelText as _vModelText,
withDirectives as _withDirectives,
ref,
} from 'vue'
const __sfc__ = {
setup() {
const msg = ref('Hello World!')
return { msg }
},
}

const _hoisted_1 = { class: 'pre-compiled-title' }

function render(_ctx, _cache, $props, $setup, $data, $options) {
return (
_openBlock(),
_createElementBlock(
_Fragment,
null,
[
_createElementVNode(
'h6',
_hoisted_1,
_toDisplayString($setup.msg),
1 /* TEXT */,
),
_withDirectives(
_createElementVNode(
'input',
{
'onUpdate:modelValue':
_cache[0] || (_cache[0] = ($event) => ($setup.msg = $event)),
},
null,
512 /* NEED_PATCH */,
),
[[_vModelText, $setup.msg]],
),
],
64 /* STABLE_FRAGMENT */,
)
)
}
__sfc__.render = render

__sfc__.__file = 'foo.vue'
export default __sfc__
3 changes: 3 additions & 0 deletions playground/vue/pre-compiled/foo.vue__0.css
@@ -0,0 +1,3 @@
.pre-compiled-title {
color: red;
}

0 comments on commit bd5055d

Please sign in to comment.