Skip to content

Commit

Permalink
WIP add tests for isExternal and SSR (to make sure SSR works and thus…
Browse files Browse the repository at this point in the history
… isExternal using DOMPUrify works within SSR)
  • Loading branch information
trusktr committed Jul 5, 2020
1 parent 22f1b2b commit 6be2965
Show file tree
Hide file tree
Showing 17 changed files with 191 additions and 89 deletions.
36 changes: 18 additions & 18 deletions build/ssr.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var rollup = require('rollup')
var buble = require('rollup-plugin-buble')
var async = require('rollup-plugin-async')
var replace = require('rollup-plugin-replace')
var rollup = require('rollup');
var buble = require('rollup-plugin-buble');
var async = require('rollup-plugin-async');
var replace = require('rollup-plugin-replace');

rollup
.rollup({
Expand All @@ -10,26 +10,26 @@ rollup
async(),
replace({
__VERSION__: process.env.VERSION || require('../package.json').version,
'process.env.SSR': true
'process.env.SSR': true,
}),
buble({
transforms: {
generator: false
}
})
generator: false,
},
}),
],
onwarn: function () {}
onwarn: function() {},
})
.then(function (bundle) {
var dest = 'packages/docsify-server-renderer/build.js'
.then(function(bundle) {
var dest = 'packages/docsify-server-renderer/build.js';

console.log(dest)
console.log(dest);
return bundle.write({
format: 'cjs',
file: dest
})
})
.catch(function (err) {
console.error(err)
process.exit(1)
file: dest,
});
})
.catch(function(err) {
console.error(err);
process.exit(1);
});
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"dev:ssr": "run-p serve:ssr watch:*",
"lint": "eslint .",
"fixlint": "eslint . --fix",
"test": "mocha ./test/**/*.test.js",
"test": "mocha `glob './test/**/*.test.js'` `glob './packages/docsify-server-renderer/src/**/*.test.js'`",
"testServer": "node cypress/setup.js",
"test:e2e": "start-server-and-test testServer http://localhost:3000 cy:run",
"posttest:e2e": "rimraf cypress/fixtures/docs",
Expand All @@ -48,7 +48,7 @@
"pub": "sh build/release.sh",
"postinstall": "opencollective-postinstall"
},
"husky": {
"husky-OFF": {
"hooks": {
"pre-commit": "lint-staged"
}
Expand All @@ -71,6 +71,7 @@
"babel-eslint": "^10.0.3",
"chai": "^4.2.0",
"chokidar": "^3.2.1",
"cli-glob": "^0.1.0",
"conventional-changelog-cli": "^2.0.25",
"copy-dir": "^1.2.0",
"cross-env": "^6.0.3",
Expand Down
22 changes: 5 additions & 17 deletions packages/docsify-server-renderer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,15 @@ import { Compiler } from '../../src/core/render/compiler';
import { isAbsolutePath } from '../../src/core/router/util';
import * as tpl from '../../src/core/render/tpl';
import { prerenderEmbed } from '../../src/core/render/embed';
import { getServerHTMLTemplate } from './template';
import { isExternal } from './src/utils';

export { getServerHTMLTemplate };

function cwd(...args) {
return resolve(process.cwd(), ...args);
}

// Borrowed from https://j11y.io/snippets/getting-a-fully-qualified-url.
function qualifyURL(url) {
const img = document.createElement('img');
img.src = url; // set string url
url = img.src; // get qualified url
img.src = ''; // prevent the server request
return url;
}

function isExternal(url) {
url = qualifyURL(url);
url = new URL(url);
return url.origin !== location.origin;
}

function mainTpl(config) {
let html = `<nav class="app-nav${
config.repo ? '' : ' no-badge'
Expand All @@ -48,12 +37,11 @@ function mainTpl(config) {
}

export default class Renderer {
constructor({ template, config, cache }) {
constructor({ template, config }) {
this.html = template;
this.config = config = Object.assign({}, config, {
routerMode: 'history',
});
this.cache = cache;

this.router = new AbstractHistory(config);
this.compiler = new Compiler(config, this.router);
Expand Down
14 changes: 14 additions & 0 deletions packages/docsify-server-renderer/src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Borrowed from https://j11y.io/snippets/getting-a-fully-qualified-url.
export function qualifyURL(url) {
const img = document.createElement('img');
img.src = url; // set string url
url = img.src; // get qualified url
img.src = ''; // prevent the server request
return url;
}

export function isExternal(url) {
url = qualifyURL(url);
url = new URL(url);
return url.origin !== location.origin;
}
24 changes: 24 additions & 0 deletions packages/docsify-server-renderer/src/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* eslint-disable no-global-assign */
require = require('esm')(module /* , options */);
const { expect } = require('chai');
const { initJSDOM } = require('../../../test/_helper');
const { isExternal } = require('./utils');

describe('isExternal', () => {
it('detects whether links are external or not', async () => {
initJSDOM('', {
url: 'http://127.0.0.1:3000',
runScripts: 'dangerously',
resources: 'usable',
});

expect(isExternal).to.be.instanceOf(Function);
expect(isExternal('/foo.md')).to.be.false;
expect(isExternal('//foo.md')).to.be.true;
expect(isExternal('//127.0.0.1:3000/foo.md')).to.be.false;
expect(isExternal('http://127.0.0.1:3001/foo.md')).to.be.true;
expect(isExternal('https://google.com/foo.md')).to.be.true;
expect(isExternal('//google.com/foo.md')).to.be.true;
expect(isExternal('/google.com/foo.md')).to.be.false;
});
});
17 changes: 17 additions & 0 deletions packages/docsify-server-renderer/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>docsify</title>
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<link rel="stylesheet" href="/themes/vue.css" title="vue" />
</head>
<body>
<!--inject-app-->
<!--inject-config-->
<script src="/lib/docsify.js"></script>
</body>
</html>
8 changes: 8 additions & 0 deletions packages/docsify-server-renderer/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import fs from 'fs';
import path from 'path';

const tmplPath = path.resolve(__dirname, 'template.html');

export function getServerHTMLTemplate() {
return fs.readFileSync(tmplPath).toString();
}
57 changes: 28 additions & 29 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
const liveServer = require('live-server')
const isSSR = !!process.env.SSR
const middleware = []
const liveServer = require('live-server');
const isSSR = !!process.env.SSR;
const middleware = [];

if (isSSR) {
const Renderer = require('./packages/docsify-server-renderer/build.js')
const { initJSDOM } = require('./test/_helper');

const dom = initJSDOM('', {
url: 'https://127.0.0.1:3000',
});

require = require('esm')(module /* , options */);

const {
Renderer,
getServerHTMLTemplate,
} = require('./packages/docsify-server-renderer/index');

debugger;

const renderer = new Renderer({
template: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>docsify</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="/themes/vue.css" title="vue">
</head>
<body>
<!--inject-app-->
<!--inject-config-->
<script src="/lib/docsify.js"></script>
</body>
</html>`,
template: getServerHTMLTemplate(),
config: {
name: 'docsify',
repo: 'docsifyjs/docsify',
Expand All @@ -32,24 +32,23 @@ if (isSSR) {
'/de-de/changelog': '/changelog',
'/zh-cn/changelog': '/changelog',
'/changelog':
'https://github.com/raw/docsifyjs/docsify/master/CHANGELOG'
}
'https://github.com/raw/docsifyjs/docsify/master/CHANGELOG',
},
},
path: './'
})
});

