Skip to content

Commit f97e676

Browse files
committedApr 6, 2018
feat: support style/script hoisting + css modules
1 parent c05448d commit f97e676

File tree

9 files changed

+67
-39
lines changed

9 files changed

+67
-39
lines changed
 

‎docs/test.md

-5
This file was deleted.

‎docs/using-vue.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,19 @@ Make sure a custom component's names either contains a hyphen or is in PascalCas
7979

8080
Sometimes you may need to apply some JavaScript or CSS only to the current page. In those case you can directly write root-level `<script>` or `<style>` blocks in the markdown file, and they will be hoisted out of the compiled HTML and used as the `<script>` and `<style>` blocks for the resulting Vue single-file component.
8181

82-
<div id="inline-script-style-example"></div>
82+
<div :class="$style.example"></div>
8383

84-
<!-- <style>
85-
#inline-script-style-example {
84+
<style module>
85+
.example {
8686
color: #41b883;
8787
}
8888
</style>
8989

9090
<script>
9191
export default {
9292
mounted () {
93-
document.getElementById('inline-script-style-example')
93+
document.querySelector(`.${this.$style.example}`)
9494
.textContent = 'Hello from inline script!'
9595
}
9696
}
9797
</script>
98-
-->

‎lib/markdown/component.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Replacing the default htmlBlock rule to allow using custom components at
22
// root level
33

4-
const blockNames = require('markdown-it/lib/common/htmlBlocks')
4+
const blockNames = require('markdown-it/lib/common/html_blocks')
55
const HTML_OPEN_CLOSE_TAG_RE = require('markdown-it/lib/common/html_re').HTML_OPEN_CLOSE_TAG_RE
66

77
// An array of opening and corresponding closing sequences for html tags,
@@ -21,7 +21,7 @@ const HTML_SEQUENCES = [
2121
]
2222

2323
module.exports = md => {
24-
md.block.ruler.at('htmlBlock', htmlBlock)
24+
md.block.ruler.at('html_block', htmlBlock)
2525
}
2626

