Skip to content

Commit

Permalink
feat: support style/script hoisting + css modules
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Apr 6, 2018
1 parent c05448d commit f97e676
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 39 deletions.
5 changes: 0 additions & 5 deletions docs/test.md

This file was deleted.

9 changes: 4 additions & 5 deletions docs/using-vue.md
Expand Up @@ -79,20 +79,19 @@ Make sure a custom component's names either contains a hyphen or is in PascalCas

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.

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

<!-- <style>
#inline-script-style-example {
<style module>
.example {
color: #41b883;
}
</style>

<script>
export default {
mounted () {
document.getElementById('inline-script-style-example')
document.querySelector(`.${this.$style.example}`)
.textContent = 'Hello from inline script!'
}
}
</script>
-->
6 changes: 3 additions & 3 deletions lib/markdown/component.js
@@ -1,7 +1,7 @@
// Replacing the default htmlBlock rule to allow using custom components at
// root level

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

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

module.exports = md => {
md.block.ruler.at('htmlBlock', htmlBlock)
md.block.ruler.at('html_block', htmlBlock)
}

function htmlBlock (state, startLine, endLine, silent) {
Expand Down Expand Up @@ -73,7 +73,7 @@ function htmlBlock (state, startLine, endLine, silent) {

state.line = nextLine

const token = state.push('htmlBlock', '', 0)
const token = state.push('html_block', '', 0)
token.map = [startLine, nextLine]
token.content = state.getLines(startLine, nextLine, state.blkIndent, true)

Expand Down
20 changes: 20 additions & 0 deletions lib/markdown/hoist.js
@@ -1,3 +1,23 @@
module.exports = md => {
const RE = /^<(script|style)(?=(\s|>|$))/i
let hoistedTags

md.renderer.rules.html_block = (tokens, idx) => {
const content = tokens[idx].content
if (hoistedTags && RE.test(content.trim())) {
hoistedTags.push(content)
return ''
} else {
return content
}
}

md.renderWithHoisting = (...args) => {
hoistedTags = []
const html = md.render(...args)
return {
html,
hoistedTags
}
}
}
2 changes: 2 additions & 0 deletions lib/markdown/index.js
@@ -1,6 +1,7 @@
const highlight = require('./highlight')
const highlightLines = require('./highlightLines')
const component = require('./component')
const hoistScriptStyle = require('./hoist')
const convertRouterLink = require('./link')
const emoji = require('markdown-it-emoji')
const anchor = require('markdown-it-anchor')
Expand All @@ -21,6 +22,7 @@ module.exports = ({ markdown = {}}) => {
.use(component)
.use(highlightLines)
.use(convertRouterLink)
.use(hoistScriptStyle)
// 3rd party plugins
.use(emoji)
.use(anchor, Object.assign({ permalink: true, permalinkBefore: true }, markdown.anchor))
Expand Down
47 changes: 27 additions & 20 deletions lib/webpack/baseConfig.js
Expand Up @@ -134,26 +134,33 @@ module.exports = function createBaseConfig ({
})

function createCSSRule (lang, test, loader, options) {
const rule = config.module
.rule(lang)
.test(test)

if (isProd) {
rule
.use('extract-css-loader').loader(CSSExtractPlugin.loader).end()
.use('css-loader').loader('css-loader').options({ minimize: true })
} else {
rule
.use('vue-style-loader').loader('vue-style-loader').end()
.use('css-loader').loader('css-loader')
}

rule.use('postcss-loader').loader('postcss-loader').options({
plugins: [require('autoprefixer')]
})

if (loader) {
rule.use(loader).loader(loader).options(options)
const baseRule = config.module.rule(lang).test(test)
const modulesRule = baseRule.oneOf('modules').resourceQuery(/module/)
const normalRule = baseRule.oneOf('normal')

applyLoaders(modulesRule, true)
applyLoaders(normalRule, false)

function applyLoaders (rule, modules) {
if (isProd) {
rule.use('extract-css-loader').loader(CSSExtractPlugin.loader)
} else {
rule.use('vue-style-loader').loader('vue-style-loader')
}

rule.use('css-loader').loader('css-loader').options({
modules,
minimize: isProd,
localIdentName: `[local]_[hash:base64:8]`
})

rule.use('postcss-loader').loader('postcss-loader').options({
plugins: [require('autoprefixer')]
})

if (loader) {
rule.use(loader).loader(loader).options(options)
}
}
}

Expand Down
9 changes: 7 additions & 2 deletions lib/webpack/markdownLoader.js
Expand Up @@ -4,6 +4,11 @@ const frontmatter = require('yaml-front-matter')
module.exports = function (src) {
const { markdown } = getOptions(this)
const content = frontmatter.loadFront(src).__content
const html = markdown.render(content)
return `<template><div class="markdown">${html}</div></template>`
const { html, hoistedTags } = markdown.renderWithHoisting(content)
return (
`<template>\n` +
`<div class="markdown">${html}</div>\n` +
`</template>\n` +
hoistedTags.join('\n')
)
}
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -70,7 +70,7 @@
"rimraf": "^2.6.2",
"url-loader": "^1.0.1",
"vue": "^2.5.16",
"vue-loader": "^15.0.0-beta.7",
"vue-loader": "^15.0.0-rc.1",
"vue-router": "^3.0.1",
"vue-server-renderer": "^2.5.16",
"vue-template-compiler": "^2.5.16",
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Expand Up @@ -5766,9 +5766,9 @@ vue-hot-reload-api@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz#97976142405d13d8efae154749e88c4e358cf926"

vue-loader@^15.0.0-beta.7:
version "15.0.0-beta.7"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.0.0-beta.7.tgz#2066ea26a940eed1fd97d2751c6abf5282f87b54"
vue-loader@^15.0.0-rc.1:
version "15.0.0-rc.1"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.0.0-rc.1.tgz#b34009276e7681f541967e151357b56158efa9b3"
dependencies:
"@vue/component-compiler-utils" "^1.0.0"
hash-sum "^1.0.2"
Expand Down

0 comments on commit f97e676

Please sign in to comment.