middleware.push(function(req, res, next) {
if (/\.(css|js)$/.test(req.url)) {
return next()
return next();
}
renderer.renderToString(req.url).then(html => res.end(html))
})
renderer.renderToString(req.url).then(html => res.end(html));
});
}

const params = {
port: 3000,
watch: ['lib', 'docs', 'themes'],
middleware
}
middleware,
};

liveServer.start(params)
liveServer.start(params);
16 changes: 1 addition & 15 deletions src/core/fetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { callHook } from '../init/lifecycle';
import { getParentPath, stringifyQuery } from '../router/util';
import { noop } from '../util/core';
import { getAndActive } from '../event/sidebar';
import { isExternal } from '../../../packages/docsify-server-renderer/src/utils';
import { get } from './ajax';

function loadNested(path, qs, file, next, vm, first) {
Expand All @@ -20,21 +21,6 @@ function loadNested(path, qs, file, next, vm, first) {
).then(next, _ => loadNested(path, qs, file, next, vm));
}

// Borrowed from https://j11y.io/snippets/getting-a-fully-qualified-url.
function qualifyURL(url) {
const img = document.createElement('img');
img.src = url; // set string url
url = img.src; // get qualified url
img.src = ''; // prevent the server request
return url;
}

export function isExternal(url) {
url = qualifyURL(url);
url = new URL(url);
return url.origin !== location.origin;
}

export function fetchMixin(proto) {
let last;

Expand Down
1 change: 1 addition & 0 deletions src/core/render/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export class Compiler {
return html;
})(text);

// TODO parse() expects an arg, but here it does not receive an arg so it fails.
const curFileName = this.router.parse().file;

if (isCached) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/render/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getPath, isAbsolutePath } from '../router/util';
import { isMobile, inBrowser } from '../util/env';
import { isPrimitive } from '../util/core';
import { scrollActiveSidebar } from '../event/scroll';
import { isExternal } from '../fetch';
import { isExternal } from '../../../packages/docsify-server-renderer/src/utils';
import { Compiler } from './compiler';
import * as tpl from './tpl';
import { prerenderEmbed } from './embed';
Expand Down
2 changes: 1 addition & 1 deletion src/core/router/history/abstract.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class AbstractHistory extends History {
this.mode = 'abstract';
}

parse(path) {
parse(path = location.href) {
let query = '';

const queryIndex = path.indexOf('?');
Expand Down
1 change: 1 addition & 0 deletions src/plugins/search/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ function updateOptions(opts) {
}

export function init(opts, vm) {
// TODO FIXME parse() expects an argument
const keywords = vm.router.parse().query.s;

updateOptions(opts);
Expand Down
8 changes: 7 additions & 1 deletion test/_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ function ready(callback) {

module.exports.initJSDOM = initJSDOM;

/** @param {string} markup - The HTML document to initialize JSDOM with. */
/**
* Creates a JSDOM instance and assigns the following variables to Node's
* `global`: window, document, navigator, location, XMLHttpRequest.
*
* @param {string} markup - The HTML document to initialize JSDOM with.
* @param {object} options - Options to pass to JSDOM. See https://github.com/jsdom/jsdom#customizing-jsdom
*/
function initJSDOM(markup = '', options = {}) {
const dom = new JSDOM(markup, options);

Expand Down
1 change: 0 additions & 1 deletion test/unit/docsify.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ describe('Docsify public API', () => {
});

it('global APIs are available', async () => {
// const DOM = new (require('jsdom').JSDOM)(markup, {
const DOM = initJSDOM(markup, {
url: docsifySite,
runScripts: 'dangerously',
Expand Down
Loading

0 comments on commit 6be2965

Please sign in to comment.