2727
function htmlBlock (state, startLine, endLine, silent) {
@@ -73,7 +73,7 @@ function htmlBlock (state, startLine, endLine, silent) {
7373

7474
state.line = nextLine
7575

76-
const token = state.push('htmlBlock', '', 0)
76+
const token = state.push('html_block', '', 0)
7777
token.map = [startLine, nextLine]
7878
token.content = state.getLines(startLine, nextLine, state.blkIndent, true)
7979

‎lib/markdown/hoist.js

+20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
11
module.exports = md => {
2+
const RE = /^<(script|style)(?=(\s|>|$))/i
3+
let hoistedTags
24

5+
md.renderer.rules.html_block = (tokens, idx) => {
6+
const content = tokens[idx].content
7+
if (hoistedTags && RE.test(content.trim())) {
8+
hoistedTags.push(content)
9+
return ''
10+
} else {
11+
return content
12+
}
13+
}
14+
15+
md.renderWithHoisting = (...args) => {
16+
hoistedTags = []
17+
const html = md.render(...args)
18+
return {
19+
html,
20+
hoistedTags
21+
}
22+
}
323
}

‎lib/markdown/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const highlight = require('./highlight')
22
const highlightLines = require('./highlightLines')
33
const component = require('./component')
4+
const hoistScriptStyle = require('./hoist')
45
const convertRouterLink = require('./link')
56
const emoji = require('markdown-it-emoji')
67
const anchor = require('markdown-it-anchor')
@@ -21,6 +22,7 @@ module.exports = ({ markdown = {}}) => {
2122
.use(component)
2223
.use(highlightLines)
2324
.use(convertRouterLink)
25+
.use(hoistScriptStyle)
2426
// 3rd party plugins
2527
.use(emoji)
2628
.use(anchor, Object.assign({ permalink: true, permalinkBefore: true }, markdown.anchor))

‎lib/webpack/baseConfig.js

+27-20
Original file line numberDiff line numberDiff line change
@@ -134,26 +134,33 @@ module.exports = function createBaseConfig ({
134134
})
135135

136136
function createCSSRule (lang, test, loader, options) {
137-
const rule = config.module
138-
.rule(lang)
139-
.test(test)
140-
141-
if (isProd) {
142-
rule
143-
.use('extract-css-loader').loader(CSSExtractPlugin.loader).end()
144-
.use('css-loader').loader('css-loader').options({ minimize: true })
145-
} else {
146-
rule
147-
.use('vue-style-loader').loader('vue-style-loader').end()
148-
.use('css-loader').loader('css-loader')
149-
}
150-
151-
rule.use('postcss-loader').loader('postcss-loader').options({
152-
plugins: [require('autoprefixer')]
153-
})
154-
155-
if (loader) {
156-
rule.use(loader).loader(loader).options(options)
137+
const baseRule = config.module.rule(lang).test(test)
138+
const modulesRule = baseRule.oneOf('modules').resourceQuery(/module/)
139+
const normalRule = baseRule.oneOf('normal')
140+
141+
applyLoaders(modulesRule, true)
142+
applyLoaders(normalRule, false)
143+
144+
function applyLoaders (rule, modules) {
145+
if (isProd) {
146+
rule.use('extract-css-loader').loader(CSSExtractPlugin.loader)
147+
} else {
148+
rule.use('vue-style-loader').loader('vue-style-loader')
149+
}
150+
151+
rule.use('css-loader').loader('css-loader').options({
152+
modules,
153+
minimize: isProd,
154+
localIdentName: `[local]_[hash:base64:8]`
155+
})
156+
157+
rule.use('postcss-loader').loader('postcss-loader').options({
158+
plugins: [require('autoprefixer')]
159+
})
160+
161+
if (loader) {
162+
rule.use(loader).loader(loader).options(options)
163+
}
157164
}
158165
}
159166

‎lib/webpack/markdownLoader.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ const frontmatter = require('yaml-front-matter')
44
module.exports = function (src) {
55
const { markdown } = getOptions(this)
66
const content = frontmatter.loadFront(src).__content
7-
const html = markdown.render(content)
8-
return `<template><div class="markdown">${html}</div></template>`
7+
const { html, hoistedTags } = markdown.renderWithHoisting(content)
8+
return (
9+
`<template>\n` +
10+
`<div class="markdown">${html}</div>\n` +
11+
`</template>\n` +
12+
hoistedTags.join('\n')
13+
)
914
}

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"rimraf": "^2.6.2",
7171
"url-loader": "^1.0.1",
7272
"vue": "^2.5.16",
73-
"vue-loader": "^15.0.0-beta.7",
73+
"vue-loader": "^15.0.0-rc.1",
7474
"vue-router": "^3.0.1",
7575
"vue-server-renderer": "^2.5.16",
7676
"vue-template-compiler": "^2.5.16",

‎yarn.lock

+3-3
Original file line numberDiff line numberDiff line change
@@ -5766,9 +5766,9 @@ vue-hot-reload-api@^2.3.0:
57665766
version "2.3.0"
57675767
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz#97976142405d13d8efae154749e88c4e358cf926"
57685768

5769-
vue-loader@^15.0.0-beta.7:
5770-
version "15.0.0-beta.7"
5771-
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.0.0-beta.7.tgz#2066ea26a940eed1fd97d2751c6abf5282f87b54"
5769+
vue-loader@^15.0.0-rc.1:
5770+
version "15.0.0-rc.1"
5771+
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.0.0-rc.1.tgz#b34009276e7681f541967e151357b56158efa9b3"
57725772
dependencies:
57735773
"@vue/component-compiler-utils" "^1.0.0"
57745774
hash-sum "^1.0.2"

0 commit comments

Comments
 (0)
Please sign in to comment.