Skip to content

Commit c72cd5f

Browse files
author
undefined
committed
1.1.0
1 parent 10591c3 commit c72cd5f

File tree

6 files changed

+9291
-7330
lines changed

6 files changed

+9291
-7330
lines changed

example/src/markdown.md

Lines changed: 10 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,15 @@
11

2-
# Hello
3-
4-
`<span>{{sss}}</span>`
5-
6-
> This is test.
7-
8-
- How are you?
9-
- Fine, Thank you, and you?
10-
- I'm fine, too. Thank you.
11-
- 🌚
12-
13-
```javascript
14-
import Vue from 'vue'
15-
16-
Vue.config.debug = true
17-
```
18-
19-
<div class="test">
20-
{{ model }} test
21-
</div>
22-
23-
<compo>{{ model }}</compo>
24-
25-
<div
26-
class="abc"
27-
@click="show = false">
28-
啊哈哈哈
29-
</div>
30-
31-
> All script or style tags in html mark will be extracted.Script will be excuted, and style will be added to document head.
32-
> Notice if there is a string instance which contains special word "&lt;/script>", it will fetch a SyntaxError.
33-
> Due to the complexity to solve it, just don't do that.
342
```html
35-
<style scoped>
36-
.test {
37-
background-color: green;
38-
}
39-
</style>
40-
41-
<style scoped>
42-
.abc {
43-
background-color: yellow;
44-
}
45-
</style>
46-
<script>
47-
let a=1<2;
48-
let b="<-forget it-/script>";
49-
console.log("***This script tag is successfully extracted and excuted.***")
50-
module.exports = {
51-
components: {
52-
compo: {
53-
render(h) {
54-
return h('div', {
55-
style: {
56-
background: 'red'
57-
}
58-
}, this.$slots.default);
59-
}
60-
}
61-
},
62-
63-
data () {
64-
return {
65-
model: 'abc'
66-
}
67-
}
68-
}
69-
</script>
70-
jjjjjjjjjjjjjjjjjjjjjj
713
<template>
72-
<div></div>
4+
<div id="components-button-demo-button-group">
5+
</div>
736
</template>
7+
<style>
8+
#components-button-demo-button-group h4 {
9+
margin: 16px 0;
10+
font-size: 14px;
11+
line-height: 1;
12+
font-weight: normal;
13+
}
14+
</style>
7415
```
75-
76-
77-
78-
<div>
79-
</div>
80-
81-
sadfsfs
82-
83-
大家哦哦好啊谁都发生地方上的冯绍峰s
84-
85-
> sahhhh
86-
87-
<compo>{{ model }}</compo>
88-
89-
```html
90-
<compo>{{model }}{{model }}{{model }}{{model }}{{ model }}</compo>
91-
```
92-
93-
94-
95-
<style src="./custom.css"></style>
96-
97-
## 引入 style 文件
98-
99-
<div class="custom">
100-
原谅色
101-
</div>

example/webpack.config.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
var resolve = require("path").resolve;
22
var webpack = require("webpack");
3+
const VueLoaderPlugin = require('vue-loader/lib/plugin');
34

45
module.exports = {
56
entry: "./src/entry.js",
@@ -28,13 +29,18 @@ module.exports = {
2829
},
2930
{
3031
test: /\.md$/,
31-
loader: resolve(__dirname, "../index.js"),
32-
options: {}
32+
use: ['vue-loader', {
33+
loader: resolve(__dirname, "../index.js"),
34+
options: {wrapper: 'div', raw: true}
35+
}],
3336
}
3437
]
3538
},
3639
devServer: {
3740
historyApiFallback: true,
3841
noInfo: true
39-
}
42+
},
43+
plugins: [
44+
new VueLoaderPlugin(),
45+
],
4046
};

lib/core.js

Lines changed: 160 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,166 @@
1-
var path = require('path');
21
var loaderUtils = require('loader-utils');
2+
var hljs = require('highlight.js');
3+
var cheerio = require('cheerio');
4+
var markdown = require('markdown-it');
5+
var Token = require('markdown-it/lib/token');
36

4-
var markdownCompilerPath = path.resolve(__dirname, 'markdown-compiler.js');
7+
/**
8+
* `<pre></pre>` => `<pre v-pre></pre>`
9+
* `<code></code>` => `<code v-pre></code>`
10+
* @param {string} str
11+
* @return {string}
12+
*/
13+
var addVuePreviewAttr = function(str) {
14+
return str.replace(/(<pre|<code)/g, '$1 v-pre');
15+
};
516

