diff --git a/src/core/render/index.js b/src/core/render/index.js
index a76b4992..bedd8bb0 100644
--- a/src/core/render/index.js
+++ b/src/core/render/index.js
@@ -70,7 +70,6 @@ function renderMain(html) {
if (
!vueGlobalData &&
docsifyConfig.vueGlobalOptions &&
- docsifyConfig.vueGlobalOptions.data &&
typeof docsifyConfig.vueGlobalOptions.data === 'function'
) {
vueGlobalData = docsifyConfig.vueGlobalOptions.data();
@@ -110,35 +109,44 @@ function renderMain(html) {
dom.find(markdownElm, cssSelector),
vueConfig,
])
- .filter(([elm, vueConfig]) => elm)
+ .filter(
+ ([elm, vueConfig]) => elm && Object.keys(vueConfig || {}).length
+ )
);
// vueGlobalOptions
- vueMountData.push(
- ...dom
- .findAll('.markdown-section > *')
- // Remove duplicates
- .filter(elm => !vueMountData.some(([e, c]) => e === elm))
- .map(elm => [
- elm,
- !vueGlobalData
- ? {}
- : // Replace data() return value with shared data object. This
- // mimics the behavior of a global store when using the same
- // configuration with multiple Vue instances.
- Object.assign({}, docsifyConfig.vueGlobalOptions || {}, {
- data() {
- return vueGlobalData;
- },
- }),
- ])
- );
+ if (Object.keys(docsifyConfig.vueGlobalOptions || {}).length) {
+ vueMountData.push(
+ ...dom
+ .findAll('.markdown-section > *')
+ // Remove duplicates
+ .filter(elm => !vueMountData.some(([e, c]) => e === elm))
+ .map(elm => [
+ elm,
+ !vueGlobalData
+ ? docsifyConfig.vueGlobalOptions
+ : // Replace vueGlobalOptions data() return value with shared data
+ // object. This provides a global store for all Vue instances
+ // that receive vueGlobalOptions as their configuration.
+ Object.assign({}, docsifyConfig.vueGlobalOptions, {
+ data() {
+ return vueGlobalData;
+ },
+ }),
+ ])
+ );
+ }
for (const [mountElm, vueConfig] of vueMountData) {
- const isValidTag = mountElm.tagName !== 'SCRIPT';
- const hasBrackets = /{{2}[^{}]*}{2}/.test(mountElm.outerHTML);
+ const isVueMount =
+ // Valid tag
+ mountElm.tagName !== 'SCRIPT' &&
+ // Matches curly braces or HTML directives
+ /{{2}[^{}]*}{2}|\sv-(bind|cloak|else|else-if|for|html|if|is|model|on|once|pre|show|slot|text)=/.test(
+ mountElm.outerHTML
+ );
- if (isValidTag && hasBrackets && !isMountedVue(mountElm)) {
+ if (isVueMount && !isMountedVue(mountElm)) {
if (vueVersion === 2) {
new window.Vue(vueConfig).$mount(mountElm);
} else if (vueVersion === 3) {
diff --git a/test/e2e/vue.test.js b/test/e2e/vue.test.js
index 395eac57..1bbd3bc0 100644
--- a/test/e2e/vue.test.js
+++ b/test/e2e/vue.test.js
@@ -1,141 +1,183 @@
+const stripIndent = require('common-tags/lib/stripIndent');
const docsifyInit = require('../helpers/docsify-init');
-describe('Vue.js Rendering', function() {
- const vueURLs = [
- `${NODE_MODULES_URL}/vue2/dist/vue.js`,
- `${NODE_MODULES_URL}/vue3/dist/vue.global.js`,
- ];
+const vueURLs = [
+ `${NODE_MODULES_URL}/vue2/dist/vue.js`,
+ `${NODE_MODULES_URL}/vue3/dist/vue.global.js`,
+];
- // Tests
- // ---------------------------------------------------------------------------
- test(`ignores Vue content when window.Vue is not present`, async () => {
- await docsifyInit({
- markdown: {
- homepage: `
-
test{{ i }}
- `,
- },
- });
-
- await page.evaluate(() => {
- return 'Vue' in window === false;
- });
- await expect(page).toEqualText('#test', 'test{{ i }}');
- });
-
- describe('Basic rendering', function() {
- for (const vueURL of vueURLs) {
- const vueVersion = vueURL.match(/vue(\d+)/)[1]; // vue2|vue3
-
- for (const executeScript of ['unspecified', true, false]) {
- test(`handles Vue v${vueVersion}.x basic rendering when executeScript is ${executeScript}`, async () => {
- const docsifyInitConfig = {
- markdown: {
- homepage: `
- test{{ i }}
- `,
- },
- scriptURLs: vueURL,
- };
-
- if (executeScript !== 'unspecified') {
- docsifyInitConfig.config = {
- executeScript,
+describe('Vue.js Compatibility', function() {
+ function getSharedConfig() {
+ const config = {
+ config: {
+ vueGlobalOptions: {
+ data: function() {
+ return {
+ counter: 0,
+ msg: 'vueglobaloptions',
};
- }
-
- await docsifyInit(docsifyInitConfig);
-
- await expect(page).toEqualText('#test', 'test12345');
- });
- }
- }
- });
-
- describe('Advanced usage', function() {
- const testData = {
- vue2: {
- markdown: `
-
-
- {{ counter }}
-
-
-
- `,
+ },
+ },
+ vueOptions: {
+ '#vueoptions': {
+ data: function() {
+ return {
+ counter: 0,
+ msg: 'vueoptions',
+ };
+ },
+ },
+ },
},
- vue3: {
- markdown: `
-
+ markdown: {
+ homepage: stripIndent`
+ #
{{ i }}
+
+
+
---
+
+
{{ counter }}
+
+
+
+
---
+
+
{{ counter }}
+
+
+
`,
},
};
+ return config;
+ }
+
+ // Tests
+ // ---------------------------------------------------------------------------
+ describe('Ignores Vue', function() {
+ test(`content when Vue is not present`, async () => {
+ const docsifyInitConfig = getSharedConfig();
+
+ await docsifyInit(docsifyInitConfig);
+ await page.evaluate(() => {
+ return 'Vue' in window === false;
+ });
+ await expect(page).toEqualText('h1', '{{ i }}');
+ await expect(page).toEqualText('#vueglobaloptions p', '---');
+ await expect(page).toEqualText('#vueoptions p', '---');
+ await expect(page).toEqualText('#vuescript p', '---');
+ });
+
+ test(`content when vueOptions and vueGlobalOptions are undefined`, async () => {
+ const docsifyInitConfig = getSharedConfig();
+
+ docsifyInitConfig.config.vueGlobalOptions = undefined;
+ docsifyInitConfig.config.vueOptions = undefined;
+ docsifyInitConfig.scriptURLs = vueURLs[0];
+
+ await docsifyInit(docsifyInitConfig);
+ await expect(page).toEqualText('h1', '{{ i }}');
+ await expect(page).toEqualText('#vueglobaloptions p', '---');
+ await expect(page).toEqualText('#vueoptions p', '---');
+ await expect(page).toEqualText('#vuescript p', 'vuescript');
+ });
+
+ test(`content when vueGlobalOptions data is undefined`, async () => {
+ const docsifyInitConfig = getSharedConfig();
+
+ docsifyInitConfig.config.vueGlobalOptions.data = undefined;
+ docsifyInitConfig.scriptURLs = vueURLs[0];
+
+ await docsifyInit(docsifyInitConfig);
+ await expect(page).toEqualText('h1', '{{ i }}');
+ await expect(page).toEqualText('#vueoptions p', 'vueoptions');
+ await expect(page).toEqualText('#vueglobaloptions p', '---');
+ await expect(page).toEqualText('#vuescript p', 'vuescript');
+ });
+
+ test(`content when vueOptions data is undefined`, async () => {
+ const docsifyInitConfig = getSharedConfig();
+
+ docsifyInitConfig.config.vueOptions['#vueoptions'].data = undefined;
+ docsifyInitConfig.scriptURLs = vueURLs[0];
+
+ await docsifyInit(docsifyInitConfig);
+ await expect(page).toEqualText('h1', '12345');
+ await expect(page).toEqualText('#vueoptions p', 'vueglobaloptions');
+ await expect(page).toEqualText('#vueglobaloptions p', 'vueglobaloptions');
+ await expect(page).toEqualText('#vuescript p', 'vuescript');
+ });
+
+ test(`