Commit 5d0c4f7b authored by Evan You's avatar Evan You

test: css modules

parent 99754c01
...@@ -10,8 +10,8 @@ module.exports = code => code ...@@ -10,8 +10,8 @@ module.exports = code => code
module.exports.pitch = function (remainingRequest) { module.exports.pitch = function (remainingRequest) {
const query = qs.parse(this.resourceQuery.slice(1)) const query = qs.parse(this.resourceQuery.slice(1))
if (query.vue != null) { if (query.vue != null) {
// For Scoped CSS: inject style-post-loader before css-loader // Inject style-post-loader before css-loader for scoped CSS and trimming
if (query.type === `style` && query.scoped != null) { if (query.type === `style`) {
const cssLoaderIndex = this.loaders.findIndex(l => /\/css-loader/.test(l.request)) const cssLoaderIndex = this.loaders.findIndex(l => /\/css-loader/.test(l.request))
if (cssLoaderIndex) { if (cssLoaderIndex) {
const afterLoaders = this.loaders.slice(1, cssLoaderIndex + 1).map(l => l.request) const afterLoaders = this.loaders.slice(1, cssLoaderIndex + 1).map(l => l.request)
...@@ -22,7 +22,8 @@ module.exports.pitch = function (remainingRequest) { ...@@ -22,7 +22,8 @@ module.exports.pitch = function (remainingRequest) {
...beforeLoaders, ...beforeLoaders,
this.resourcePath + this.resourceQuery this.resourcePath + this.resourceQuery
].join('!') ].join('!')
return `export * from ${loaderUtils.stringifyRequest(this, request)}` // use cjs to ensure exports from (vue-)style-loader/css-loader are intact
return `module.exports = require(${loaderUtils.stringifyRequest(this, request)})`
} }
} }
...@@ -34,6 +35,7 @@ module.exports.pitch = function (remainingRequest) { ...@@ -34,6 +35,7 @@ module.exports.pitch = function (remainingRequest) {
...beforeLoaders, ...beforeLoaders,
this.resourcePath + this.resourceQuery this.resourcePath + this.resourceQuery
].join('!') ].join('!')
// the template compiler uses esm exports
return `export * from ${loaderUtils.stringifyRequest(this, request)}` return `export * from ${loaderUtils.stringifyRequest(this, request)}`
} }
} }
......
...@@ -11,7 +11,11 @@ module.exports = function (source, map) { ...@@ -11,7 +11,11 @@ module.exports = function (source, map) {
const query = qs.parse(this.resourceQuery.slice(1)) const query = qs.parse(this.resourceQuery.slice(1))
const id = `data-v-${query.id}` const id = `data-v-${query.id}`
const plugins = [trim(), scoped({ id })] const plugins = [trim()]
if (query.scoped != null) {
plugins.push(scoped({ id }))
}
const options = { const options = {
to: this.resourcePath, to: this.resourcePath,
......
...@@ -75,7 +75,7 @@ test('style import', done => { ...@@ -75,7 +75,7 @@ test('style import', done => {
entry: 'style-import.vue' entry: 'style-import.vue'
}, ({ window }) => { }, ({ window }) => {
const styles = window.document.querySelectorAll('style') const styles = window.document.querySelectorAll('style')
expect(styles[0].textContent).toContain('h1 { color: red; }') expect(styles[0].textContent).toContain('h1 { color: red;\n}')
// import with scoped // import with scoped
const id = 'data-v-' + genId('style-import.vue') const id = 'data-v-' + genId('style-import.vue')
expect(styles[1].textContent).toContain('h1[' + id + '] { color: green;\n}') expect(styles[1].textContent).toContain('h1[' + id + '] { color: green;\n}')
...@@ -90,7 +90,7 @@ test('style import for a same file twice', done => { ...@@ -90,7 +90,7 @@ test('style import for a same file twice', done => {
initStylesForAllSubComponents(module) initStylesForAllSubComponents(module)
const styles = window.document.querySelectorAll('style') const styles = window.document.querySelectorAll('style')
expect(styles.length).toBe(3) expect(styles.length).toBe(3)
expect(styles[0].textContent).toContain('h1 { color: red; }') expect(styles[0].textContent).toContain('h1 { color: red;\n}')
// import with scoped // import with scoped
const id = 'data-v-' + genId('style-import-twice-sub.vue') const id = 'data-v-' + genId('style-import-twice-sub.vue')
expect(styles[1].textContent).toContain('h1[' + id + '] { color: green;\n}') expect(styles[1].textContent).toContain('h1[' + id + '] { color: green;\n}')
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
} }
</style> </style>
<style scoped lang="stylus" module> <style lang="stylus" module scoped>
.red .red
color: red color: red
</style> </style>
<script> <script>
module.exports = {} export default {}
</script> </script>
...@@ -106,49 +106,79 @@ test('postcss', done => { ...@@ -106,49 +106,79 @@ test('postcss', done => {
}) })
}) })
// TODO test('css-modules', async () => {
// test('css-modules', done => { function testWithIdent (localIdentName, regexToMatch) {
// function testWithIdent (localIdentName, regexToMatch, cb) { return new Promise((resolve, reject) => {
// mockBundleAndRun({ const baseLoaders = [
// entry: 'css-modules.vue', 'vue-style-loader',
// vue: { {
// cssModules: localIdentName && { loader: 'css-loader',
// localIdentName: localIdentName options: {
// } modules: true,
// } localIdentName
// }, (window, module, raw, instance) => { }
// // get local class name }
// const className = instance.style.red ]
// expect(className).toMatch(regexToMatch) mockBundleAndRun({
entry: 'css-modules.vue',
modify: config => {
config.module.rules = [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: baseLoaders
},
{
test: /\.stylus$/,
use: [
...baseLoaders,
'stylus-loader'
]
}
]
}
}, ({ window, instance, jsdomError, bundleError }) => {
if (jsdomError) return reject(jsdomError)
if (bundleError) return reject(bundleError)
// get local class name
const className = instance.style.red
expect(className).toMatch(regexToMatch)
// class name in style
let style = [].slice.call(window.document.querySelectorAll('style')).map((style) => {
return style.textContent
}).join('\n')
style = normalizeNewline(style)
expect(style).toContain('.' + className + ' {\n color: red;\n}')
// // class name in style // animation name
// let style = [].slice.call(window.document.querySelectorAll('style')).map((style) => { const match = style.match(/@keyframes\s+(\S+)\s+{/)
// return style.textContent expect(match).toHaveLength(2)
// }).join('\n') const animationName = match[1]
// style = normalizeNewline(style) expect(animationName).not.toBe('fade')
// expect(style).toContain('.' + className + ' {\n color: red;\n}') expect(style).toContain('animation: ' + animationName + ' 1s;')
// // animation name // default module + pre-processor + scoped
// const match = style.match(/@keyframes\s+(\S+)\s+{/) const anotherClassName = instance.$style.red
// expect(match).toHaveLength(2) expect(anotherClassName).toMatch(regexToMatch)
// const animationName = match[1] const id = 'data-v-' + genId('css-modules.vue')
// expect(animationName).not.toBe('fade') expect(style).toContain('.' + anotherClassName + '[' + id + ']')
// expect(style).toContain('animation: ' + animationName + ' 1s;')
// // default module + pre-processor + scoped resolve()
// const anotherClassName = instance.$style.red })
// expect(anotherClassName).to.match(regexToMatch).not.toBe(className) })
// const id = 'data-v-' + genId('css-modules.vue') }
// expect(style).toContain('.' + anotherClassName + '[' + id + ']')
// cb() // default ident
// }) await testWithIdent(undefined, /^\w{22}/)
// }
// // default localIdentName // custom ident
// testWithIdent(undefined, /^red_\w{8}/, () => { await testWithIdent(
// // specified localIdentName '[path][name]---[local]---[hash:base64:5]',
// const ident = '[path][name]---[local]---[hash:base64:5]' /css-modules---red---\w{5}/
// const regex = /css-modules---red---\w{5}/ )
// testWithIdent(ident, regex, done) })
// })
// })
const path = require('path') const path = require('path')
const normalizeNewline = require('normalize-newline')
const { const {
mockRender, mockRender,
mockBundleAndRun mockBundleAndRun
...@@ -63,8 +64,8 @@ test('transform relative URLs and respects resolve alias', done => { ...@@ -63,8 +64,8 @@ test('transform relative URLs and respects resolve alias', done => {
expect(vnode.children[2].data.attrs.src).toBe('logo.c9e00e.png') expect(vnode.children[2].data.attrs.src).toBe('logo.c9e00e.png')
const style = window.document.querySelector('style').textContent const style = window.document.querySelector('style').textContent
expect(style).toContain('html { background-image: url(logo.c9e00e.png); }') expect(style).toContain('html { background-image: url(logo.c9e00e.png);\n}')
expect(style).toContain('body { background-image: url(logo.c9e00e.png); }') expect(style).toContain('body { background-image: url(logo.c9e00e.png);\n}')
done() done()
}) })
}) })
...@@ -109,24 +110,23 @@ test('transform srcset', done => { ...@@ -109,24 +110,23 @@ test('transform srcset', done => {
}) })
}) })
// TODO test('functional component with styles', done => {
// test('functional component with styles', done => { mockBundleAndRun({
// mockBundleAndRun({ entry: 'functional-style.vue'
// entry: 'functional-style.vue' }, ({ window, module, rawModule }) => {
// }, ({ window, module, rawModule }) => { expect(module.functional).toBe(true)
// expect(module.functional).toBe(true) const vnode = mockRender(module)
// const vnode = mockRender(module) // <div class="foo">hi</div>
// // <div class="foo">hi</div> expect(vnode.tag).toBe('div')
// expect(vnode.tag).toBe('div') expect(vnode.data.class).toBe('foo')
// expect(vnode.data.class).toBe('foo') expect(vnode.children[0].text).toBe('functional')
// expect(vnode.children[0].text).toBe('functional')
let style = window.document.querySelector('style').textContent
// let style = window.document.querySelector('style').textContent style = normalizeNewline(style)
// style = normalizeNewline(style) expect(style).toContain('.foo { color: red;\n}')
// expect(style).toContain('.foo { color: red;\n}') done()
// done() })
// }) })
// })
test('functional template', done => { test('functional template', done => {
mockBundleAndRun({ mockBundleAndRun({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment