Skip to content

Commit 600ca0c

Browse files
committed
wip: custom blocks
1 parent cda1ec3 commit 600ca0c

File tree

12 files changed

+133
-29
lines changed

12 files changed

+133
-29
lines changed

lib/customBlocks.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
// const { attrsToQuery } = require('./utils')
1+
const qs = require('querystring')
2+
const { attrsToQuery } = require('./utils')
23

34
module.exports = function genCustomBlocksCode (
45
blocks,
5-
resourcePath
6+
resourcePath,
7+
stringifyRequest
68
) {
7-
// blocks.map((block, i) => {
8-
// const src = block.src || resourcePath
9-
// const langQuery = getLangQuery(block)
10-
11-
// })
9+
return `\n/* custom blocks */\n` + blocks.map((block, i) => {
10+
const src = block.attrs.src || resourcePath
11+
const attrsQuery = attrsToQuery(block.attrs)
12+
const query = `?vue&type=custom&index=${i}&blockType=${qs.escape(block.type)}${attrsQuery}`
13+
return (
14+
`import block${i} from ${stringifyRequest(src + query)}\n` +
15+
`if (typeof block${i} === 'function') block${i}(component)`
16+
)
17+
}).join(`\n`) + `\n`
1218
}

lib/index.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ module.exports = function (source) {
112112
${templateImport}
113113
${scriptImport}
114114
${stylesCode}
115+
116+
/* normalize component */
115117
import normalizer from ${stringifyRequest(`!${componentNormalizerPath}`)}
116118
var component = normalizer(
117119
script,
@@ -123,21 +125,25 @@ var component = normalizer(
123125
${isServer ? JSON.stringify(hash(request)) : `null`}
124126
${isShadow ? `,true` : ``}
125127
)
126-
`.trim()
128+
`.trim() + `\n`
127129

128130
if (descriptor.customBlocks && descriptor.customBlocks.length) {
129-
code += genCustomBlocksCode(descriptor.customBlocks)
131+
code += genCustomBlocksCode(
132+
descriptor.customBlocks,
133+
resourcePath,
134+
stringifyRequest
135+
)
136+
}
137+
138+
if (needsHotReload) {
139+
code += `\n` + genHotReloadCode(id, hasFunctional)
130140
}
131141

132142
// Expose filename. This is used by the devtools and vue runtime warnings.
133143
if (!isProduction) {
134144
code += `\ncomponent.options.__file = ${JSON.stringify(shortFilePath)}`
135145
}
136146

137-
if (needsHotReload) {
138-
code += genHotReloadCode(id, hasFunctional)
139-
}
140-
141147
code += `\nexport default component.exports`
142148
// console.log(code)
143149
return code

lib/noop.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// a noop loader that matches custom blocks with no
2+
// matching rules.
3+
module.exports = function noop () {
4+
return ``
5+
}

lib/plugin.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
const qs = require('querystring')
22
const RuleSet = require('webpack/lib/RuleSet')
33

4+
// TODO handling rules without `test` being matched twice
5+
// e.g. a rule with just resourceQuery: /blockType=foo/
6+
47
// TODO handle vueRule with oneOf
8+
59
module.exports = class VueLoaderPlugin {
610
apply (compiler) {
711
// get a hold of the raw rules
@@ -68,6 +72,11 @@ module.exports = class VueLoaderPlugin {
6872
const baseRules = rawRules.filter(r => r !== vueRule)
6973
const normalizedRules = rawNormalizedRules.filter(r => r !== normalizedVueRule)
7074

75+
const customFallbackRule = {
76+
loader: require.resolve('./noop'),
77+
resourceQuery: /type=custom/
78+
}
79+
7180
// construct a new rule for vue file, with oneOf containing
7281
// multiple rules with dynamic resourceQuery functions that applies to
7382
// different language blocks in a raw vue file.
@@ -77,7 +86,7 @@ module.exports = class VueLoaderPlugin {
7786
// for each user rule, create a cloned rule by checking if the rule
7887
// matches the lang specified in the resourceQuery.
7988
return cloneRule(rule, normalizedRules[i], normalizedVueUse)
80-
}).concat(vueRule)
89+
}).concat(customFallbackRule, vueRule)
8190
}
8291

8392
// replace the original vue rule with our new constructed rule.

lib/select.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,15 @@ module.exports = function selectBlock (descriptor, loaderContext, query) {
2929
)
3030
return
3131
}
32+
33+
// custom
34+
if (query.type === 'custom' && query.index != null) {
35+
const block = descriptor.customBlocks[query.index]
36+
loaderContext.callback(
37+
null,
38+
block.content,
39+
block.map
40+
)
41+
return
42+
}
3243
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"normalize-newline": "^3.0.0",
6666
"postcss-loader": "^2.1.2",
6767
"pug": "^2.0.1",
68+
"raw-loader": "^0.5.1",
6869
"sass-loader": "^6.0.7",
6970
"stylus": "^0.54.5",
7071
"stylus-loader": "^3.0.2",

test/custom.spec.js

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,71 @@
1-
test('custom blocks', () => {
1+
const {
2+
bundle
3+
} = require('./utils')
24

5+
test('add custom blocks to the webpack output', done => {
6+
bundle({
7+
entry: 'custom-language.vue',
8+
module: {
9+
rules: [
10+
{ test: /\.js/, loader: 'babel-loader' }
11+
]
12+
}
13+
}, code => {
14+
// should also be transpiled
15+
expect(code).toContain(`
16+
describe('example', function () {
17+
it('basic', function (done) {
18+
done();
19+
});
20+
});
21+
`.trim())
22+
done()
23+
})
24+
})
25+
26+
test('custom blocks should work with src imports', done => {
27+
bundle({
28+
entry: 'custom-import.vue',
29+
module: {
30+
rules: [
31+
{ test: /\.js/, loader: 'babel-loader' }
32+
]
33+
}
34+
}, (code) => {
35+
expect(code).toContain(`
36+
describe('example', function () {
37+
it('basic', function (done) {
38+
done();
39+
});
40+
});
41+
`.trim())
42+
done()
43+
})
44+
})
45+
46+
// TODO
47+
// test('passes Component to custom block loaders', done => {
48+
// mockBundleAndRun({
49+
// entry: 'custom-language.vue',
50+
// module: {
51+
// rules: [
52+
// {
53+
// resourceQuery: /blockType=documentation/,
54+
// loader: require.resolve('./mock-loaders/docs')
55+
// }
56+
// ]
57+
// }
58+
// }, ({ module }) => {
59+
// expect(module.__docs).toContain('This is example documentation for a component.')
60+
// done()
61+
// })
62+
// })
63+
64+
test('custom blocks can be ignored', done => {
65+
bundle({
66+
entry: 'custom-language.vue'
67+
}, code => {
68+
expect(code).not.toContain(`describe('example'`)
69+
done()
70+
})
371
})

test/fixtures/custom-blocks.vue

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ ja:
77

88
<blog>## foo</blog>
99

10-
<esm>
11-
export default function (Component) {
12-
Component.options.foo = 1
13-
}
14-
</esm>
15-
1610
<template>
1711
<div>
1812
<h1>{{ msg }}</h1>

test/fixtures/custom-language.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
<unit-test>
2-
describe('example', function () {
3-
it('basic', function (done) {
1+
<unit-test lang="js">
2+
describe('example', () => {
3+
it('basic', done => {
44
done();
55
})
66
})

test/fixtures/unit-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
describe('example', function () {
2-
it('basic', function (done) {
1+
describe('example', () => {
2+
it('basic', done => {
33
done()
44
})
55
})

0 commit comments

Comments
 (0)