diff options
Diffstat (limited to 'node_modules/vuepress/lib/webpack')
| -rw-r--r-- | node_modules/vuepress/lib/webpack/ClientPlugin.js | 87 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/webpack/DevLogPlugin.js | 38 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/webpack/HeadPlugin.js | 22 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/webpack/createBaseConfig.js | 315 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/webpack/createClientConfig.js | 69 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/webpack/createServerConfig.js | 58 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/webpack/markdownLoader.js | 101 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/webpack/noopModule.js | 1 |
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 {} |
