Skip to content

update src/core/index.js to export all global APIs, deprecate old globals… #1195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion build/build.js
Original file line number Diff line number Diff line change
@@ -9,6 +9,14 @@ const version = process.env.VERSION || require('../package.json').version
const chokidar = require('chokidar')
const path = require('path')

/**
* @param {{
* input: string,
* output?: string,
* globalName?: string,
* plugins?: Array<import('rollup').Plugin>
* }} opts
*/
async function build(opts) {
await rollup
.rollup({
@@ -29,6 +37,7 @@ async function build(opts) {
console.log(dest)
return bundle.write({
format: 'iife',
output: opts.globalName ? {name: opts.globalName} : {},
file: dest,
strict: false
})
@@ -40,13 +49,15 @@ async function buildCore() {

promises.push(build({
input: 'src/core/index.js',
output: 'docsify.js'
output: 'docsify.js',
globalName: 'DOCSIFY'
}))

if (isProd) {
promises.push(build({
input: 'src/core/index.js',
output: 'docsify.min.js',
globalName: 'DOCSIFY',
plugins: [uglify()]
}))
}
441 changes: 315 additions & 126 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@
"eslint-plugin-prettier": "^3.1.2",
"esm": "^3.1.4",
"husky": "^3.1.0",
"jsdom": "^15.1.1",
"jsdom": "^16.2.2",
"lerna": "^3.17.0",
"lint-staged": "^9.5.0",
"live-server": "^1.2.1",
@@ -100,6 +100,7 @@
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-uglify": "^6.0.4",
"serve-handler": "^6.1.2",
"start-server-and-test": "^1.10.6",
"stylus": "^0.54.5"
},
8 changes: 6 additions & 2 deletions src/core/global-api.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import prism from 'prismjs';
import marked from 'marked';
import * as util from './util';
import * as dom from './util/dom';
import { Compiler } from './render/compiler';
import { slugify } from './render/slugify';
import { get } from './fetch/ajax';
import prism from 'prismjs';
import marked from 'marked';

// TODO This is deprecated, kept for backwards compatibility. Remove in next
// major release. We'll tell people to get everything from the DOCSIFY global
// when using the global build, but we'll highly recommend for them to import
// from the ESM build (f.e. lib/docsify.esm.js and lib/docsify.min.esm.js).
export default function() {
window.Docsify = {
util,
31 changes: 13 additions & 18 deletions src/core/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
import Prism from 'prismjs';
import marked from 'marked';
import { initMixin } from './init';
import { routerMixin } from './router';
import { renderMixin } from './render';
import { fetchMixin } from './fetch';
import { eventMixin } from './event';
import initGlobalAPI from './global-api';

/**
* Fork https://github.com/bendrucker/document-ready/blob/master/index.js
* @param {Function} callback The callbacack to be called when the page is loaded
* @returns {Number|void} If the page is already laoded returns the result of the setTimeout callback,
* otherwise it only attaches the callback to the DOMContentLoaded event
*/
export function documentReady(callback) {
const state = document.readyState;

if (state === 'complete' || state === 'interactive') {
return setTimeout(callback, 0);
}

document.addEventListener('DOMContentLoaded', callback);
}
import { Compiler as DocsifyCompiler } from './render/compiler';
import * as util from './util';
import * as dom from './util/dom';
import { slugify } from './render/slugify';
import { get } from './fetch/ajax';

export function Docsify() {
this._init();
@@ -36,10 +27,14 @@ eventMixin(proto);
/**
* Global API
*/
initGlobalAPI();
initGlobalAPI(); // deprecated

// Rollup assigns all exports from this file onto a single DOCSIFY global.
export { util, dom, get, slugify, DocsifyCompiler, marked, Prism };
export const version = '__VERSION__';

/**
* Run Docsify
*/
// eslint-disable-next-line no-unused-vars
documentReady(_ => new Docsify());
dom.documentReady(_ => new Docsify());
16 changes: 16 additions & 0 deletions src/core/util/dom.js
Original file line number Diff line number Diff line change
@@ -101,3 +101,19 @@ export function toggleClass(el, type, val) {
export function style(content) {
appendTo(head, create('style', content));
}

/**
* Fork https://github.com/bendrucker/document-ready/blob/master/index.js
* @param {Function} callback The callbacack to be called when the page is loaded
* @returns {Number|void} If the page is already laoded returns the result of the setTimeout callback,
* otherwise it only attaches the callback to the DOMContentLoaded event
*/
export function documentReady(callback, doc = document) {
const state = doc.readyState;

if (state === 'complete' || state === 'interactive') {
return setTimeout(callback, 0);
}

doc.addEventListener('DOMContentLoaded', callback);
}
182 changes: 114 additions & 68 deletions test/unit/docsify.test.js
Original file line number Diff line number Diff line change
@@ -1,101 +1,147 @@
/* global before after */
/* eslint-disable no-global-assign */
require = require('esm')(module /* , options */);

const path = require('path');
const http = require('http');
const handler = require('serve-handler');
const { expect } = require('chai');
const { initJSDOM } = require('../_helper');

const docsifySite = path.join(__dirname, '..', '..', 'docs');
const docsifySite = 'http://127.0.0.1:3000';

const markup = /* html */ `<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="app"></div>
<script src="/lib/docsify.js"></script>
<script>
//fetch("../lib/docsify.js").then(async r => console.log(r.text()))
</script>
</body>
</html>
`;

/** @type {ReturnType<typeof http.createServer>} */
let server;

describe('Docsify public API', () => {
it('is available', async () => {
const DOM = initJSDOM(markup);
DOM.reconfigure({ url: 'file:///' + docsifySite });

const { documentReady } = require('../../src/core/index');
await new Promise(resolve => documentReady(resolve));

expect(typeof window.Docsify).to.equal('object');
expect(typeof window.Docsify.util).to.equal('object');
expect(typeof window.Docsify.dom).to.equal('object');
expect(typeof window.Docsify.get).to.equal('function');
expect(typeof window.Docsify.slugify).to.equal('function');
expect(typeof window.Docsify.version).to.equal('string');

expect(window.DocsifyCompiler).to.be.an.instanceof(Function);
expect(window.marked).to.be.an.instanceof(Function);
expect(typeof window.Prism).to.equal('object');
before(async () => {
server = http.createServer((request, response) => {
// You pass two more arguments for config and middleware
// More details here: https://github.com/zeit/serve-handler#options
return handler(request, response);
});

await new Promise(r => server.listen(3000, r));
});
});

describe('Docsify config function', function() {
it('allows $docsify to be a function', async function() {
const DOM = initJSDOM(markup);
DOM.reconfigure({ url: 'file:///' + docsifySite });
after(async () => {
server.close(err => {
if (err) {
console.error(err); // eslint-disable-line
process.exit(1);
}
// eslint-disable-next-line
console.log('Server closed.');
});
});

window.configFunctionCalled = false;
it('global APIs are available', async () => {
// const DOM = new (require('jsdom').JSDOM)(markup, {
const DOM = initJSDOM(markup, {
url: docsifySite,
runScripts: 'dangerously',
resources: 'usable',
});

const { documentReady } = require('../../src/core/util/dom');
await new Promise(resolve => documentReady(resolve, DOM.window.document));

// deprecated global API, still works for now, backwards comaptible
expect(typeof DOM.window.Docsify).to.equal('object');
expect(typeof DOM.window.Docsify.util).to.equal('object');
expect(typeof DOM.window.Docsify.dom).to.equal('object');
expect(typeof DOM.window.Docsify.get).to.equal('function');
expect(typeof DOM.window.Docsify.slugify).to.equal('function');
expect(typeof DOM.window.Docsify.version).to.equal('string');
expect(typeof DOM.window.DocsifyCompiler).to.equal('function');
expect(typeof DOM.window.marked).to.equal('function');
expect(typeof DOM.window.Prism).to.equal('object');

// new global API, everything under one namespace (DOCSIFY)
expect(typeof DOM.window.DOCSIFY).to.equal('object');
expect(typeof DOM.window.DOCSIFY.Docsify).to.equal('function');
expect(typeof DOM.window.DOCSIFY.util).to.equal('object');
expect(typeof DOM.window.DOCSIFY.dom).to.equal('object');
expect(typeof DOM.window.DOCSIFY.get).to.equal('function');
expect(typeof DOM.window.DOCSIFY.slugify).to.equal('function');
expect(typeof DOM.window.DOCSIFY.version).to.equal('string');
expect(typeof DOM.window.DOCSIFY.DocsifyCompiler).to.equal('function');
expect(typeof DOM.window.DOCSIFY.marked).to.equal('function');
expect(typeof DOM.window.DOCSIFY.Prism).to.equal('object');
});

window.$docsify = function(vm) {
// Check public API (that which is available at this point)
expect(vm).to.be.an.instanceof(Object);
expect(vm.constructor.name).to.equal('Docsify');
expect(vm.$fetch).to.be.an.instanceof(Function);
expect(vm.$resetEvents).to.be.an.instanceof(Function);
expect(vm.route).to.be.an.instanceof(Object);
describe('Docsify config function', function() {
it('allows $docsify to be a function', async function() {
initJSDOM(markup, { url: docsifySite });

window.configFunctionCalled = true;
window.configFunctionCalled = false;

return {};
};
window.$docsify = function(vm) {
// Check public API (that which is available at this point)
expect(vm).to.be.an.instanceof(Object);
expect(vm.constructor.name).to.equal('Docsify');
expect(vm.$fetch).to.be.an.instanceof(Function);
expect(vm.$resetEvents).to.be.an.instanceof(Function);
expect(vm.route).to.be.an.instanceof(Object);

const { documentReady, Docsify } = require('../../src/core/index');
await new Promise(resolve => documentReady(resolve));
window.configFunctionCalled = true;

new Docsify(); // eslint-disable-line
return {};
};

expect(window.configFunctionCalled).to.equal(true);
});
const { documentReady } = require('../../src/core/util/dom');
const { Docsify } = require('../../src/core/index');
await new Promise(resolve => documentReady(resolve));

new Docsify(); // eslint-disable-line

expect(window.configFunctionCalled).to.equal(true);
});

it('provides the hooks and vm API to plugins', async function() {
initJSDOM(markup, { url: docsifySite });

window.pluginFunctionCalled = false;

window.$docsify = function(vm) {
const vm1 = vm;
return {
plugins: [
function(hook, vm2) {
expect(vm1).to.equal(vm2);

expect(hook.init).to.be.an.instanceof(Function);
expect(hook.beforeEach).to.be.an.instanceof(Function);
expect(hook.afterEach).to.be.an.instanceof(Function);
expect(hook.doneEach).to.be.an.instanceof(Function);
expect(hook.mounted).to.be.an.instanceof(Function);
expect(hook.ready).to.be.an.instanceof(Function);

it('provides the hooks and vm API to plugins', async function() {
const DOM = initJSDOM(markup);
DOM.reconfigure({ url: 'file:///' + docsifySite });

window.pluginFunctionCalled = false;

window.$docsify = function(vm) {
const vm1 = vm;
return {
plugins: [
function(hook, vm2) {
expect(vm1).to.equal(vm2);

expect(hook.init).to.be.an.instanceof(Function);
expect(hook.beforeEach).to.be.an.instanceof(Function);
expect(hook.afterEach).to.be.an.instanceof(Function);
expect(hook.doneEach).to.be.an.instanceof(Function);
expect(hook.mounted).to.be.an.instanceof(Function);
expect(hook.ready).to.be.an.instanceof(Function);

window.pluginFunctionCalled = true;
},
],
window.pluginFunctionCalled = true;
},
],
};
};
};

const { documentReady, Docsify } = require('../../src/core/index');
await new Promise(resolve => documentReady(resolve));
const { documentReady } = require('../../src/core/util/dom');
const { Docsify } = require('../../src/core/index');
await new Promise(resolve => documentReady(resolve));

new Docsify(); // eslint-disable-line
new Docsify(); // eslint-disable-line

expect(window.pluginFunctionCalled).to.equal(true);
expect(window.pluginFunctionCalled).to.equal(true);
});
});
});