6-
module.exports = function(source) {
7-
this.cacheable();
8-
9-
this.options.__vueMarkdownOptions__ =
10-
this.query || this.vueMarkdown || this.options.vueMarkdown || {};
11-
12-
var filePath = this.resourcePath;
13-
var vueLoaderOptions = this.query && this.query.vueLoaderOptions
14-
var result =
15-
'module.exports = require(' +
16-
loaderUtils.stringifyRequest(
17-
this,
18-
'!!vue-loader' +
19-
(vueLoaderOptions ? `?${JSON.stringify(vueLoaderOptions)}` : '') +
20-
'!' +
21-
markdownCompilerPath +
22-
'?raw!' +
23-
filePath +
24-
(this.resourceQuery || '')
25-
) +
26-
');';
17+
/**
18+
* renderHighlight
19+
* @param {string} str
20+
* @param {string} lang
21+
*/
22+
var renderHighlight = function(str, lang) {
23+
if (!(lang && hljs.getLanguage(lang))) {
24+
return '';
25+
}
26+
27+
return hljs.highlight(lang, str, true).value;
28+
};
29+
30+
/**
31+
* html => vue file template
32+
* @param {[type]} html [description]
33+
* @return {[type]} [description]
34+
*/
35+
var renderVueTemplate = function(html, wrapper) {
36+
var $ = cheerio.load(html, {
37+
decodeEntities: false,
38+
lowerCaseAttributeNames: false,
39+
lowerCaseTags: false,
40+
xmlMode: true,
41+
});
42+
43+
var output = {
44+
style: $.html('style'),
45+
// get only the first script child. Causes issues if multiple script files in page.
46+
script: $.html($('script').first())
47+
};
48+
var result;
49+
50+
$('style').remove();
51+
$('script').remove();
52+
if(wrapper) {
53+
result =
54+
`<template><${wrapper}>` +
55+
$.html() +
56+
`</${wrapper}></template>\n`
57+
} else {
58+
result =
59+
`<template>` +
60+
$.html() +
61+
`</template>\n`
62+
}
63+
result += output.style + '\n' + output.script;
2764

2865
return result;
2966
};
67+
68+
module.exports = function(source) {
69+
this.cacheable && this.cacheable();
70+
var parser, preprocess;
71+
var opts = loaderUtils.getOptions(this);
72+
var preventExtract = false;
73+
if (opts.preventExtract) {
74+
delete opts.preventExtract;
75+
preventExtract = true;
76+
}
77+
78+
if (typeof opts.render === 'function') {
79+
parser = opts;
80+
} else {
81+
opts = Object.assign(
82+
{
83+
preset: 'default',
84+
html: true,
85+
highlight: renderHighlight,
86+
wrapper: 'section'
87+
},
88+
opts
89+
);
90+
91+
var plugins = opts.use;
92+
preprocess = opts.preprocess;
93+
94+
delete opts.use;
95+
delete opts.preprocess;
96+
97+
parser = markdown(opts.preset, opts);
98+
99+
//add ruler:extract script and style tags from html token content
100+
!preventExtract &&
101+
parser.core.ruler.push('extract_script_or_style', function replace(
102+
state
103+
) {
104+
let tag_reg = new RegExp('<(script|style)(?:[^<]|<)+</\\1>', 'g');
105+
let newTokens = [];
106+
state.tokens
107+
.filter(token => token.type == 'fence' && token.info == 'html')
108+
.forEach(token => {
109+
let tokens = (token.content.match(tag_reg) || []).map(content => {
110+
let t = new Token('html_block', '', 0);
111+
t.content = content;
112+
return t;
113+
});
114+
if (tokens.length > 0) {
115+
newTokens.push.apply(newTokens, tokens);
116+
}
117+
});
118+
state.tokens.push.apply(state.tokens, newTokens);
119+
});
120+
121+
if (plugins) {
122+
plugins.forEach(function(plugin) {
123+
if (Array.isArray(plugin)) {
124+
parser.use.apply(parser, plugin);
125+
} else {
126+
parser.use(plugin);
127+
}
128+
});
129+
}
130+
}
131+
132+
/**
133+
* override default parser rules by adding v-pre attribute on 'code' and 'pre' tags
134+
* @param {Array<string>} rules rules to override
135+
*/
136+
function overrideParserRules(rules) {
137+
if (parser && parser.renderer && parser.renderer.rules) {
138+
var parserRules = parser.renderer.rules;
139+
rules.forEach(function(rule) {
140+
if (parserRules && parserRules[rule]) {
141+
var defaultRule = parserRules[rule];
142+
parserRules[rule] = function() {
143+
return addVuePreviewAttr(defaultRule.apply(this, arguments));
144+
};
145+
}
146+
});
147+
}
148+
}
149+
150+
overrideParserRules(['code_inline', 'code_block', 'fence']);
151+
152+
if (preprocess) {
153+
source = preprocess.call(this, parser, source);
154+
}
155+
156+
source = source.replace(/@/g, '__at__');
157+
158+
var content = parser.render(source).replace(/__at__/g, '@');
159+
var result = renderVueTemplate(content, opts.wrapper);
160+
161+
if (opts.raw) {
162+
return result;
163+
} else {
164+
return 'module.exports = ' + JSON.stringify(result);
165+
}
166+
};

0 commit comments

Comments
 (0)