Commit 600ca0cb authored by Evan You's avatar Evan You

wip: custom blocks

parent cda1ec35
// const { attrsToQuery } = require('./utils') const qs = require('querystring')
const { attrsToQuery } = require('./utils')
module.exports = function genCustomBlocksCode ( module.exports = function genCustomBlocksCode (
blocks, blocks,
resourcePath resourcePath,
stringifyRequest
) { ) {
// blocks.map((block, i) => { return `\n/* custom blocks */\n` + blocks.map((block, i) => {
// const src = block.src || resourcePath const src = block.attrs.src || resourcePath
// const langQuery = getLangQuery(block) const attrsQuery = attrsToQuery(block.attrs)
const query = `?vue&type=custom&index=${i}&blockType=${qs.escape(block.type)}${attrsQuery}`
// }) return (
`import block${i} from ${stringifyRequest(src + query)}\n` +
`if (typeof block${i} === 'function') block${i}(component)`
)
}).join(`\n`) + `\n`
} }
...@@ -112,6 +112,8 @@ module.exports = function (source) { ...@@ -112,6 +112,8 @@ module.exports = function (source) {
${templateImport} ${templateImport}
${scriptImport} ${scriptImport}
${stylesCode} ${stylesCode}
/* normalize component */
import normalizer from ${stringifyRequest(`!${componentNormalizerPath}`)} import normalizer from ${stringifyRequest(`!${componentNormalizerPath}`)}
var component = normalizer( var component = normalizer(
script, script,
...@@ -123,10 +125,18 @@ var component = normalizer( ...@@ -123,10 +125,18 @@ var component = normalizer(
${isServer ? JSON.stringify(hash(request)) : `null`} ${isServer ? JSON.stringify(hash(request)) : `null`}
${isShadow ? `,true` : ``} ${isShadow ? `,true` : ``}
) )
`.trim() `.trim() + `\n`
if (descriptor.customBlocks && descriptor.customBlocks.length) { if (descriptor.customBlocks && descriptor.customBlocks.length) {
code += genCustomBlocksCode(descriptor.customBlocks) code += genCustomBlocksCode(
descriptor.customBlocks,
resourcePath,
stringifyRequest
)
}
if (needsHotReload) {
code += `\n` + genHotReloadCode(id, hasFunctional)
} }
// Expose filename. This is used by the devtools and vue runtime warnings. // Expose filename. This is used by the devtools and vue runtime warnings.
...@@ -134,10 +144,6 @@ var component = normalizer( ...@@ -134,10 +144,6 @@ var component = normalizer(
code += `\ncomponent.options.__file = ${JSON.stringify(shortFilePath)}` code += `\ncomponent.options.__file = ${JSON.stringify(shortFilePath)}`
} }
if (needsHotReload) {
code += genHotReloadCode(id, hasFunctional)
}
code += `\nexport default component.exports` code += `\nexport default component.exports`
// console.log(code) // console.log(code)
return code return code
......
// a noop loader that matches custom blocks with no
// matching rules.
module.exports = function noop () {
return ``
}
const qs = require('querystring') const qs = require('querystring')
const RuleSet = require('webpack/lib/RuleSet') const RuleSet = require('webpack/lib/RuleSet')
// TODO handling rules without `test` being matched twice
// e.g. a rule with just resourceQuery: /blockType=foo/
// TODO handle vueRule with oneOf // TODO handle vueRule with oneOf
module.exports = class VueLoaderPlugin { module.exports = class VueLoaderPlugin {
apply (compiler) { apply (compiler) {
// get a hold of the raw rules // get a hold of the raw rules
...@@ -68,6 +72,11 @@ module.exports = class VueLoaderPlugin { ...@@ -68,6 +72,11 @@ module.exports = class VueLoaderPlugin {
const baseRules = rawRules.filter(r => r !== vueRule) const baseRules = rawRules.filter(r => r !== vueRule)
const normalizedRules = rawNormalizedRules.filter(r => r !== normalizedVueRule) const normalizedRules = rawNormalizedRules.filter(r => r !== normalizedVueRule)
const customFallbackRule = {
loader: require.resolve('./noop'),
resourceQuery: /type=custom/
}
// construct a new rule for vue file, with oneOf containing // construct a new rule for vue file, with oneOf containing
// multiple rules with dynamic resourceQuery functions that applies to // multiple rules with dynamic resourceQuery functions that applies to
// different language blocks in a raw vue file. // different language blocks in a raw vue file.
...@@ -77,7 +86,7 @@ module.exports = class VueLoaderPlugin { ...@@ -77,7 +86,7 @@ module.exports = class VueLoaderPlugin {
// for each user rule, create a cloned rule by checking if the rule // for each user rule, create a cloned rule by checking if the rule
// matches the lang specified in the resourceQuery. // matches the lang specified in the resourceQuery.
return cloneRule(rule, normalizedRules[i], normalizedVueUse) return cloneRule(rule, normalizedRules[i], normalizedVueUse)
}).concat(vueRule) }).concat(customFallbackRule, vueRule)
} }
// replace the original vue rule with our new constructed rule. // replace the original vue rule with our new constructed rule.
......
...@@ -29,4 +29,15 @@ module.exports = function selectBlock (descriptor, loaderContext, query) { ...@@ -29,4 +29,15 @@ module.exports = function selectBlock (descriptor, loaderContext, query) {
) )
return return
} }
// custom
if (query.type === 'custom' && query.index != null) {
const block = descriptor.customBlocks[query.index]
loaderContext.callback(
null,
block.content,
block.map
)
return
}
} }
test('custom blocks', () => { const {
bundle
} = require('./utils')
test('add custom blocks to the webpack output', done => {
bundle({
entry: 'custom-language.vue',
module: {
rules: [
{ test: /\.js/, loader: 'babel-loader' }
]
}
}, code => {
// should also be transpiled
expect(code).toContain(`
describe('example', function () {
it('basic', function (done) {
done();
});
});
`.trim())
done()
})
})
test('custom blocks should work with src imports', done => {
bundle({
entry: 'custom-import.vue',
module: {
rules: [
{ test: /\.js/, loader: 'babel-loader' }
]
}
}, (code) => {
expect(code).toContain(`
describe('example', function () {
it('basic', function (done) {
done();
});
});
`.trim())
done()
})
})
// TODO
// test('passes Component to custom block loaders', done => {
// mockBundleAndRun({
// entry: 'custom-language.vue',
// module: {
// rules: [
// {
// resourceQuery: /blockType=documentation/,
// loader: require.resolve('./mock-loaders/docs')
// }
// ]
// }
// }, ({ module }) => {
// expect(module.__docs).toContain('This is example documentation for a component.')
// done()
// })
// })
test('custom blocks can be ignored', done => {
bundle({
entry: 'custom-language.vue'
}, code => {
expect(code).not.toContain(`describe('example'`)
done()
})
}) })
...@@ -7,12 +7,6 @@ ja: ...@@ -7,12 +7,6 @@ ja:
<blog>## foo</blog> <blog>## foo</blog>
<esm>
export default function (Component) {
Component.options.foo = 1
}
</esm>
<template> <template>
<div> <div>
<h1>{{ msg }}</h1> <h1>{{ msg }}</h1>
......
<unit-test> <unit-test lang="js">
describe('example', function () { describe('example', () => {
it('basic', function (done) { it('basic', done => {
done(); done();
}) })
}) })
......
describe('example', function () { describe('example', () => {
it('basic', function (done) { it('basic', done => {
done() done()
}) })
}) })
module.exports = function (source, map) { module.exports = function (source, map) {
this.callback(null, this.callback(null,
'module.exports = function(Component) {Component.options.__docs = ' + `export default Component => {
JSON.stringify(source) + Component.options.__docs = ${JSON.stringify(source)}
'}', }`,
map) map)
} }
...@@ -6413,6 +6413,10 @@ raw-body@2.3.2: ...@@ -6413,6 +6413,10 @@ raw-body@2.3.2:
iconv-lite "0.4.19" iconv-lite "0.4.19"
unpipe "1.0.0" unpipe "1.0.0"
raw-loader@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
rc@^1.1.7: rc@^1.1.7:
version "1.2.5" version "1.2.5"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd"
......
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