mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(vant-markdown-loader): 增强 README,支持通过声明的方式引入 demo 并直接预览
This commit is contained in:
parent
c0b10e4374
commit
a913f5bd36
24
packages/vant-markdown-loader/src/extract-demo.js
Normal file
24
packages/vant-markdown-loader/src/extract-demo.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = function extraDemo(content) {
|
||||||
|
const demoLinks = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 提取 README 中的 demo 文件路径,例如下面的内容,就会提取为 ['./demo-link/index.vue']
|
||||||
|
* ```demo
|
||||||
|
* ./demo-link/index.vue
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
content = content.replace(
|
||||||
|
/<pre><code class="language-demo">([\s\S]*?)<\/code><\/pre>/g,
|
||||||
|
function (_, link) {
|
||||||
|
link = link.trim(); // 去换行符
|
||||||
|
demoLinks.push(link);
|
||||||
|
const demoFileName = path.basename(link, '.vue'); // 获取文件名
|
||||||
|
const tag = demoFileName.replace(/\B([A-Z])/g, '-$1').toLowerCase(); // 驼峰转连字符
|
||||||
|
return `<${tag} />`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return [content, demoLinks];
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
|
const path = require('path');
|
||||||
const loaderUtils = require('loader-utils');
|
const loaderUtils = require('loader-utils');
|
||||||
const MarkdownIt = require('markdown-it');
|
const MarkdownIt = require('markdown-it');
|
||||||
const markdownItAnchor = require('markdown-it-anchor');
|
const markdownItAnchor = require('markdown-it-anchor');
|
||||||
@ -5,18 +6,42 @@ const frontMatter = require('front-matter');
|
|||||||
const highlight = require('./highlight');
|
const highlight = require('./highlight');
|
||||||
const linkOpen = require('./link-open');
|
const linkOpen = require('./link-open');
|
||||||
const cardWrapper = require('./card-wrapper');
|
const cardWrapper = require('./card-wrapper');
|
||||||
|
const extractDemo = require('./extract-demo');
|
||||||
|
const sideEffectTags = require('./side-effect-tags');
|
||||||
const { slugify } = require('transliteration');
|
const { slugify } = require('transliteration');
|
||||||
|
|
||||||
|
function camelize(str) {
|
||||||
|
return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : ''));
|
||||||
|
}
|
||||||
|
|
||||||
function wrapper(content) {
|
function wrapper(content) {
|
||||||
|
const markdownDir = path.dirname(this.resourcePath);
|
||||||
|
let demoLinks;
|
||||||
|
let styles;
|
||||||
|
[content, demoLinks] = extractDemo(content);
|
||||||
|
[content, styles] = sideEffectTags(content);
|
||||||
content = cardWrapper(content);
|
content = cardWrapper(content);
|
||||||
content = escape(content);
|
|
||||||
|
|
||||||
return `
|
return `
|
||||||
import { h } from 'vue';
|
<template>
|
||||||
|
<section>
|
||||||
|
${content}
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
const content = unescape(\`${content}\`);
|
<script>
|
||||||
|
${demoLinks
|
||||||
|
.map((link) => {
|
||||||
|
const absPath = path.join(markdownDir, link); // 获取 demo 文件的完整路径
|
||||||
|
const demoFileName = path.basename(link, '.vue');
|
||||||
|
return `import ${camelize(demoFileName)} from '${absPath}';`;
|
||||||
|
})
|
||||||
|
.join('\n')}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
${demoLinks.map((link) => camelize(path.basename(link, '.vue'))).join(',')}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
const anchors = [].slice.call(this.$el.querySelectorAll('h2, h3, h4, h5'));
|
const anchors = [].slice.call(this.$el.querySelectorAll('h2, h3, h4, h5'));
|
||||||
|
|
||||||
@ -35,11 +60,10 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
|
||||||
return h('section', { innerHTML: content });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
${styles.join('\n')}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,5 +96,5 @@ module.exports = function (source) {
|
|||||||
linkOpen(parser);
|
linkOpen(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
return options.wrapper(parser.render(source), fm);
|
return options.wrapper.call(this, parser.render(source), fm);
|
||||||
};
|
};
|
||||||
|
14
packages/vant-markdown-loader/src/side-effect-tags.js
Normal file
14
packages/vant-markdown-loader/src/side-effect-tags.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = function sideEffectTags(content) {
|
||||||
|
const styles = [];
|
||||||
|
|
||||||
|
// 从模版中移除 script 标签
|
||||||
|
content = content.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/g, '');
|
||||||
|
|
||||||
|
// 从模版中移除 style 标签,并收集到 styles 数组中,以转移为 .vue 文件 的 style 标签
|
||||||
|
content = content.replace(/<style[\s\S]*?>([\s\S]*?)<\/style>/g, (_, css) => {
|
||||||
|
styles.push(`<style scoped>${css}</style>`);
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
|
return [content, styles];
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user