From 7d1a388ed8afa37879d4ef95f21756c0117fac80 Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Mon, 23 Apr 2018 21:37:51 +0100 Subject: [PATCH 1/9] added explosion of md includes --- lib/prepare.js | 6 +++++- lib/webpack/markdownLoader.js | 13 +++++++++---- lib/webpack/util.js | 27 +++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 lib/webpack/util.js diff --git a/lib/prepare.js b/lib/prepare.js index 2d0fc56db2..6906930194 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -6,6 +6,7 @@ const tomlParser = require('toml') const createMarkdown = require('./markdown') const tempPath = path.resolve(__dirname, 'app/.temp') const { inferTitle, extractHeaders, parseFrontmatter } = require('./util') +const { mdExplodeIncludes } = require('./webpack/util') fs.ensureDirSync(tempPath) @@ -187,7 +188,10 @@ async function resolveOptions (sourceDir) { } // extract yaml frontmatter - const content = await fs.readFile(path.resolve(sourceDir, file), 'utf-8') + const { explodedSrc: content } = mdExplodeIncludes({ + cwd: path.dirname(path.resolve(sourceDir, file)), + src: await fs.readFile(path.resolve(sourceDir, file), 'utf-8') + }) const frontmatter = parseFrontmatter(content) // infer title const title = inferTitle(frontmatter) diff --git a/lib/webpack/markdownLoader.js b/lib/webpack/markdownLoader.js index 1aa38f32ce..2f936dd0bc 100644 --- a/lib/webpack/markdownLoader.js +++ b/lib/webpack/markdownLoader.js @@ -5,11 +5,18 @@ const { EventEmitter } = require('events') const { getOptions } = require('loader-utils') const { inferTitle, extractHeaders, parseFrontmatter } = require('../util') const LRU = require('lru-cache') +const { mdExplodeIncludes } = require('./util') const cache = LRU({ max: 1000 }) const devCache = LRU({ max: 1000 }) module.exports = function (src) { + const file = this.resourcePath + const dir = path.dirname(file) + + const { explodedSrc, dependencies } = mdExplodeIncludes({ dir, src }) + dependencies.forEach(d => this.addDependency(d)) + const isProd = process.env.NODE_ENV === 'production' const isServer = this.target === 'node' const { markdown, sourceDir } = getOptions(this) @@ -17,14 +24,13 @@ module.exports = function (src) { // we implement a manual cache here because this loader is chained before // vue-loader, and will be applied on the same file multiple times when // selecting the individual blocks. - const file = this.resourcePath - const key = hash(file + src) + const key = hash(file + explodedSrc) const cached = cache.get(key) if (cached && (isProd || /\?vue/.test(this.resourceQuery))) { return cached } - const frontmatter = parseFrontmatter(src) + const frontmatter = parseFrontmatter(explodedSrc) const content = frontmatter.content if (!isProd && !isServer) { @@ -66,7 +72,6 @@ module.exports = function (src) { const altname = shortname .replace(/\/$/, '/index.md') .replace(/^\//, sourceDir + '/') - const dir = path.dirname(this.resourcePath) const file = path.resolve(dir, filename) const altfile = altname !== filename ? path.resolve(dir, altname) : null if (!fs.existsSync(file) && (!altfile || !fs.existsSync(altfile))) { diff --git a/lib/webpack/util.js b/lib/webpack/util.js new file mode 100644 index 0000000000..d7fbb68bf9 --- /dev/null +++ b/lib/webpack/util.js @@ -0,0 +1,27 @@ +const { readFileSync } = require('fs') +const { resolve, dirname } = require('path') + +const mdExplodeIncludes = exports.mdExplodeIncludes = ({ cwd, src }) => { + const deps = [] + + return { + explodedSrc: src.replace(//g, (match, path) => { + try { + const absolutePath = resolve(cwd, path) + const content = readFileSync(absolutePath, 'utf8') + + // recursively explode the included file + const { explodedSrc, dependencies } = mdExplodeIncludes({ + cwd: dirname(absolutePath), + src: content + }) + + deps.push(absolutePath, ...dependencies) + return explodedSrc + } catch (e) { + return match + } + }), + dependencies: deps + } +} From 1362a90eba95e970b13130f22b58965d100bd960 Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Tue, 24 Apr 2018 20:14:14 +0100 Subject: [PATCH 2/9] updated regexp --- lib/webpack/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webpack/util.js b/lib/webpack/util.js index d7fbb68bf9..ee3ade823f 100644 --- a/lib/webpack/util.js +++ b/lib/webpack/util.js @@ -5,7 +5,7 @@ const mdExplodeIncludes = exports.mdExplodeIncludes = ({ cwd, src }) => { const deps = [] return { - explodedSrc: src.replace(//g, (match, path) => { + explodedSrc: src.replace(//g, (match, path) => { try { const absolutePath = resolve(cwd, path) const content = readFileSync(absolutePath, 'utf8') From b967b758138c65c1083f635ece4e14e0a81918ca Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Tue, 24 Apr 2018 22:35:32 +0100 Subject: [PATCH 3/9] made file reading async --- lib/prepare.js | 2 +- lib/webpack/markdownLoader.js | 147 ++++++++++++++++++---------------- lib/webpack/util.js | 32 ++++++-- 3 files changed, 104 insertions(+), 77 deletions(-) diff --git a/lib/prepare.js b/lib/prepare.js index 6906930194..0e69e92129 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -188,7 +188,7 @@ async function resolveOptions (sourceDir) { } // extract yaml frontmatter - const { explodedSrc: content } = mdExplodeIncludes({ + const { explodedSrc: content } = await mdExplodeIncludes({ cwd: path.dirname(path.resolve(sourceDir, file)), src: await fs.readFile(path.resolve(sourceDir, file), 'utf-8') }) diff --git a/lib/webpack/markdownLoader.js b/lib/webpack/markdownLoader.js index 2f936dd0bc..c4b058cd66 100644 --- a/lib/webpack/markdownLoader.js +++ b/lib/webpack/markdownLoader.js @@ -10,88 +10,93 @@ const { mdExplodeIncludes } = require('./util') const cache = LRU({ max: 1000 }) const devCache = LRU({ max: 1000 }) -module.exports = function (src) { - const file = this.resourcePath - const dir = path.dirname(file) +module.exports = async function (src) { + const cb = this.async() + try { + const file = this.resourcePath + const dir = path.dirname(file) - const { explodedSrc, dependencies } = mdExplodeIncludes({ dir, src }) - dependencies.forEach(d => this.addDependency(d)) + const { explodedSrc, dependencies } = await mdExplodeIncludes({ cwd: dir, src }) + dependencies.forEach(d => this.addDependency(d)) - const isProd = process.env.NODE_ENV === 'production' - const isServer = this.target === 'node' - const { markdown, sourceDir } = getOptions(this) + const isProd = process.env.NODE_ENV === 'production' + const isServer = this.target === 'node' + const { markdown, sourceDir } = getOptions(this) - // we implement a manual cache here because this loader is chained before - // vue-loader, and will be applied on the same file multiple times when - // selecting the individual blocks. - const key = hash(file + explodedSrc) - const cached = cache.get(key) - if (cached && (isProd || /\?vue/.test(this.resourceQuery))) { - return cached - } + // we implement a manual cache here because this loader is chained before + // vue-loader, and will be applied on the same file multiple times when + // selecting the individual blocks. + const key = hash(file + explodedSrc) + const cached = cache.get(key) + if (cached && (isProd || /\?vue/.test(this.resourceQuery))) { + return cb(null, cached) + } - const frontmatter = parseFrontmatter(explodedSrc) - const content = frontmatter.content + const frontmatter = parseFrontmatter(explodedSrc) + const content = frontmatter.content - if (!isProd && !isServer) { - const inferredTitle = inferTitle(frontmatter) - const headers = extractHeaders(content, ['h2', 'h3'], markdown) - delete frontmatter.content + if (!isProd && !isServer) { + const inferredTitle = inferTitle(frontmatter) + const headers = extractHeaders(content, ['h2', 'h3'], markdown) + delete frontmatter.content - // diff frontmatter and title, since they are not going to be part of the - // returned component, changes in frontmatter do not trigger proper updates - const cachedData = devCache.get(file) - if (cachedData && ( - cachedData.inferredTitle !== inferredTitle || - JSON.stringify(cachedData.frontmatter) !== JSON.stringify(frontmatter) || - headersChanged(cachedData.headers, headers) - )) { - // frontmatter changed... need to do a full reload - module.exports.frontmatterEmitter.emit('update') - } + // diff frontmatter and title, since they are not going to be part of the + // returned component, changes in frontmatter do not trigger proper updates + const cachedData = devCache.get(file) + if (cachedData && ( + cachedData.inferredTitle !== inferredTitle || + JSON.stringify(cachedData.frontmatter) !== JSON.stringify(frontmatter) || + headersChanged(cachedData.headers, headers) + )) { + // frontmatter changed... need to do a full reload + module.exports.frontmatterEmitter.emit('update') + } - devCache.set(file, { - headers, - frontmatter, - inferredTitle - }) - } + devCache.set(file, { + headers, + frontmatter, + inferredTitle + }) + } - // the render method has been augmented to allow plugins to - // register data during render - const { html, data: { hoistedTags, links }} = markdown.render(content) + // the render method has been augmented to allow plugins to + // register data during render + const { html, data: { hoistedTags, links }} = markdown.render(content) - // check if relative links are valid - links && links.forEach(link => { - const shortname = link - .replace(/#.*$/, '') - .replace(/\.html$/, '.md') - const filename = shortname - .replace(/\/$/, '/README.md') - .replace(/^\//, sourceDir + '/') - const altname = shortname - .replace(/\/$/, '/index.md') - .replace(/^\//, sourceDir + '/') - const file = path.resolve(dir, filename) - const altfile = altname !== filename ? path.resolve(dir, altname) : null - if (!fs.existsSync(file) && (!altfile || !fs.existsSync(altfile))) { - this.emitWarning( - new Error( - `\nFile for relative link "${link}" does not exist.\n` + - `(Resolved file: ${file})\n` + // check if relative links are valid + links && links.forEach(link => { + const shortname = link + .replace(/#.*$/, '') + .replace(/\.html$/, '.md') + const filename = shortname + .replace(/\/$/, '/README.md') + .replace(/^\//, sourceDir + '/') + const altname = shortname + .replace(/\/$/, '/index.md') + .replace(/^\//, sourceDir + '/') + const file = path.resolve(dir, filename) + const altfile = altname !== filename ? path.resolve(dir, altname) : null + if (!fs.existsSync(file) && (!altfile || !fs.existsSync(altfile))) { + this.emitWarning( + new Error( + `\nFile for relative link "${link}" does not exist.\n` + + `(Resolved file: ${file})\n` + ) ) - ) - } - }) + } + }) - const res = ( - `\n` + - (hoistedTags || []).join('\n') - ) - cache.set(key, res) - return res + const res = ( + `\n` + + (hoistedTags || []).join('\n') + ) + cache.set(key, res) + return cb(null, res) + } catch (e) { + return cb(e) + } } function headersChanged (a, b) { diff --git a/lib/webpack/util.js b/lib/webpack/util.js index ee3ade823f..1ca6a3663d 100644 --- a/lib/webpack/util.js +++ b/lib/webpack/util.js @@ -1,17 +1,39 @@ -const { readFileSync } = require('fs') +const { promisify } = require('util') +const fs = require('fs') +const readFile = promisify(fs.readFile) const { resolve, dirname } = require('path') -const mdExplodeIncludes = exports.mdExplodeIncludes = ({ cwd, src }) => { +const asyncReplace = async (str, regex, aReplacer) => { + regex = new RegExp(regex, 'g') + const replacedParts = [] + let match + let i = 0 + while ((match = regex.exec(str)) !== null) { + // put non matching string + replacedParts.push(str.slice(i, match.index)) + // call the async replacer function with the matched array spreaded + replacedParts.push(aReplacer(...match)) + i = regex.lastIndex + } + + // put the rest of str + replacedParts.push(str.slice(i)) + + // wait for aReplacer calls to finish and join them back into string + return (await Promise.all(replacedParts)).join('') +} + +const mdExplodeIncludes = exports.mdExplodeIncludes = async ({ cwd, src }) => { const deps = [] return { - explodedSrc: src.replace(//g, (match, path) => { + explodedSrc: await asyncReplace(src, //g, async (match, path) => { try { const absolutePath = resolve(cwd, path) - const content = readFileSync(absolutePath, 'utf8') + const content = await readFile(absolutePath, 'utf8') // recursively explode the included file - const { explodedSrc, dependencies } = mdExplodeIncludes({ + const { explodedSrc, dependencies } = await mdExplodeIncludes({ cwd: dirname(absolutePath), src: content }) From 43c760b8b5d74f36300f552525da302bdb6db008 Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Tue, 24 Apr 2018 22:43:29 +0100 Subject: [PATCH 4/9] use fs-extra --- lib/webpack/util.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/webpack/util.js b/lib/webpack/util.js index 1ca6a3663d..cee62888ad 100644 --- a/lib/webpack/util.js +++ b/lib/webpack/util.js @@ -1,6 +1,4 @@ -const { promisify } = require('util') -const fs = require('fs') -const readFile = promisify(fs.readFile) +const { readFile } = require('fs-extra') const { resolve, dirname } = require('path') const asyncReplace = async (str, regex, aReplacer) => { From 961eada0e68868d920ba4219f8e5d3f0328fd49f Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Fri, 27 Apr 2018 21:26:50 +0100 Subject: [PATCH 5/9] try unindent lines for diff --- lib/webpack/markdownLoader.js | 141 +++++++++++++++++----------------- 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/lib/webpack/markdownLoader.js b/lib/webpack/markdownLoader.js index c4b058cd66..d6ddd73179 100644 --- a/lib/webpack/markdownLoader.js +++ b/lib/webpack/markdownLoader.js @@ -13,87 +13,88 @@ const devCache = LRU({ max: 1000 }) module.exports = async function (src) { const cb = this.async() try { - const file = this.resourcePath - const dir = path.dirname(file) + /* IMPORTANT: I didn't indent these lines to hopefully get a better looking diff */ + const file = this.resourcePath + const dir = path.dirname(file) - const { explodedSrc, dependencies } = await mdExplodeIncludes({ cwd: dir, src }) - dependencies.forEach(d => this.addDependency(d)) + const { explodedSrc, dependencies } = await mdExplodeIncludes({ cwd: dir, src }) + dependencies.forEach(d => this.addDependency(d)) - const isProd = process.env.NODE_ENV === 'production' - const isServer = this.target === 'node' - const { markdown, sourceDir } = getOptions(this) + const isProd = process.env.NODE_ENV === 'production' + const isServer = this.target === 'node' + const { markdown, sourceDir } = getOptions(this) - // we implement a manual cache here because this loader is chained before - // vue-loader, and will be applied on the same file multiple times when - // selecting the individual blocks. - const key = hash(file + explodedSrc) - const cached = cache.get(key) - if (cached && (isProd || /\?vue/.test(this.resourceQuery))) { - return cb(null, cached) - } - - const frontmatter = parseFrontmatter(explodedSrc) - const content = frontmatter.content + // we implement a manual cache here because this loader is chained before + // vue-loader, and will be applied on the same file multiple times when + // selecting the individual blocks. + const key = hash(file + explodedSrc) + const cached = cache.get(key) + if (cached && (isProd || /\?vue/.test(this.resourceQuery))) { + return cb(null, cached) + } - if (!isProd && !isServer) { - const inferredTitle = inferTitle(frontmatter) - const headers = extractHeaders(content, ['h2', 'h3'], markdown) - delete frontmatter.content + const frontmatter = parseFrontmatter(explodedSrc) + const content = frontmatter.content - // diff frontmatter and title, since they are not going to be part of the - // returned component, changes in frontmatter do not trigger proper updates - const cachedData = devCache.get(file) - if (cachedData && ( - cachedData.inferredTitle !== inferredTitle || - JSON.stringify(cachedData.frontmatter) !== JSON.stringify(frontmatter) || - headersChanged(cachedData.headers, headers) - )) { - // frontmatter changed... need to do a full reload - module.exports.frontmatterEmitter.emit('update') - } + if (!isProd && !isServer) { + const inferredTitle = inferTitle(frontmatter) + const headers = extractHeaders(content, ['h2', 'h3'], markdown) + delete frontmatter.content - devCache.set(file, { - headers, - frontmatter, - inferredTitle - }) + // diff frontmatter and title, since they are not going to be part of the + // returned component, changes in frontmatter do not trigger proper updates + const cachedData = devCache.get(file) + if (cachedData && ( + cachedData.inferredTitle !== inferredTitle || + JSON.stringify(cachedData.frontmatter) !== JSON.stringify(frontmatter) || + headersChanged(cachedData.headers, headers) + )) { + // frontmatter changed... need to do a full reload + module.exports.frontmatterEmitter.emit('update') } - // the render method has been augmented to allow plugins to - // register data during render - const { html, data: { hoistedTags, links }} = markdown.render(content) + devCache.set(file, { + headers, + frontmatter, + inferredTitle + }) + } + + // the render method has been augmented to allow plugins to + // register data during render + const { html, data: { hoistedTags, links }} = markdown.render(content) - // check if relative links are valid - links && links.forEach(link => { - const shortname = link - .replace(/#.*$/, '') - .replace(/\.html$/, '.md') - const filename = shortname - .replace(/\/$/, '/README.md') - .replace(/^\//, sourceDir + '/') - const altname = shortname - .replace(/\/$/, '/index.md') - .replace(/^\//, sourceDir + '/') - const file = path.resolve(dir, filename) - const altfile = altname !== filename ? path.resolve(dir, altname) : null - if (!fs.existsSync(file) && (!altfile || !fs.existsSync(altfile))) { - this.emitWarning( - new Error( - `\nFile for relative link "${link}" does not exist.\n` + - `(Resolved file: ${file})\n` - ) + // check if relative links are valid + links && links.forEach(link => { + const shortname = link + .replace(/#.*$/, '') + .replace(/\.html$/, '.md') + const filename = shortname + .replace(/\/$/, '/README.md') + .replace(/^\//, sourceDir + '/') + const altname = shortname + .replace(/\/$/, '/index.md') + .replace(/^\//, sourceDir + '/') + const file = path.resolve(dir, filename) + const altfile = altname !== filename ? path.resolve(dir, altname) : null + if (!fs.existsSync(file) && (!altfile || !fs.existsSync(altfile))) { + this.emitWarning( + new Error( + `\nFile for relative link "${link}" does not exist.\n` + + `(Resolved file: ${file})\n` ) - } - }) + ) + } + }) - const res = ( - `\n` + - (hoistedTags || []).join('\n') - ) - cache.set(key, res) - return cb(null, res) + const res = ( + `\n` + + (hoistedTags || []).join('\n') + ) + cache.set(key, res) + return cb(null, res) } catch (e) { return cb(e) } From 3eaf157cf7b607198e4d9076b2cf04ec42a96fd9 Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Fri, 27 Apr 2018 21:31:44 +0100 Subject: [PATCH 6/9] added comment --- lib/prepare.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/prepare.js b/lib/prepare.js index 0e69e92129..e302c9b089 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -187,11 +187,13 @@ async function resolveOptions (sourceDir) { path: fileToPath(file) } - // extract yaml frontmatter + // explode content in order to extract correct headers const { explodedSrc: content } = await mdExplodeIncludes({ cwd: path.dirname(path.resolve(sourceDir, file)), src: await fs.readFile(path.resolve(sourceDir, file), 'utf-8') }) + + // extract yaml frontmatter const frontmatter = parseFrontmatter(content) // infer title const title = inferTitle(frontmatter) From 4b5a3abb06f9e5e6adfc14eff4ef05d9d145b927 Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Fri, 27 Apr 2018 22:02:21 +0100 Subject: [PATCH 7/9] added comment --- lib/webpack/markdownLoader.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/webpack/markdownLoader.js b/lib/webpack/markdownLoader.js index d6ddd73179..66c677acc0 100644 --- a/lib/webpack/markdownLoader.js +++ b/lib/webpack/markdownLoader.js @@ -14,9 +14,10 @@ module.exports = async function (src) { const cb = this.async() try { /* IMPORTANT: I didn't indent these lines to hopefully get a better looking diff */ + + // explode content of placeholders const file = this.resourcePath const dir = path.dirname(file) - const { explodedSrc, dependencies } = await mdExplodeIncludes({ cwd: dir, src }) dependencies.forEach(d => this.addDependency(d)) From 61ac480dad77614500ab6039c6a88405af40151c Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Fri, 27 Apr 2018 22:13:21 +0100 Subject: [PATCH 8/9] cwd to dir --- lib/prepare.js | 2 +- lib/webpack/markdownLoader.js | 2 +- lib/webpack/util.js | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/prepare.js b/lib/prepare.js index e302c9b089..09d007a1be 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -189,7 +189,7 @@ async function resolveOptions (sourceDir) { // explode content in order to extract correct headers const { explodedSrc: content } = await mdExplodeIncludes({ - cwd: path.dirname(path.resolve(sourceDir, file)), + dir: path.dirname(path.resolve(sourceDir, file)), src: await fs.readFile(path.resolve(sourceDir, file), 'utf-8') }) diff --git a/lib/webpack/markdownLoader.js b/lib/webpack/markdownLoader.js index 66c677acc0..4ada1dc687 100644 --- a/lib/webpack/markdownLoader.js +++ b/lib/webpack/markdownLoader.js @@ -18,7 +18,7 @@ module.exports = async function (src) { // explode content of placeholders const file = this.resourcePath const dir = path.dirname(file) - const { explodedSrc, dependencies } = await mdExplodeIncludes({ cwd: dir, src }) + const { explodedSrc, dependencies } = await mdExplodeIncludes({ dir, src }) dependencies.forEach(d => this.addDependency(d)) const isProd = process.env.NODE_ENV === 'production' diff --git a/lib/webpack/util.js b/lib/webpack/util.js index cee62888ad..a1e66cfbd1 100644 --- a/lib/webpack/util.js +++ b/lib/webpack/util.js @@ -21,18 +21,18 @@ const asyncReplace = async (str, regex, aReplacer) => { return (await Promise.all(replacedParts)).join('') } -const mdExplodeIncludes = exports.mdExplodeIncludes = async ({ cwd, src }) => { +const mdExplodeIncludes = exports.mdExplodeIncludes = async ({ dir, src }) => { const deps = [] return { explodedSrc: await asyncReplace(src, //g, async (match, path) => { try { - const absolutePath = resolve(cwd, path) + const absolutePath = resolve(dir, path) const content = await readFile(absolutePath, 'utf8') // recursively explode the included file const { explodedSrc, dependencies } = await mdExplodeIncludes({ - cwd: dirname(absolutePath), + dir: dirname(absolutePath), src: content }) From f0eabfcc7c5b672756eb0f6caa157edb03320585 Mon Sep 17 00:00:00 2001 From: Jason Yu Date: Wed, 6 Jun 2018 17:56:37 +0100 Subject: [PATCH 9/9] unindent stuff to have better diff --- lib/webpack/markdownLoader.js | 120 +++++++++++++++++----------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/lib/webpack/markdownLoader.js b/lib/webpack/markdownLoader.js index 4937d9302a..7d563e6fe9 100644 --- a/lib/webpack/markdownLoader.js +++ b/lib/webpack/markdownLoader.js @@ -13,90 +13,90 @@ const devCache = LRU({ max: 1000 }) module.exports = async function (src) { const cb = this.async() try { - /* IMPORTANT: I didn't indent these lines to hopefully get a better looking diff */ +/* IMPORTANT: I didn't indent these lines to hopefully get a better looking diff */ - // explode content of placeholders - const file = this.resourcePath - const dir = path.dirname(file) - const { explodedSrc, dependencies } = await mdExplodeIncludes({ dir, src }) - dependencies.forEach(d => this.addDependency(d)) +// explode content of placeholders + const file = this.resourcePath + const dir = path.dirname(file) + const { explodedSrc, dependencies } = await mdExplodeIncludes({ dir, src }) + dependencies.forEach(d => this.addDependency(d)) - const isProd = process.env.NODE_ENV === 'production' - const isServer = this.target === 'node' - const { markdown, sourceDir } = getOptions(this) + const isProd = process.env.NODE_ENV === 'production' + const isServer = this.target === 'node' + const { markdown, sourceDir } = getOptions(this) - // we implement a manual cache here because this loader is chained before - // vue-loader, and will be applied on the same file multiple times when - // selecting the individual blocks. - const key = hash(file + explodedSrc) - const cached = cache.get(key) - if (cached && (isProd || /\?vue/.test(this.resourceQuery))) { - return cb(null, cached) - } + // we implement a manual cache here because this loader is chained before + // vue-loader, and will be applied on the same file multiple times when + // selecting the individual blocks. + const key = hash(file + explodedSrc) + const cached = cache.get(key) + if (cached && (isProd || /\?vue/.test(this.resourceQuery))) { + return cb(null, cached) + } - const frontmatter = parseFrontmatter(explodedSrc) - const content = frontmatter.content + const frontmatter = parseFrontmatter(explodedSrc) + const content = frontmatter.content - if (!isProd && !isServer) { - const inferredTitle = inferTitle(frontmatter) - const headers = extractHeaders(content, ['h2', 'h3'], markdown) - delete frontmatter.content + if (!isProd && !isServer) { + const inferredTitle = inferTitle(frontmatter) + const headers = extractHeaders(content, ['h2', 'h3'], markdown) + delete frontmatter.content - // diff frontmatter and title, since they are not going to be part of the - // returned component, changes in frontmatter do not trigger proper updates - const cachedData = devCache.get(file) - if (cachedData && ( - cachedData.inferredTitle !== inferredTitle || + // diff frontmatter and title, since they are not going to be part of the + // returned component, changes in frontmatter do not trigger proper updates + const cachedData = devCache.get(file) + if (cachedData && ( + cachedData.inferredTitle !== inferredTitle || JSON.stringify(cachedData.frontmatter) !== JSON.stringify(frontmatter) || headersChanged(cachedData.headers, headers) - )) { + )) { // frontmatter changed... need to do a full reload - module.exports.frontmatterEmitter.emit('update') - } - - devCache.set(file, { - headers, - frontmatter, - inferredTitle - }) + module.exports.frontmatterEmitter.emit('update') } - // the render method has been augmented to allow plugins to - // register data during render - const { html, data: { hoistedTags, links }} = markdown.render(content) + devCache.set(file, { + headers, + frontmatter, + inferredTitle + }) + } + + // the render method has been augmented to allow plugins to + // register data during render + const { html, data: { hoistedTags, links }} = markdown.render(content) - // check if relative links are valid - links && links.forEach(link => { - link = decodeURIComponent(link) - const shortname = link + // check if relative links are valid + links && links.forEach(link => { + link = decodeURIComponent(link) + const shortname = link .replace(/#.*$/, '') .replace(/\.html$/, '.md') - const filename = shortname + const filename = shortname .replace(/\/$/, '/README.md') .replace(/^\//, sourceDir + '/') - const altname = shortname + const altname = shortname .replace(/\/$/, '/index.md') .replace(/^\//, sourceDir + '/') - const file = path.resolve(dir, filename) - const altfile = altname !== filename ? path.resolve(dir, altname) : null - if (!fs.existsSync(file) && (!altfile || !fs.existsSync(altfile))) { - this.emitWarning( - new Error( - `\nFile for relative link "${link}" does not exist.\n` + + const file = path.resolve(dir, filename) + const altfile = altname !== filename ? path.resolve(dir, altname) : null + if (!fs.existsSync(file) && (!altfile || !fs.existsSync(altfile))) { + this.emitWarning( + new Error( + `\nFile for relative link "${link}" does not exist.\n` + `(Resolved file: ${file})\n` - ) ) - } - }) + ) + } + }) - const res = ( - `