aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vuepress/lib/webpack
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/vuepress/lib/webpack')
-rw-r--r--node_modules/vuepress/lib/webpack/ClientPlugin.js87
-rw-r--r--node_modules/vuepress/lib/webpack/DevLogPlugin.js38
-rw-r--r--node_modules/vuepress/lib/webpack/HeadPlugin.js22
-rw-r--r--node_modules/vuepress/lib/webpack/createBaseConfig.js315
-rw-r--r--node_modules/vuepress/lib/webpack/createClientConfig.js69
-rw-r--r--node_modules/vuepress/lib/webpack/createServerConfig.js58
-rw-r--r--node_modules/vuepress/lib/webpack/markdownLoader.js101
-rw-r--r--node_modules/vuepress/lib/webpack/noopModule.js1
8 files changed, 691 insertions, 0 deletions
diff --git a/node_modules/vuepress/lib/webpack/ClientPlugin.js b/node_modules/vuepress/lib/webpack/ClientPlugin.js
new file mode 100644
index 00000000..82028475
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/ClientPlugin.js
@@ -0,0 +1,87 @@
+// Temporarily hacked dev build
+
+var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file) }
+
+var isCSS = function (file) { return /\.css(\?[^.]+)?$/.test(file) }
+
+var onEmit = function (compiler, name, hook) {
+ if (compiler.hooks) {
+ // Webpack >= 4.0.0
+ compiler.hooks.emit.tapAsync(name, hook)
+ } else {
+ // Webpack < 4.0.0
+ compiler.plugin('emit', hook)
+ }
+}
+
+var hash = require('hash-sum')
+var uniq = require('lodash.uniq')
+var VueSSRClientPlugin = function VueSSRClientPlugin (options) {
+ if (options === void 0) options = {}
+
+ this.options = Object.assign({
+ filename: 'vue-ssr-client-manifest.json'
+ }, options)
+}
+
+VueSSRClientPlugin.prototype.apply = function apply (compiler) {
+ var this$1 = this
+
+ onEmit(compiler, 'vue-client-plugin', function (compilation, cb) {
+ var stats = compilation.getStats().toJson()
+
+ var allFiles = uniq(stats.assets
+ .map(function (a) { return a.name }))
+ // Avoid preloading / injecting the style chunk
+ .filter(file => !/styles\.\w{8}\.js$/.test(file))
+
+ var initialFiles = uniq(Object.keys(stats.entrypoints)
+ .map(function (name) { return stats.entrypoints[name].assets })
+ .reduce(function (assets, all) { return all.concat(assets) }, [])
+ .filter(function (file) { return isJS(file) || isCSS(file) }))
+ // Avoid preloading / injecting the style chunk
+ .filter(file => !/styles\.\w{8}\.js$/.test(file))
+
+ var asyncFiles = allFiles
+ .filter(function (file) { return isJS(file) || isCSS(file) })
+ .filter(function (file) { return initialFiles.indexOf(file) < 0 })
+
+ var manifest = {
+ publicPath: stats.publicPath,
+ all: allFiles,
+ initial: initialFiles,
+ async: asyncFiles,
+ modules: { /* [identifier: string]: Array<index: number> */ }
+ }
+
+ var assetModules = stats.modules.filter(function (m) { return m.assets.length })
+ var fileToIndex = function (file) { return manifest.all.indexOf(file) }
+ stats.modules.forEach(function (m) {
+ // ignore modules duplicated in multiple chunks
+ if (m.chunks.length === 1) {
+ var cid = m.chunks[0]
+ var chunk = stats.chunks.find(function (c) { return c.id === cid })
+ if (!chunk || !chunk.files) {
+ return
+ }
+ var id = m.identifier.replace(/\s\w+$/, '') // remove appended hash
+ var files = manifest.modules[hash(id)] = chunk.files.map(fileToIndex)
+ // find all asset modules associated with the same chunk
+ assetModules.forEach(function (m) {
+ if (m.chunks.some(function (id) { return id === cid })) {
+ files.push.apply(files, m.assets.map(fileToIndex))
+ }
+ })
+ }
+ })
+
+ var json = JSON.stringify(manifest, null, 2)
+ compilation.assets[this$1.options.filename] = {
+ source: function () { return json },
+ size: function () { return json.length }
+ }
+ cb()
+ })
+}
+
+module.exports = VueSSRClientPlugin
diff --git a/node_modules/vuepress/lib/webpack/DevLogPlugin.js b/node_modules/vuepress/lib/webpack/DevLogPlugin.js
new file mode 100644
index 00000000..8fd18d4a
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/DevLogPlugin.js
@@ -0,0 +1,38 @@
+const chalk = require('chalk')
+const logger = require('../util/logger')
+
+module.exports = class DevLogPlugin {
+ constructor (options) {
+ this.options = options
+ }
+
+ apply (compiler) {
+ let isFirst = true
+ compiler.hooks.done.tap('vuepress-log', stats => {
+ clearScreen()
+
+ const { displayHost, port, publicPath } = this.options
+ const time = new Date().toTimeString().match(/^[\d:]+/)[0]
+ const displayUrl = `http://${displayHost}:${port}${publicPath}`
+
+ logger.success(
+ `\n${chalk.gray(`[${time}]`)} Build ${chalk.italic(stats.hash.slice(0, 6))} ` +
+ `finished in ${stats.endTime - stats.startTime} ms! ` +
+ (
+ isFirst
+ ? ''
+ : `${chalk.gray(`(${displayUrl})`)}`
+ )
+ )
+ if (isFirst) {
+ isFirst = false
+ console.log(`\n${chalk.gray('>')} VuePress dev server listening at ${chalk.cyan(displayUrl)}`)
+ }
+ })
+ compiler.hooks.invalid.tap('vuepress-log', clearScreen)
+ }
+}
+
+function clearScreen () {
+ process.stdout.write('\x1Bc')
+}
diff --git a/node_modules/vuepress/lib/webpack/HeadPlugin.js b/node_modules/vuepress/lib/webpack/HeadPlugin.js
new file mode 100644
index 00000000..2ccb46e0
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/HeadPlugin.js
@@ -0,0 +1,22 @@
+const { normalizeHeadTag } = require('../util')
+
+module.exports = class SiteDataPlugin {
+ constructor ({ tags }) {
+ this.tags = tags
+ }
+
+ apply (compiler) {
+ compiler.hooks.compilation.tap('vuepress-site-data', compilation => {
+ compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync('vuepress-site-data', (data, cb) => {
+ try {
+ this.tags.forEach(tag => {
+ data.head.push(normalizeHeadTag(tag))
+ })
+ } catch (e) {
+ return cb(e)
+ }
+ cb(null, data)
+ })
+ })
+ }
+}
diff --git a/node_modules/vuepress/lib/webpack/createBaseConfig.js b/node_modules/vuepress/lib/webpack/createBaseConfig.js
new file mode 100644
index 00000000..dcf7fab3
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/createBaseConfig.js
@@ -0,0 +1,315 @@
+const path = require('path')
+
+module.exports = function createBaseConfig ({
+ siteConfig,
+ siteData,
+ sourceDir,
+ outDir,
+ publicPath,
+ themePath,
+ themeLayoutPath,
+ themeNotFoundPath,
+ isAlgoliaSearch,
+ markdown
+}, { debug } = {}, isServer) {
+ const Config = require('webpack-chain')
+ const { VueLoaderPlugin } = require('vue-loader')
+ const CSSExtractPlugin = require('mini-css-extract-plugin')
+
+ const isProd = process.env.NODE_ENV === 'production'
+ const inlineLimit = 10000
+
+ const config = new Config()
+
+ config
+ .mode(isProd && !debug ? 'production' : 'development')
+ .output
+ .path(outDir)
+ .filename(isProd ? 'assets/js/[name].[chunkhash:8].js' : 'assets/js/[name].js')
+ .publicPath(isProd ? publicPath : '/')
+
+ if (debug) {
+ config.devtool('source-map')
+ } else if (!isProd) {
+ config.devtool('cheap-module-eval-source-map')
+ }
+
+ config.resolve
+ .set('symlinks', true)
+ .alias
+ .set('@theme', themePath)
+ .set('@themeLayout', themeLayoutPath)
+ .set('@themeNotFound', themeNotFoundPath)
+ .set('@source', sourceDir)
+ .set('@app', path.resolve(__dirname, '../app'))
+ .set('@temp', path.resolve(__dirname, '../app/.temp'))
+ .set('@default-theme', path.resolve(__dirname, '../default-theme'))
+ .set('@AlgoliaSearchBox', isAlgoliaSearch
+ ? path.resolve(__dirname, '../default-theme/AlgoliaSearchBox.vue')
+ : path.resolve(__dirname, './noopModule.js'))
+ .end()
+ .extensions
+ .merge(['.js', '.jsx', '.vue', '.json', '.styl'])
+ .end()
+ .modules
+ // prioritize our own
+ .add(path.resolve(__dirname, '../../node_modules'))
+ .add(path.resolve(__dirname, '../../../'))
+ .add('node_modules')
+
+ // Load extra root mixins on demand.
+ const { activeHeaderLinks = true } = siteData.themeConfig
+ const rootMixinsLoadingConfig = { activeHeaderLinks }
+ for (const mixinName in rootMixinsLoadingConfig) {
+ const enabled = rootMixinsLoadingConfig[mixinName]
+ config.resolve
+ .alias.set(`@${mixinName}`, enabled
+ ? path.resolve(__dirname, `../app/root-mixins/${mixinName}.js`)
+ : path.resolve(__dirname, './noopModule.js')
+ )
+ }
+
+ config.resolveLoader
+ .set('symlinks', true)
+ .modules
+ // prioritize our own
+ .add(path.resolve(__dirname, '../../node_modules'))
+ .add(path.resolve(__dirname, '../../../'))
+ .add('node_modules')
+
+ config.module
+ .noParse(/^(vue|vue-router|vuex|vuex-router-sync)$/)
+
+ const cacheDirectory = path.resolve(__dirname, '../../node_modules/.cache/vuepress')
+ const cacheIdentifier = JSON.stringify({
+ vuepress: require('../../package.json').version,
+ 'cache-loader': require('cache-loader').version,
+ 'vue-loader': require('vue-loader').version,
+ isProd,
+ isServer,
+ config: (
+ (siteConfig.markdown ? JSON.stringify(siteConfig.markdown) : '') +
+ (siteConfig.chainWebpack || '').toString() +
+ (siteConfig.configureWebpack || '').toString()
+ )
+ })
+
+ function applyVuePipeline (rule) {
+ rule
+ .use('cache-loader')
+ .loader('cache-loader')
+ .options({
+ cacheDirectory,
+ cacheIdentifier
+ })
+
+ rule
+ .use('vue-loader')
+ .loader('vue-loader')
+ .options({
+ compilerOptions: {
+ preserveWhitespace: true
+ },
+ cacheDirectory,
+ cacheIdentifier
+ })
+ }
+
+ const vueRule = config.module
+ .rule('vue')
+ .test(/\.vue$/)
+
+ applyVuePipeline(vueRule)
+
+ const mdRule = config.module
+ .rule('markdown')
+ .test(/\.md$/)
+
+ applyVuePipeline(mdRule)
+
+ mdRule
+ .use('markdown-loader')
+ .loader(require.resolve('./markdownLoader'))
+ .options({ sourceDir, markdown })
+
+ config.module
+ .rule('pug')
+ .test(/\.pug$/)
+ .use('pug-plain-loader')
+ .loader('pug-plain-loader')
+ .end()
+
+ if (!siteConfig.evergreen) {
+ const libDir = path.join(__dirname, '..')
+ config.module
+ .rule('js')
+ .test(/\.js$/)
+ .exclude.add(filepath => {
+ // Always transpile lib directory
+ if (filepath.startsWith(libDir)) {
+ return false
+ }
+ // always transpile js in vue files
+ if (/\.vue\.js$/.test(filepath)) {
+ return false
+ }
+ // Don't transpile node_modules
+ return /node_modules/.test(filepath)
+ }).end()
+ .use('cache-loader')
+ .loader('cache-loader')
+ .options({
+ cacheDirectory,
+ cacheIdentifier
+ })
+ .end()
+ .use('babel-loader')
+ .loader('babel-loader')
+ .options({
+ // do not pick local project babel config (.babelrc)
+ babelrc: false,
+ // do not pick local project babel config (babel.config.js)
+ // ref: http://babeljs.io/docs/en/config-files
+ configFile: false,
+ presets: [
+ require.resolve('@vue/babel-preset-app')
+ ]
+ })
+ }
+
+ config.module
+ .rule('images')
+ .test(/\.(png|jpe?g|gif)(\?.*)?$/)
+ .use('url-loader')
+ .loader('url-loader')
+ .options({
+ limit: inlineLimit,
+ name: `assets/img/[name].[hash:8].[ext]`
+ })
+
+ // do not base64-inline SVGs.
+ // https://github.com/facebookincubator/create-react-app/pull/1180
+ config.module
+ .rule('svg')
+ .test(/\.(svg)(\?.*)?$/)
+ .use('file-loader')
+ .loader('file-loader')
+ .options({
+ name: `assets/img/[name].[hash:8].[ext]`
+ })
+
+ config.module
+ .rule('media')
+ .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/)
+ .use('url-loader')
+ .loader('url-loader')
+ .options({
+ limit: inlineLimit,
+ name: `assets/media/[name].[hash:8].[ext]`
+ })
+
+ config.module
+ .rule('fonts')
+ .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
+ .use('url-loader')
+ .loader('url-loader')
+ .options({
+ limit: inlineLimit,
+ name: `assets/fonts/[name].[hash:8].[ext]`
+ })
+
+ function createCSSRule (lang, test, loader, options) {
+ const baseRule = config.module.rule(lang).test(test)
+ const modulesRule = baseRule.oneOf('modules').resourceQuery(/module/)
+ const normalRule = baseRule.oneOf('normal')
+
+ applyLoaders(modulesRule, true)
+ applyLoaders(normalRule, false)
+
+ function applyLoaders (rule, modules) {
+ if (!isServer) {
+ if (isProd) {
+ rule.use('extract-css-loader').loader(CSSExtractPlugin.loader)
+ } else {
+ rule.use('vue-style-loader').loader('vue-style-loader')
+ }
+ }
+
+ rule.use('css-loader')
+ .loader(isServer ? 'css-loader/locals' : 'css-loader')
+ .options({
+ modules,
+ localIdentName: `[local]_[hash:base64:8]`,
+ importLoaders: 1,
+ sourceMap: !isProd
+ })
+
+ rule.use('postcss-loader').loader('postcss-loader').options(Object.assign({
+ plugins: [require('autoprefixer')],
+ sourceMap: !isProd
+ }, siteConfig.postcss))
+
+ if (loader) {
+ rule.use(loader).loader(loader).options(options)
+ }
+ }
+ }
+
+ createCSSRule('css', /\.css$/)
+ createCSSRule('postcss', /\.p(ost)?css$/)
+ createCSSRule('scss', /\.scss$/, 'sass-loader', siteConfig.scss)
+ createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign({ indentedSyntax: true }, siteConfig.sass))
+ createCSSRule('less', /\.less$/, 'less-loader', siteConfig.less)
+ createCSSRule('stylus', /\.styl(us)?$/, 'stylus-loader', Object.assign({
+ preferPathResolver: 'webpack'
+ }, siteConfig.stylus))
+
+ config
+ .plugin('vue-loader')
+ .use(VueLoaderPlugin)
+
+ if (isProd && !isServer) {
+ config
+ .plugin('extract-css')
+ .use(CSSExtractPlugin, [{
+ filename: 'assets/css/styles.[chunkhash:8].css'
+ }])
+
+ // ensure all css are extracted together.
+ // since most of the CSS will be from the theme and very little
+ // CSS will be from async chunks
+ config.optimization.splitChunks({
+ cacheGroups: {
+ styles: {
+ name: 'styles',
+ // necessary to ensure async chunks are also extracted
+ test: m => /css-extract/.test(m.type),
+ chunks: 'all',
+ enforce: true
+ }
+ }
+ })
+ }
+
+ // inject constants
+ config
+ .plugin('injections')
+ .use(require('webpack/lib/DefinePlugin'), [{
+ BASE_URL: JSON.stringify(siteConfig.base || '/'),
+ GA_ID: siteConfig.ga ? JSON.stringify(siteConfig.ga) : false,
+ SW_ENABLED: !!siteConfig.serviceWorker,
+ VUEPRESS_VERSION: JSON.stringify(require('../../package.json').version),
+ LAST_COMMIT_HASH: JSON.stringify(getLastCommitHash())
+ }])
+
+ return config
+}
+
+function getLastCommitHash () {
+ const spawn = require('cross-spawn')
+ let hash
+ try {
+ hash = spawn.sync('git', ['log', '-1', '--format=%h']).stdout.toString('utf-8').trim()
+ } catch (error) {}
+ return hash
+}
diff --git a/node_modules/vuepress/lib/webpack/createClientConfig.js b/node_modules/vuepress/lib/webpack/createClientConfig.js
new file mode 100644
index 00000000..8c276633
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/createClientConfig.js
@@ -0,0 +1,69 @@
+module.exports = function createClientConfig (options, cliOptions) {
+ const path = require('path')
+ const WebpackBar = require('webpackbar')
+ const createBaseConfig = require('./createBaseConfig')
+
+ const config = createBaseConfig(options, cliOptions)
+
+ config
+ .entry('app')
+ .add(path.resolve(__dirname, '../app/clientEntry.js'))
+
+ config.node
+ .merge({
+ // prevent webpack from injecting useless setImmediate polyfill because Vue
+ // source contains it (although only uses it if it's native).
+ setImmediate: false,
+ global: false,
+ process: false,
+ // prevent webpack from injecting mocks to Node native modules
+ // that does not make sense for the client
+ dgram: 'empty',
+ fs: 'empty',
+ net: 'empty',
+ tls: 'empty',
+ child_process: 'empty'
+ })
+
+ // generate client manifest only during build
+ if (process.env.NODE_ENV === 'production') {
+ // This is a temp build of vue-server-renderer/client-plugin.
+ // TODO Switch back to original after problems are resolved.
+ // Fixes two things:
+ // 1. Include CSS in preload files
+ // 2. filter out useless styles.xxxxx.js chunk from mini-css-extract-plugin
+ // https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85
+ config
+ .plugin('ssr-client')
+ .use(require('./ClientPlugin'), [{
+ filename: 'manifest/client.json'
+ }])
+
+ config
+ .plugin('optimize-css')
+ .use(require('optimize-css-assets-webpack-plugin'), [{
+ canPrint: false,
+ cssProcessorOptions: {
+ safe: true,
+ autoprefixer: { disable: true },
+ mergeLonghand: false
+ }
+ }])
+ }
+
+ if (!cliOptions.debug) {
+ config
+ .plugin('bar')
+ .use(WebpackBar, [{
+ name: 'Client',
+ color: '#41b883',
+ compiledIn: false
+ }])
+ }
+
+ if (options.siteConfig.chainWebpack) {
+ options.siteConfig.chainWebpack(config, false /* isServer */)
+ }
+
+ return config
+}
diff --git a/node_modules/vuepress/lib/webpack/createServerConfig.js b/node_modules/vuepress/lib/webpack/createServerConfig.js
new file mode 100644
index 00000000..e9f09835
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/createServerConfig.js
@@ -0,0 +1,58 @@
+module.exports = function createServerConfig (options, cliOptions) {
+ const fs = require('fs')
+ const path = require('path')
+ const WebpackBar = require('webpackbar')
+ const createBaseConfig = require('./createBaseConfig')
+ const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
+ const CopyPlugin = require('copy-webpack-plugin')
+
+ const config = createBaseConfig(options, cliOptions, true /* isServer */)
+ const { sourceDir, outDir } = options
+
+ config
+ .target('node')
+ .externals([/^vue|vue-router$/])
+ .devtool('source-map')
+
+ // no need to minimize server build
+ config.optimization.minimize(false)
+
+ config
+ .entry('app')
+ .add(path.resolve(__dirname, '../app/serverEntry.js'))
+
+ config.output
+ .filename('server-bundle.js')
+ .libraryTarget('commonjs2')
+
+ config
+ .plugin('ssr-server')
+ .use(VueSSRServerPlugin, [{
+ filename: 'manifest/server.json'
+ }])
+
+ const publicDir = path.resolve(sourceDir, '.vuepress/public')
+ if (fs.existsSync(publicDir)) {
+ config
+ .plugin('copy')
+ .use(CopyPlugin, [[
+ { from: publicDir, to: outDir }
+ ]])
+ }
+
+ if (!cliOptions.debug) {
+ config
+ .plugin('bar')
+ .use(WebpackBar, [{
+ name: 'Server',
+ color: 'blue',
+ compiledIn: false
+ }])
+ }
+
+ if (options.siteConfig.chainWebpack) {
+ options.siteConfig.chainWebpack(config, true /* isServer */)
+ }
+
+ return config
+}
diff --git a/node_modules/vuepress/lib/webpack/markdownLoader.js b/node_modules/vuepress/lib/webpack/markdownLoader.js
new file mode 100644
index 00000000..3c49b747
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/markdownLoader.js
@@ -0,0 +1,101 @@
+const fs = require('fs')
+const path = require('path')
+const hash = require('hash-sum')
+const { EventEmitter } = require('events')
+const { getOptions } = require('loader-utils')
+const { inferTitle, extractHeaders, parseFrontmatter } = require('../util')
+const LRU = require('lru-cache')
+
+const cache = LRU({ max: 1000 })
+const devCache = LRU({ max: 1000 })
+
+module.exports = function (src) {
+ 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 file = this.resourcePath
+ const key = hash(file + src)
+ const cached = cache.get(key)
+ if (cached && (isProd || /\?vue/.test(this.resourceQuery))) {
+ return cached
+ }
+
+ const frontmatter = parseFrontmatter(src)
+ const content = 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')
+ }
+
+ 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
+ .replace(/#.*$/, '')
+ .replace(/\.html$/, '.md')
+ const filename = shortname
+ .replace(/\/$/, '/README.md')
+ .replace(/^\//, sourceDir + '/')
+ 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))) {
+ this.emitWarning(
+ new Error(
+ `\nFile for relative link "${link}" does not exist.\n` +
+ `(Resolved file: ${file})\n`
+ )
+ )
+ }
+ })
+
+ const res = (
+ `<template>\n` +
+ `<div class="content">${html}</div>\n` +
+ `</template>\n` +
+ (hoistedTags || []).join('\n')
+ )
+ cache.set(key, res)
+ return res
+}
+
+function headersChanged (a, b) {
+ if (a.length !== b.length) return true
+ return a.some((h, i) => (
+ h.title !== b[i].title ||
+ h.level !== b[i].level
+ ))
+}
+
+module.exports.frontmatterEmitter = new EventEmitter()
diff --git a/node_modules/vuepress/lib/webpack/noopModule.js b/node_modules/vuepress/lib/webpack/noopModule.js
new file mode 100644
index 00000000..b1c6ea43
--- /dev/null
+++ b/node_modules/vuepress/lib/webpack/noopModule.js
@@ -0,0 +1 @@
+export default {}