/*!
 * @nuxt/webpack v2.16.0 (c) 2016-2023
 * Released under the MIT License
 * Repository: https://github.com/nuxt/nuxt.js
 * Website: https://nuxtjs.org
*/
'use strict';

const upath = require('upath');
const pify = require('pify');
const webpack = require('webpack');
const Glob = require('glob');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const consola = require('consola');
const utils = require('@nuxt/utils');
const MFS = require('memory-fs');
const path = require('path');
const querystring = require('querystring');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzer = require('webpack-bundle-analyzer');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('@nuxt/friendly-errors-webpack-plugin');
const EventEmitter = require('events');
const hash = require('hash-sum');
const lodash = require('lodash');
const TimeFixPlugin = require('time-fix-plugin');
const VueLoader = require('vue-loader');
const ExtractCssChunksPlugin = require('extract-css-chunks-webpack-plugin');
const PnpWebpackPlugin = require('pnp-webpack-plugin');
const HardSourcePlugin = require('hard-source-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const WebpackBar = require('webpackbar');
const stdEnv = require('std-env');
const semver = require('semver');
const ufo = require('ufo');
const threadLoader = require('thread-loader');
const fs = require('fs');
const createResolver = require('postcss-import-resolver');
const Watchpack = require('watchpack');
const objectToMap = require('webpack/lib/util/objectToMap');
const nodeExternals = require('webpack-node-externals');

function _interopNamespaceDefault(e) {
  const n = Object.create(null);
  if (e) {
    for (const k in e) {
      if (k !== 'default') {
        const d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    }
  }
  n.default = e;
  return Object.freeze(n);
}

const PnpWebpackPlugin__namespace = /*#__PURE__*/_interopNamespaceDefault(PnpWebpackPlugin);

class AsyncMFS extends MFS {
}
const syncRegex = /Sync$/;
const propsToPromisify = Object.getOwnPropertyNames(MFS.prototype).filter((n) => syncRegex.test(n));
for (const prop of propsToPromisify) {
  const asyncProp = prop.replace(syncRegex, "");
  const origAsync = AsyncMFS.prototype[asyncProp];
  AsyncMFS.prototype[asyncProp] = function(...args) {
    if (origAsync && args.length && typeof args[args.length - 1] === "function") {
      return origAsync.call(this, ...args);
    }
    try {
      return Promise.resolve(MFS.prototype[prop].call(this, ...args));
    } catch (error) {
      return Promise.reject(error);
    }
  };
}

class CorsPlugin {
  constructor({ crossorigin }) {
    this.crossorigin = crossorigin;
  }
  apply(compiler) {
    const ID = "vue-cors-plugin";
    compiler.hooks.compilation.tap(ID, (compilation) => {
      HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tap(ID, (data) => {
        if (!this.crossorigin) {
          return;
        }
        [...data.headTags, ...data.bodyTags].forEach((tag) => {
          if (["script", "link"].includes(tag.tagName)) {
            if (tag.attributes) {
              tag.attributes.crossorigin = this.crossorigin;
            }
          }
        });
      });
    });
  }
}

const legacyTemplateTags = {};
const legacyTemplateWatcher = new EventEmitter();
class ModernModePlugin {
  constructor({ targetDir, isModernBuild, noUnsafeInline }) {
    this.targetDir = targetDir;
    this.isModernBuild = isModernBuild;
    this.noUnsafeInline = noUnsafeInline;
  }
  apply(compiler) {
    if (!this.isModernBuild) {
      this.applyLegacy(compiler);
    } else {
      this.applyModern(compiler);
    }
  }
  getLegacyTemplateTags(name) {
    return new Promise((resolve) => {
      const tags = legacyTemplateTags[name];
      if (tags) {
        return resolve(tags);
      }
      return legacyTemplateWatcher.once(name, () => {
        const tags2 = legacyTemplateTags[name];
        return tags2 && resolve(tags2);
      });
    });
  }
  applyLegacy(compiler) {
    const ID = "nuxt-legacy-bundle";
    compiler.hooks.compilation.tap(ID, (compilation) => {
      HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tap(ID, (data) => {
        HtmlWebpackPlugin.getHooks(compilation).afterEmit.tap(ID, ({ outputName }) => {
          legacyTemplateTags[data.plugin.options.filename] = data.bodyTags;
          legacyTemplateWatcher.emit(outputName);
        });
        return data;
      });
    });
  }
  applyModern(compiler) {
    const ID = "nuxt-modern-bundle";
    compiler.hooks.compilation.tap(ID, (compilation) => {
      HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapPromise(ID, async (data) => {
        data.bodyTags.forEach((tag) => {
          if (tag.tagName === "script" && tag.attributes) {
            tag.attributes.type = "module";
          }
        });
        data.headTags.forEach((tag) => {
          if (tag.tagName === "link" && tag.attributes.rel === "preload" && tag.attributes.as === "script") {
            tag.attributes.rel = "modulepreload";
          }
        });
        const fileName = data.plugin.options.filename;
        const legacyScriptTags = (await this.getLegacyTemplateTags(fileName)).filter((a) => a.tagName === "script" && a.attributes);
        for (const a of legacyScriptTags) {
          a.attributes.nomodule = true;
          data.bodyTags.push(a);
        }
        if (this.noUnsafeInline) {
          const safariFixFilename = "safari-nomodule-fix.js";
          const safariFixPath = legacyScriptTags[0].attributes.src.split("/").slice(0, -1).concat([safariFixFilename]).join("/");
          compilation.assets[safariFixFilename] = {
            source: () => Buffer.from(utils.safariNoModuleFix),
            size: () => Buffer.byteLength(utils.safariNoModuleFix)
          };
          data.bodyTags.push({
            tagName: "script",
            closeTag: true,
            attributes: {
              src: safariFixPath
            }
          });
        } else {
          data.bodyTags.push({
            tagName: "script",
            closeTag: true,
            innerHTML: utils.safariNoModuleFix
          });
        }
        delete legacyTemplateTags[fileName];
        return data;
      });
    });
  }
}

const validate = (compiler) => {
  if (compiler.options.target !== "node") {
    consola.warn('webpack config `target` should be "node".');
  }
  if (compiler.options.output && compiler.options.output.libraryTarget !== "commonjs2") {
    consola.warn('webpack config `output.libraryTarget` should be "commonjs2".');
  }
  if (!compiler.options.externals) {
    consola.info(
      "It is recommended to externalize dependencies in the server build for better build performance."
    );
  }
};
const isJSRegExp = /\.js(\?[^.]+)?$/;
const isJS = (file) => isJSRegExp.test(file);
const extractQueryPartJS = (file) => isJSRegExp.exec(file)[1];
const isCSS = (file) => /\.css(\?[^.]+)?$/.test(file);

class VueSSRClientPlugin {
  constructor(options = {}) {
    this.options = Object.assign({
      filename: null
    }, options);
  }
  apply(compiler) {
    compiler.hooks.emit.tapAsync("vue-client-plugin", (compilation, cb) => {
      const stats = compilation.getStats().toJson();
      const allFiles = lodash.uniq(stats.assets.map((a) => a.name));
      const initialFiles = lodash.uniq(Object.keys(stats.entrypoints).map((name) => stats.entrypoints[name].assets).reduce((assets, all) => all.concat(assets), []).filter((file) => isJS(file) || isCSS(file)));
      const asyncFiles = allFiles.filter((file) => isJS(file) || isCSS(file)).filter((file) => !initialFiles.includes(file));
      const assetsMapping = {};
      stats.assets.filter(({ name }) => isJS(name)).forEach(({ name, chunkNames }) => {
        const componentHash = hash(chunkNames.join("|"));
        if (!assetsMapping[componentHash]) {
          assetsMapping[componentHash] = [];
        }
        assetsMapping[componentHash].push(name);
      });
      const manifest = {
        publicPath: stats.publicPath,
        all: allFiles,
        initial: initialFiles,
        async: asyncFiles,
        modules: {
          /* [identifier: string]: Array<index: number> */
        },
        assetsMapping
      };
      const { entrypoints, namedChunkGroups } = stats;
      const assetModules = stats.modules.filter((m) => m.assets.length);
      const fileToIndex = (file) => manifest.all.indexOf(file);
      stats.modules.forEach((m) => {
        if (m.chunks.length === 1) {
          const [cid] = m.chunks;
          const chunk = stats.chunks.find((c) => c.id === cid);
          if (!chunk || !chunk.files) {
            return;
          }
          const id = m.identifier.replace(/\s\w+$/, "");
          const filesSet = new Set(chunk.files.map(fileToIndex));
          for (const chunkName of chunk.names) {
            if (!entrypoints[chunkName]) {
              const chunkGroup = namedChunkGroups[chunkName];
              if (chunkGroup) {
                for (const asset of chunkGroup.assets) {
                  filesSet.add(fileToIndex(asset));
                }
              }
            }
          }
          const files = Array.from(filesSet);
          manifest.modules[hash(id)] = files;
          if (Array.isArray(m.modules)) {
            for (const concatenatedModule of m.modules) {
              const id2 = hash(concatenatedModule.identifier.replace(/\s\w+$/, ""));
              if (!manifest.modules[id2]) {
                manifest.modules[id2] = files;
              }
            }
          }
          assetModules.forEach((m2) => {
            if (m2.chunks.includes(cid)) {
              files.push.apply(files, m2.assets.map(fileToIndex));
            }
          });
        }
      });
      const src = JSON.stringify(manifest, null, 2);
      compilation.assets[this.options.filename] = {
        source: () => src,
        size: () => src.length
      };
      cb();
    });
  }
}

class PerfLoader {
  constructor(name, buildContext, { resolveModule }) {
    this.name = name;
    this.buildContext = buildContext;
    this.workerPools = PerfLoader.defaultPools({ dev: buildContext.options.dev });
    this.resolveModule = resolveModule;
    return new Proxy(this, {
      get(target, name2) {
        return target[name2] ? target[name2] : target.use.bind(target, name2);
      }
    });
  }
  static defaultPools({ dev }) {
    const poolTimeout = dev ? Infinity : 2e3;
    return {
      js: { name: "js", poolTimeout },
      css: { name: "css", poolTimeout }
    };
  }
  static warmupAll({ dev, resolveModule }) {
    const pools = PerfLoader.defaultPools({ dev });
    PerfLoader.warmup(pools.js, [
      resolveModule("babel-loader"),
      resolveModule("@babel/preset-env")
    ]);
    PerfLoader.warmup(pools.css, [resolveModule("css-loader")]);
  }
  static warmup(...args) {
    threadLoader.warmup(...args);
  }
  use(poolName) {
    const loaders = [];
    if (this.buildContext.buildOptions.cache) {
      loaders.push({
        loader: this.resolveModule("cache-loader"),
        options: {
          cacheDirectory: path.resolve(`node_modules/.cache/cache-loader/${this.name}`)
        }
      });
    }
    if (this.buildContext.buildOptions.parallel) {
      const pool = this.workerPools[poolName];
      if (pool) {
        loaders.push({
          loader: this.resolveModule("thread-loader"),
          options: pool
        });
      }
    }
    return loaders;
  }
}

const orderPresets = {
  cssnanoLast(names) {
    const nanoIndex = names.indexOf("cssnano");
    if (nanoIndex !== names.length - 1) {
      names.push(names.splice(nanoIndex, 1)[0]);
    }
    return names;
  },
  presetEnvLast(names) {
    const nanoIndex = names.indexOf("postcss-preset-env");
    if (nanoIndex !== names.length - 1) {
      names.push(names.splice(nanoIndex, 1)[0]);
    }
    return names;
  },
  presetEnvAndCssnanoLast(names) {
    return orderPresets.cssnanoLast(orderPresets.presetEnvLast(names));
  }
};
function postcssConfigFileWarning() {
  if (postcssConfigFileWarning.executed) {
    return;
  }
  consola.warn("Please use `build.postcss` in your nuxt.config.js instead of an external config file. Support for such files will be removed in Nuxt 3 as they remove all defaults set by Nuxt and can cause severe problems with features like alias resolving inside your CSS.");
  postcssConfigFileWarning.executed = true;
}
class PostcssConfig {
  constructor(buildContext) {
    this.buildContext = buildContext;
  }
  get cssSourceMap() {
    return this.buildContext.buildOptions.cssSourceMap;
  }
  get postcssLoaderOptions() {
    return this.buildContext.buildOptions.postcss;
  }
  get postcssOptions() {
    return this.buildContext.buildOptions.postcss.postcssOptions;
  }
  get postcssImportAlias() {
    const alias = { ...this.buildContext.options.alias };
    for (const key in alias) {
      if (key.startsWith("~")) {
        continue;
      }
      const newKey = "~" + key;
      if (!alias[newKey]) {
        alias[newKey] = alias[key];
      }
    }
    return alias;
  }
  get defaultPostcssOptions() {
    const { dev, srcDir, rootDir, modulesDir } = this.buildContext.options;
    return {
      plugins: {
        // https://github.com/postcss/postcss-import
        "postcss-import": {
          resolve: createResolver({
            alias: this.postcssImportAlias,
            modules: [srcDir, rootDir, ...modulesDir]
          })
        },
        // https://github.com/postcss/postcss-url
        "postcss-url": {},
        // https://github.com/csstools/postcss-preset-env
        "postcss-preset-env": this.postcssLoaderOptions.preset || {},
        cssnano: dev ? false : {
          preset: ["default", {
            // Keep quotes in font values to prevent from HEX conversion
            // https://github.com/nuxt/nuxt.js/issues/6306
            minifyFontValues: { removeQuotes: false }
          }]
        }
      },
      // Array, String or Function
      order: "presetEnvAndCssnanoLast"
    };
  }
  searchConfigFile() {
    const { srcDir, rootDir } = this.buildContext.options;
    for (const dir of [srcDir, rootDir]) {
      for (const file of [
        "postcss.config.js",
        ".postcssrc.js",
        ".postcssrc",
        ".postcssrc.json",
        ".postcssrc.yaml"
      ]) {
        const configFile = path.resolve(dir, file);
        if (fs.existsSync(configFile)) {
          postcssConfigFileWarning();
          return configFile;
        }
      }
    }
  }
  configFromFile() {
    const loaderConfig = this.postcssOptions && this.postcssOptions.config || {};
    if (loaderConfig.path) {
      consola.warn("`postcss-loader` has been removed `config.path` option, please use `config` instead.");
      return {
        config: loaderConfig.path
      };
    }
    const postcssConfigFile = this.searchConfigFile();
    if (postcssConfigFile) {
      return {
        config: postcssConfigFile
      };
    }
  }
  normalize(postcssOptions) {
    if (Array.isArray(postcssOptions)) {
      consola.warn("Using an Array as `build.postcss` will be deprecated in Nuxt 3. Please switch to the object declaration");
      postcssOptions = { plugins: postcssOptions };
    }
    return postcssOptions;
  }
  sortPlugins({ plugins, order }) {
    const names = Object.keys(plugins);
    if (typeof order === "string") {
      order = orderPresets[order];
    }
    return typeof order === "function" ? order(names, orderPresets) : order || names;
  }
  loadPlugins(postcssOptions) {
    const { plugins } = postcssOptions;
    if (utils.isPureObject(plugins)) {
      postcssOptions.plugins = this.sortPlugins(postcssOptions).map((p) => {
        const plugin = this.buildContext.nuxt.resolver.requireModule(p, { paths: [__dirname] });
        const opts = plugins[p];
        if (opts === false) {
          return false;
        }
        return plugin(opts);
      }).filter(Boolean);
    }
  }
  config() {
    if (!this.postcssOptions) {
      return false;
    }
    let postcssOptions = this.configFromFile();
    if (postcssOptions) {
      return {
        postcssOptions,
        sourceMap: this.cssSourceMap
      };
    }
    postcssOptions = this.normalize(lodash.cloneDeep(this.postcssOptions));
    if (utils.isPureObject(postcssOptions)) {
      const postcssLoaderOptions = this.postcssLoaderOptions;
      if (postcssLoaderOptions.plugins && !postcssOptions.plugins) {
        postcssOptions.plugins = postcssLoaderOptions.plugins;
        delete postcssLoaderOptions.plugins;
      }
      if (postcssLoaderOptions.order && !postcssOptions.order) {
        postcssOptions.order = postcssLoaderOptions.order;
        delete postcssLoaderOptions.order;
      }
      if (Array.isArray(postcssOptions.plugins)) {
        lodash.defaults(postcssOptions, this.defaultPostcssOptions);
      } else {
        postcssOptions = lodash.merge({}, this.defaultPostcssOptions, postcssOptions);
        this.loadPlugins(postcssOptions);
      }
      delete postcssOptions.order;
      delete postcssLoaderOptions.preset;
      return {
        sourceMap: this.cssSourceMap,
        ...postcssLoaderOptions,
        postcssOptions
      };
    }
  }
}

class StyleLoader {
  constructor(buildContext, { isServer, perfLoader, resolveModule }) {
    this.buildContext = buildContext;
    this.isServer = isServer;
    this.perfLoader = perfLoader;
    this.resolveModule = resolveModule;
    const { postcss } = buildContext.options.build;
    if (postcss) {
      this.postcssConfig = new PostcssConfig(buildContext);
    }
  }
  get extractCSS() {
    return this.buildContext.buildOptions.extractCSS;
  }
  get exportOnlyLocals() {
    return Boolean(this.isServer && this.extractCSS);
  }
  isUrlResolvingEnabled(url, resourcePath) {
    return !url.startsWith("/");
  }
  normalize(loaders) {
    loaders = utils.wrapArray(loaders);
    return loaders.map((loader) => typeof loader === "string" ? { loader } : loader);
  }
  styleResource(ext) {
    const { buildOptions: { styleResources }, options: { rootDir } } = this.buildContext;
    const extResource = styleResources[ext];
    if (!extResource) {
      return;
    }
    const patterns = utils.wrapArray(extResource).map((p) => path.resolve(rootDir, p));
    return {
      loader: this.resolveModule("style-resources-loader"),
      options: Object.assign(
        { patterns },
        styleResources.options || {}
      )
    };
  }
  postcss() {
    if (!this.postcssConfig) {
      return;
    }
    const config = this.postcssConfig.config();
    if (!config) {
      return;
    }
    return {
      loader: this.resolveModule("postcss-loader"),
      options: Object.assign({ sourceMap: this.buildContext.buildOptions.cssSourceMap }, config)
    };
  }
  css(options) {
    const cssLoader = { loader: this.resolveModule("css-loader"), options };
    if (!options.url) {
      options.url = this.isUrlResolvingEnabled;
    }
    if (this.exportOnlyLocals) {
      options.modules = {
        ...options.modules,
        exportOnlyLocals: true
      };
      return [cssLoader];
    }
    return [this.styleLoader(), cssLoader];
  }
  cssModules(options) {
    return this.css(options);
  }
  extract() {
    if (this.extractCSS) {
      const isDev = this.buildContext.options.dev;
      return {
        loader: ExtractCssChunksPlugin.loader,
        options: {
          // TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132
          // https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/161#issuecomment-500162574
          reloadAll: isDev,
          hmr: isDev
        }
      };
    }
  }
  styleLoader() {
    return this.extract() || {
      loader: this.resolveModule("vue-style-loader"),
      options: this.buildContext.buildOptions.loaders.vueStyle
    };
  }
  apply(ext, loaders = []) {
    const { css, cssModules } = this.buildContext.buildOptions.loaders;
    const customLoaders = [].concat(
      this.postcss(),
      this.normalize(loaders),
      this.styleResource(ext)
    ).filter(Boolean);
    css.importLoaders = cssModules.importLoaders = customLoaders.length;
    return [
      // This matches <style module>
      {
        resourceQuery: /module/,
        use: this.perfLoader.css().concat(
          this.cssModules(cssModules),
          customLoaders
        )
      },
      // This matches plain <style> or <style scoped>
      {
        use: this.perfLoader.css().concat(
          this.css(css),
          customLoaders
        )
      }
    ];
  }
}

class WarningIgnorePlugin {
  constructor(filter) {
    this.filter = filter;
  }
  apply(compiler) {
    compiler.hooks.done.tap("warnfix-plugin", (stats) => {
      stats.compilation.warnings = stats.compilation.warnings.filter(this.filter);
    });
  }
}

class Watchpack2Plugin {
  apply(compiler) {
    if (compiler.watchFileSystem && compiler.watchFileSystem.watcher) {
      compiler.watchFileSystem.watcher.close();
    }
    compiler.watchFileSystem = new NodeWatchFileSystem(
      compiler.inputFileSystem
    );
  }
}
class NodeWatchFileSystem {
  constructor(inputFileSystem) {
    this.inputFileSystem = inputFileSystem;
    this.watcherOptions = {
      aggregateTimeout: 0
    };
    this.watcher = new Watchpack(this.watcherOptions);
  }
  watch(files, dirs, missing, startTime, options, callback, callbackUndelayed) {
    if (!Array.isArray(files)) {
      throw new TypeError("Invalid arguments: 'files'");
    }
    if (!Array.isArray(dirs)) {
      throw new TypeError("Invalid arguments: 'dirs'");
    }
    if (!Array.isArray(missing)) {
      throw new TypeError("Invalid arguments: 'missing'");
    }
    if (typeof callback !== "function") {
      throw new TypeError("Invalid arguments: 'callback'");
    }
    if (typeof startTime !== "number" && startTime) {
      throw new Error("Invalid arguments: 'startTime'");
    }
    if (typeof options !== "object") {
      throw new TypeError("Invalid arguments: 'options'");
    }
    if (typeof callbackUndelayed !== "function" && callbackUndelayed) {
      throw new Error("Invalid arguments: 'callbackUndelayed'");
    }
    const oldWatcher = this.watcher;
    this.watcher = new Watchpack(options);
    if (callbackUndelayed) {
      this.watcher.once("change", callbackUndelayed);
    }
    const cachedFiles = files;
    const cachedDirs = dirs;
    this.watcher.once("aggregated", (_changes, _removals) => {
      const removals = Array.from(_removals);
      const changes = Array.from(_changes).concat(removals);
      if (this.inputFileSystem && this.inputFileSystem.purge) {
        this.inputFileSystem.purge(changes);
      }
      const times = objectToMap(this.watcher.getTimes());
      files = new Set(files);
      dirs = new Set(dirs);
      missing = new Set(missing);
      callback(
        null,
        changes.filter((file) => files.has(file)).sort(),
        changes.filter((file) => dirs.has(file)).sort(),
        changes.filter((file) => missing.has(file)).sort(),
        times,
        times,
        new Set(removals.filter((file) => files.has(file)))
      );
    });
    this.watcher.watch(
      cachedFiles.concat(missing),
      cachedDirs.concat(missing),
      startTime
    );
    if (oldWatcher) {
      oldWatcher.close();
    }
    return {
      close: () => {
        if (this.watcher) {
          this.watcher.close();
          this.watcher = null;
        }
      },
      pause: () => {
        if (this.watcher) {
          this.watcher.pause();
        }
      },
      getFileTimestamps: () => {
        if (this.watcher) {
          return objectToMap(this.watcher.getTimes());
        } else {
          return /* @__PURE__ */ new Map();
        }
      },
      getContextTimestamps: () => {
        if (this.watcher) {
          return objectToMap(this.watcher.getTimes());
        } else {
          return /* @__PURE__ */ new Map();
        }
      }
    };
  }
}

const reservedVueTags = [
  // HTML tags
  "html",
  "body",
  "base",
  "head",
  "link",
  "meta",
  "style",
  "title",
  "address",
  "article",
  "aside",
  "footer",
  "header",
  "h1",
  "h2",
  "h3",
  "h4",
  "h5",
  "h6",
  "hgroup",
  "nav",
  "section",
  "div",
  "dd",
  "dl",
  "dt",
  "figcaption",
  "figure",
  "picture",
  "hr",
  "img",
  "li",
  "main",
  "ol",
  "p",
  "pre",
  "ul",
  "a",
  "b",
  "abbr",
  "bdi",
  "bdo",
  "br",
  "cite",
  "code",
  "data",
  "dfn",
  "em",
  "i",
  "kbd",
  "mark",
  "q",
  "rp",
  "rt",
  "rtc",
  "ruby",
  "s",
  "samp",
  "small",
  "span",
  "strong",
  "sub",
  "sup",
  "time",
  "u",
  "var",
  "wbr",
  "area",
  "audio",
  "map",
  "track",
  "video",
  "embed",
  "object",
  "param",
  "source",
  "canvas",
  "script",
  "noscript",
  "del",
  "ins",
  "caption",
  "col",
  "colgroup",
  "table",
  "thead",
  "tbody",
  "td",
  "th",
  "tr",
  "button",
  "datalist",
  "fieldset",
  "form",
  "input",
  "label",
  "legend",
  "meter",
  "optgroup",
  "option",
  "output",
  "progress",
  "select",
  "textarea",
  "details",
  "dialog",
  "menu",
  "menuitem",
  "summary",
  "content",
  "element",
  "shadow",
  "template",
  "blockquote",
  "iframe",
  "tfoot",
  // SVG tags
  "svg",
  "animate",
  "circle",
  "clippath",
  "cursor",
  "defs",
  "desc",
  "ellipse",
  "filter",
  "font-face",
  "foreignObject",
  "g",
  "glyph",
  "image",
  "line",
  "marker",
  "mask",
  "missing-glyph",
  "path",
  "pattern",
  "polygon",
  "polyline",
  "rect",
  "switch",
  "symbol",
  "text",
  "textpath",
  "tspan",
  "use",
  "view",
  // Vue built-in tags
  "slot",
  "component"
];

class WebpackBaseConfig {
  constructor(builder) {
    this.builder = builder;
    this.buildContext = builder.buildContext;
    this.resolveModule = (id) => utils.tryResolve(id, [this.buildContext.options.rootDir, __dirname]) || id;
  }
  get colors() {
    return {
      client: "green",
      server: "orange",
      modern: "blue"
    };
  }
  get nuxtEnv() {
    return {
      isDev: this.dev,
      isServer: this.isServer,
      isClient: !this.isServer,
      isModern: Boolean(this.isModern),
      isLegacy: Boolean(!this.isModern)
    };
  }
  get mode() {
    return this.dev ? "development" : "production";
  }
  get target() {
    return this.buildContext.target;
  }
  get dev() {
    return this.buildContext.options.dev;
  }
  get loaders() {
    if (!this._loaders) {
      this._loaders = lodash.cloneDeep(this.buildContext.buildOptions.loaders);
      const sassLoaderPKG = utils.getPKG("sass-loader");
      if (sassLoaderPKG && semver.lt(sassLoaderPKG.version, "8.0.0")) {
        const { sass } = this._loaders;
        sass.indentedSyntax = sass.sassOptions.indentedSyntax;
        delete sass.sassOptions.indentedSyntax;
      }
    }
    return this._loaders;
  }
  get modulesToTranspile() {
    return [
      /\.vue\.js/i,
      // include SFCs in node_modules
      /consola\/src/,
      /ufo/,
      // exports modern syntax for browser field
      ...this.normalizeTranspile({ pathNormalize: true })
    ];
  }
  normalizeTranspile({ pathNormalize = false } = {}) {
    const transpile = [];
    for (let pattern of this.buildContext.buildOptions.transpile) {
      if (typeof pattern === "function") {
        pattern = pattern(this.nuxtEnv);
      }
      if (pattern instanceof RegExp) {
        transpile.push(pattern);
      } else if (typeof pattern === "string") {
        const posixModule = pattern.replace(/\\/g, "/");
        transpile.push(new RegExp(lodash.escapeRegExp(
          pathNormalize ? path.normalize(posixModule) : posixModule
        )));
      }
    }
    return transpile;
  }
  getBabelOptions() {
    const envName = this.name;
    const { buildOptions: { corejs }, options: { rootDir } } = this.buildContext;
    const options = {
      ...this.buildContext.buildOptions.babel,
      envName
    };
    if (options.configFile || options.babelrc) {
      return options;
    }
    if (typeof options.plugins === "function") {
      options.plugins = options.plugins(
        {
          envName,
          ...this.nuxtEnv
        }
      );
    }
    let corejsVersion = corejs;
    if (corejsVersion === "auto") {
      try {
        corejsVersion = Number.parseInt(utils.requireModule("core-js/package.json", rootDir).version.split(".")[0]);
      } catch (_err) {
        corejsVersion = 3;
      }
    } else {
      corejsVersion = Number.parseInt(corejsVersion);
    }
    if (![2, 3].includes(corejsVersion)) {
      consola.warn(`Invalid corejs version ${corejsVersion}! Please set "build.corejs" to either "auto", 2 or 3.`);
      corejsVersion = 3;
    }
    const defaultPreset = [this.resolveModule("@nuxt/babel-preset-app"), {
      corejs: {
        version: corejsVersion
      }
    }];
    if (typeof options.presets === "function") {
      options.presets = options.presets(
        {
          envName,
          ...this.nuxtEnv
        },
        defaultPreset
      );
    }
    if (!options.presets) {
      options.presets = [defaultPreset];
    }
    return options;
  }
  getFileName(key) {
    let fileName = this.buildContext.buildOptions.filenames[key];
    if (typeof fileName === "function") {
      fileName = fileName(this.nuxtEnv);
    }
    if (this.dev) {
      const hash = /\[(chunkhash|contenthash|hash)(?::(\d+))?]/.exec(fileName);
      if (hash) {
        consola.warn(`Notice: Please do not use ${hash[1]} in dev mode to prevent memory leak`);
      }
    }
    if (this.buildContext.buildOptions.analyze && !fileName.includes("[name]")) {
      fileName = "[name]." + fileName;
    }
    return fileName;
  }
  env() {
    const env = {
      "process.env.NODE_ENV": JSON.stringify(this.mode),
      "process.mode": JSON.stringify(this.mode),
      "process.dev": this.dev,
      "process.static": this.target === utils.TARGETS.static,
      "process.target": JSON.stringify(this.target)
    };
    if (this.buildContext.buildOptions.aggressiveCodeRemoval) {
      env["typeof process"] = JSON.stringify(this.isServer ? "object" : "undefined");
      env["typeof window"] = JSON.stringify(!this.isServer ? "object" : "undefined");
      env["typeof document"] = JSON.stringify(!this.isServer ? "object" : "undefined");
    }
    Object.entries(this.buildContext.options.env).forEach(([key, value]) => {
      env["process.env." + key] = ["boolean", "number"].includes(typeof value) ? value : JSON.stringify(value);
    });
    return env;
  }
  output() {
    const {
      options: { buildDir, router },
      buildOptions: { publicPath }
    } = this.buildContext;
    return {
      path: path.resolve(buildDir, "dist", this.isServer ? "server" : "client"),
      filename: this.getFileName("app"),
      futureEmitAssets: true,
      // TODO: Remove when using webpack 5
      chunkFilename: this.getFileName("chunk"),
      publicPath: utils.isUrl(publicPath) ? publicPath : ufo.isRelative(publicPath) ? publicPath.replace(/^\.+\//, "/") : utils.urlJoin(router.base, publicPath)
    };
  }
  optimization() {
    const optimization = lodash.cloneDeep(this.buildContext.buildOptions.optimization);
    if (optimization.minimize && optimization.minimizer === void 0) {
      optimization.minimizer = this.minimizer();
    }
    return optimization;
  }
  resolve() {
    const webpackModulesDir = ["node_modules"].concat(this.buildContext.options.modulesDir);
    const resolvePath = [
      ...global.__NUXT_PREPATHS__ || [],
      this.buildContext.options.rootDir,
      __dirname,
      ...global.__NUXT_PATHS__ || [],
      utils.resolveModule("@nuxt/vue-app"),
      utils.resolveModule("@nuxt/babel-preset-app")
    ];
    const resolvePlugins = [PnpWebpackPlugin__namespace].concat(resolvePath.map((p) => PnpWebpackPlugin__namespace.moduleLoader(p)));
    return {
      resolve: {
        extensions: [".mjs", ".cjs", ".js", ".json", ".vue", ".jsx", ".wasm"],
        alias: this.alias(),
        modules: webpackModulesDir,
        plugins: resolvePlugins
      },
      resolveLoader: {
        modules: [
          path.resolve(__dirname, "../node_modules"),
          ...webpackModulesDir
        ],
        plugins: resolvePlugins
      }
    };
  }
  minimizer() {
    const minimizer = [];
    const { terser, cache } = this.buildContext.buildOptions;
    if (terser) {
      minimizer.push(
        new TerserWebpackPlugin(Object.assign({
          cache,
          extractComments: {
            condition: "some",
            filename: "LICENSES"
          },
          terserOptions: {
            compress: {
              ecma: this.isModern ? 2015 : void 0
            },
            mangle: {
              reserved: reservedVueTags
            }
          }
        }, terser))
      );
    }
    return minimizer;
  }
  alias() {
    return {
      ...this.buildContext.options.alias,
      "vue-meta": this.resolveModule(`vue-meta${this.isServer ? "" : "/dist/vue-meta.esm.browser.js"}`)
    };
  }
  rules() {
    const perfLoader = new PerfLoader(this.name, this.buildContext, { resolveModule: this.resolveModule });
    const styleLoader = new StyleLoader(
      this.buildContext,
      { isServer: this.isServer, perfLoader, resolveModule: this.resolveModule }
    );
    const babelLoader = {
      loader: this.resolveModule("babel-loader"),
      options: this.getBabelOptions()
    };
    return [
      {
        test: /\.vue$/i,
        loader: this.resolveModule("vue-loader"),
        options: this.loaders.vue
      },
      {
        test: /\.pug$/i,
        oneOf: [
          {
            resourceQuery: /^\?vue/i,
            use: [{
              loader: this.resolveModule("pug-plain-loader"),
              options: this.loaders.pugPlain
            }]
          },
          {
            use: [
              this.resolveModule("raw-loader"),
              {
                loader: this.resolveModule("pug-plain-loader"),
                options: this.loaders.pugPlain
              }
            ]
          }
        ]
      },
      {
        test: /\.(c|m)?jsx?$/i,
        type: "javascript/auto",
        exclude: (file) => {
          file = file.split(/node_modules(.*)/)[1];
          if (!file) {
            return false;
          }
          return !this.modulesToTranspile.some((module) => module.test(file));
        },
        use: perfLoader.js().concat(babelLoader)
      },
      {
        test: /\.css$/i,
        oneOf: styleLoader.apply("css")
      },
      {
        test: /\.p(ost)?css$/i,
        oneOf: styleLoader.apply("postcss")
      },
      {
        test: /\.less$/i,
        oneOf: styleLoader.apply("less", {
          loader: this.resolveModule("less-loader"),
          options: this.loaders.less
        })
      },
      {
        test: /\.sass$/i,
        oneOf: styleLoader.apply("sass", {
          loader: this.resolveModule("sass-loader"),
          options: this.loaders.sass
        })
      },
      {
        test: /\.scss$/i,
        oneOf: styleLoader.apply("scss", {
          loader: this.resolveModule("sass-loader"),
          options: this.loaders.scss
        })
      },
      {
        test: /\.styl(us)?$/i,
        oneOf: styleLoader.apply("stylus", {
          loader: this.resolveModule("stylus-loader"),
          options: this.loaders.stylus
        })
      },
      {
        test: /\.(png|jpe?g|gif|svg|webp|avif)$/i,
        use: [{
          loader: this.resolveModule("url-loader"),
          options: Object.assign(
            this.loaders.imgUrl,
            { name: this.getFileName("img") }
          )
        }]
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
        use: [{
          loader: this.resolveModule("url-loader"),
          options: Object.assign(
            this.loaders.fontUrl,
            { name: this.getFileName("font") }
          )
        }]
      },
      {
        test: /\.(webm|mp4|ogv)$/i,
        use: [{
          loader: this.resolveModule("file-loader"),
          options: Object.assign(
            this.loaders.file,
            { name: this.getFileName("video") }
          )
        }]
      }
    ];
  }
  plugins() {
    const plugins = [];
    const { nuxt, buildOptions } = this.buildContext;
    if (this.dev) {
      plugins.push(new TimeFixPlugin());
    }
    if (buildOptions.extractCSS) {
      plugins.push(new ExtractCssChunksPlugin(Object.assign({
        filename: this.getFileName("css"),
        chunkFilename: this.getFileName("css")
      }, buildOptions.extractCSS)));
    }
    plugins.push(new VueLoader.VueLoaderPlugin());
    plugins.push(...buildOptions.plugins || []);
    plugins.push(new WarningIgnorePlugin(this.warningIgnoreFilter()));
    plugins.push(new WebpackBar({
      name: this.name,
      color: this.colors[this.name],
      reporters: [
        "basic",
        "fancy",
        "profile",
        "stats"
      ],
      basic: !buildOptions.quiet && stdEnv.isMinimal,
      fancy: !buildOptions.quiet && !stdEnv.isMinimal,
      profile: !buildOptions.quiet && buildOptions.profile,
      stats: !buildOptions.quiet && !this.dev && buildOptions.stats,
      reporter: {
        change: (_, { shortPath }) => {
          if (!this.isServer) {
            nuxt.callHook("bundler:change", shortPath);
          }
        },
        done: (buildContext) => {
          if (buildContext.hasErrors) {
            nuxt.callHook("bundler:error");
          }
        },
        allDone: () => {
          nuxt.callHook("bundler:done");
        },
        progress({ statesArray }) {
          nuxt.callHook("bundler:progress", statesArray);
        }
      }
    }));
    if (buildOptions.hardSource) {
      plugins.push(new HardSourcePlugin({
        info: {
          level: "warn"
        },
        ...buildOptions.hardSource
      }));
    }
    plugins.push(new Watchpack2Plugin());
    return plugins;
  }
  warningIgnoreFilter() {
    const filters = [
      // Hide warnings about plugins without a default export (#1179)
      (warn) => warn.name === "ModuleDependencyWarning" && warn.message.includes("export 'default'") && warn.message.includes("nuxt_plugin_"),
      ...this.buildContext.buildOptions.warningIgnoreFilters || []
    ];
    return (warn) => !filters.some((ignoreFilter) => ignoreFilter(warn));
  }
  extendConfig(config) {
    const { extend } = this.buildContext.buildOptions;
    if (typeof extend === "function") {
      const extendedConfig = extend.call(
        this.builder,
        config,
        { loaders: this.loaders, ...this.nuxtEnv }
      ) || config;
      const pragma = /@|#/;
      const { devtool } = extendedConfig;
      if (typeof devtool === "string" && pragma.test(devtool)) {
        extendedConfig.devtool = devtool.replace(pragma, "");
        consola.warn(`devtool has been normalized to ${extendedConfig.devtool} as webpack documented value`);
      }
      return extendedConfig;
    }
    return config;
  }
  config() {
    const config = {
      name: this.name,
      mode: this.mode,
      devtool: this.devtool,
      optimization: this.optimization(),
      output: this.output(),
      performance: {
        maxEntrypointSize: 1e3 * 1024,
        hints: this.dev ? false : "warning"
      },
      module: {
        rules: this.rules()
      },
      plugins: this.plugins(),
      ...this.resolve()
    };
    const extendedConfig = lodash.cloneDeep(this.extendConfig(config));
    return extendedConfig;
  }
}

class WebpackClientConfig extends WebpackBaseConfig {
  constructor(builder) {
    super(builder);
    this.name = "client";
    this.isServer = false;
    this.isModern = false;
  }
  get devtool() {
    if (!this.dev) {
      return false;
    }
    const scriptPolicy = this.getCspScriptPolicy();
    const noUnsafeEval = scriptPolicy && !scriptPolicy.includes("'unsafe-eval'");
    return noUnsafeEval ? "cheap-module-source-map" : "cheap-module-eval-source-map";
  }
  getCspScriptPolicy() {
    const { csp } = this.buildContext.options.render;
    if (csp) {
      const { policies = {} } = csp;
      return policies["script-src"] || policies["default-src"] || [];
    }
  }
  env() {
    return Object.assign(
      super.env(),
      {
        "process.env.VUE_ENV": JSON.stringify("client"),
        "process.browser": true,
        "process.client": true,
        "process.server": false,
        "process.modern": false
      }
    );
  }
  optimization() {
    const optimization = super.optimization();
    const { splitChunks } = optimization;
    const { cacheGroups } = splitChunks;
    if (this.buildContext.buildOptions.splitChunks.commons === true && cacheGroups.commons === void 0) {
      cacheGroups.commons = {
        test: /node_modules[\\/](vue|vue-loader|vue-router|vuex|vue-meta|core-js|@babel\/runtime|axios|webpack|setimmediate|timers-browserify|process|regenerator-runtime|cookie|js-cookie|is-buffer|dotprop|url-polyfill|@nuxt[\\/]ufo|ufo|nuxt\.js)[\\/]/,
        chunks: "all",
        name: true,
        priority: 10
      };
    }
    return optimization;
  }
  minimizer() {
    const minimizer = super.minimizer();
    const { optimizeCSS } = this.buildContext.buildOptions;
    if (optimizeCSS) {
      minimizer.push(new OptimizeCSSAssetsPlugin(Object.assign({}, optimizeCSS)));
    }
    return minimizer;
  }
  alias() {
    const aliases = super.alias();
    for (const p of this.buildContext.plugins) {
      if (!aliases[p.name]) {
        aliases[p.name] = p.mode === "server" ? "./empty.js" : p.src;
      }
    }
    return aliases;
  }
  plugins() {
    const plugins = super.plugins();
    const { buildOptions, options: { appTemplatePath, buildDir, modern, render } } = this.buildContext;
    if (buildOptions.ssr) {
      plugins.push(
        new HtmlWebpackPlugin({
          filename: "../server/index.ssr.html",
          template: appTemplatePath,
          minify: buildOptions.html.minify,
          inject: false
          // Resources will be injected using bundleRenderer
        })
      );
    }
    plugins.push(
      new HtmlWebpackPlugin({
        filename: "../server/index.spa.html",
        template: appTemplatePath,
        minify: buildOptions.html.minify,
        inject: true
      }),
      new VueSSRClientPlugin({
        filename: `../server/${this.name}.manifest.json`
      }),
      new webpack.DefinePlugin(this.env())
    );
    if (this.dev) {
      plugins.push(new webpack.HotModuleReplacementPlugin());
    }
    if (!this.dev && buildOptions.analyze) {
      const statsDir = path.resolve(buildDir, "stats");
      plugins.push(new BundleAnalyzer.BundleAnalyzerPlugin(Object.assign({
        analyzerMode: "static",
        defaultSizes: "gzip",
        generateStatsFile: true,
        openAnalyzer: !buildOptions.quiet,
        reportFilename: path.resolve(statsDir, `${this.name}.html`),
        statsFilename: path.resolve(statsDir, `${this.name}.json`)
      }, buildOptions.analyze)));
    }
    if (modern) {
      const scriptPolicy = this.getCspScriptPolicy();
      const noUnsafeInline = scriptPolicy && !scriptPolicy.includes("'unsafe-inline'");
      plugins.push(new ModernModePlugin({
        targetDir: path.resolve(buildDir, "dist", "client"),
        isModernBuild: this.isModern,
        noUnsafeInline
      }));
    }
    if (render.crossorigin) {
      plugins.push(new CorsPlugin({
        crossorigin: render.crossorigin
      }));
    }
    return plugins;
  }
  config() {
    const config = super.config();
    const {
      options: { router, buildDir },
      buildOptions: { hotMiddleware, quiet, friendlyErrors }
    } = this.buildContext;
    const { client = {} } = hotMiddleware || {};
    const { ansiColors, overlayStyles, ...options } = client;
    const hotMiddlewareClientOptions = {
      reload: true,
      timeout: 3e4,
      ansiColors: JSON.stringify(ansiColors),
      overlayStyles: JSON.stringify(overlayStyles),
      path: `${router.base}/__webpack_hmr/${this.name}`.replace(/\/\//g, "/"),
      ...options,
      name: this.name
    };
    const hotMiddlewareClientOptionsStr = querystring.stringify(hotMiddlewareClientOptions);
    config.entry = Object.assign({}, config.entry, {
      app: [path.resolve(buildDir, "client.js")]
    });
    if (this.dev) {
      config.entry.app.unshift(
        // https://github.com/webpack-contrib/webpack-hot-middleware/issues/53#issuecomment-162823945
        this.resolveModule("eventsource-polyfill"),
        // https://github.com/glenjamin/webpack-hot-middleware#config
        `${this.resolveModule("webpack-hot-middleware/client")}?${hotMiddlewareClientOptionsStr}`
      );
    }
    if (this.dev && !quiet && friendlyErrors) {
      config.plugins.push(
        new FriendlyErrorsWebpackPlugin({
          clearConsole: false,
          reporter: "consola",
          logLevel: "WARNING"
        })
      );
    }
    return config;
  }
}

class WebpackModernConfig extends WebpackClientConfig {
  constructor(...args) {
    super(...args);
    this.name = "modern";
    this.isModern = true;
  }
  env() {
    return Object.assign(super.env(), {
      "process.modern": true
    });
  }
}

class VueSSRServerPlugin {
  constructor(options = {}) {
    this.options = Object.assign({
      filename: null
    }, options);
  }
  apply(compiler) {
    validate(compiler);
    compiler.hooks.emit.tapAsync("vue-server-plugin", (compilation, cb) => {
      const stats = compilation.getStats().toJson();
      const [entryName] = Object.keys(stats.entrypoints);
      const entryInfo = stats.entrypoints[entryName];
      if (!entryInfo) {
        return cb();
      }
      const entryAssets = entryInfo.assets.filter(isJS);
      if (entryAssets.length > 1) {
        throw new Error(
          "Server-side bundle should have one single entry file. Avoid using CommonsChunkPlugin in the server config."
        );
      }
      const [entry] = entryAssets;
      if (!entry || typeof entry !== "string") {
        throw new Error(
          `Entry "${entryName}" not found. Did you specify the correct entry option?`
        );
      }
      const bundle = {
        entry,
        files: {},
        maps: {}
      };
      stats.assets.forEach((asset) => {
        if (isJS(asset.name)) {
          const queryPart = extractQueryPartJS(asset.name);
          if (queryPart !== void 0) {
            bundle.files[asset.name] = asset.name.replace(queryPart, "");
          } else {
            bundle.files[asset.name] = asset.name;
          }
        } else if (asset.name.match(/\.js\.map$/)) {
          bundle.maps[asset.name.replace(/\.map$/, "")] = asset.name;
        } else {
          delete compilation.assets[asset.name];
        }
      });
      const src = JSON.stringify(bundle, null, 2);
      compilation.assets[this.options.filename] = {
        source: () => src,
        size: () => src.length
      };
      cb();
    });
  }
}

const nativeFileExtensions = [
  ".json",
  ".js"
];
class WebpackServerConfig extends WebpackBaseConfig {
  constructor(...args) {
    super(...args);
    this.name = "server";
    this.isServer = true;
  }
  get devtool() {
    return "cheap-module-source-map";
  }
  get externalsAllowlist() {
    return [
      this.isNonNativeImport.bind(this),
      ...this.normalizeTranspile()
    ];
  }
  /**
   * files *not* ending on js|json should be processed by webpack
   *
   * this might generate false-positives for imports like
   * - "someFile.umd" (actually requiring someFile.umd.js)
   * - "some.folder" (some.folder being a directory containing a package.json)
   */
  isNonNativeImport(modulePath) {
    const extname = path.extname(modulePath);
    return extname !== "" && !nativeFileExtensions.includes(extname);
  }
  env() {
    return Object.assign(
      super.env(),
      {
        "process.env.VUE_ENV": JSON.stringify("server"),
        "process.browser": false,
        "process.client": false,
        "process.server": true,
        "process.modern": false
      }
    );
  }
  optimization() {
    const { _minifyServer } = this.buildContext.buildOptions;
    return {
      splitChunks: false,
      minimizer: _minifyServer ? this.minimizer() : []
    };
  }
  resolve() {
    const resolveConfig = super.resolve();
    resolveConfig.resolve.mainFields = ["main", "module"];
    return resolveConfig;
  }
  alias() {
    const aliases = super.alias();
    for (const p of this.buildContext.plugins) {
      if (!aliases[p.name]) {
        aliases[p.name] = p.mode === "client" ? "./empty.js" : p.src;
      }
    }
    return aliases;
  }
  plugins() {
    const plugins = super.plugins();
    plugins.push(
      new VueSSRServerPlugin({ filename: `${this.name}.manifest.json` }),
      new webpack.DefinePlugin(this.env())
    );
    const { serverURLPolyfill } = this.buildContext.options.build;
    if (serverURLPolyfill) {
      plugins.push(new webpack.ProvidePlugin({
        URL: [serverURLPolyfill, "URL"],
        URLSearchParams: [serverURLPolyfill, "URLSearchParams"]
      }));
    }
    return plugins;
  }
  config() {
    const config = super.config();
    Object.assign(config, {
      target: "node",
      node: false,
      entry: Object.assign({}, config.entry, {
        app: [path.resolve(this.buildContext.options.buildDir, "server.js")]
      }),
      output: Object.assign({}, config.output, {
        filename: "server.js",
        chunkFilename: "[name].js",
        libraryTarget: "commonjs2"
      }),
      performance: {
        hints: false,
        maxEntrypointSize: Infinity,
        maxAssetSize: Infinity
      },
      externals: [].concat(config.externals || [])
    });
    if (!this.buildContext.buildOptions.standalone) {
      this.buildContext.options.modulesDir.forEach((dir) => {
        if (fs.existsSync(dir)) {
          config.externals.push(
            nodeExternals({
              allowlist: this.externalsAllowlist,
              modulesDir: dir
            })
          );
        }
      });
    }
    return config;
  }
}

const WebpackConfigs = /*#__PURE__*/Object.freeze({
  __proto__: null,
  client: WebpackClientConfig,
  modern: WebpackModernConfig,
  server: WebpackServerConfig
});

const glob = pify(Glob);
class WebpackBundler {
  constructor(buildContext) {
    this.buildContext = buildContext;
    this.compilers = [];
    this.compilersWatching = [];
    this.devMiddleware = {};
    this.hotMiddleware = {};
    this.middleware = this.middleware.bind(this);
    if (this.buildContext.options.dev) {
      this.mfs = new AsyncMFS();
    }
  }
  getWebpackConfig(name) {
    const Config = WebpackConfigs[name.toLowerCase()];
    if (!Config) {
      throw new Error(`Unsupported webpack config ${name}`);
    }
    const config = new Config(this);
    return config.config();
  }
  async build() {
    const { options } = this.buildContext;
    const webpackConfigs = [
      this.getWebpackConfig("Client")
    ];
    if (options.modern) {
      webpackConfigs.push(this.getWebpackConfig("Modern"));
    }
    if (options.build.ssr) {
      webpackConfigs.push(this.getWebpackConfig("Server"));
    }
    await this.buildContext.nuxt.callHook("webpack:config", webpackConfigs);
    const { styleResources } = this.buildContext.options.build;
    if (styleResources && Object.keys(styleResources).length) {
      consola.warn(
        "Using styleResources without the @nuxtjs/style-resources is not suggested and can lead to severe performance issues.",
        "Please use https://github.com/nuxt-community/style-resources-module"
      );
      for (const ext of Object.keys(styleResources)) {
        await Promise.all(utils.wrapArray(styleResources[ext]).map(async (p) => {
          const styleResourceFiles = await glob(upath.resolve(this.buildContext.options.rootDir, p));
          if (!styleResourceFiles || styleResourceFiles.length === 0) {
            throw new Error(`Style Resource not found: ${p}`);
          }
        }));
      }
    }
    this.compilers = webpackConfigs.map((config) => {
      const compiler = webpack(config);
      if (options.dev) {
        compiler.outputFileSystem = this.mfs;
      }
      return compiler;
    });
    if (options.build.parallel) {
      consola.info("Warming up worker pools");
      PerfLoader.warmupAll({ dev: options.dev, resolveModule: (id) => utils.tryResolve(id, __filename) || id });
      consola.success("Worker pools ready");
    }
    const runner = options.dev ? utils.parallel : utils.sequence;
    await runner(this.compilers, (compiler) => this.webpackCompile(compiler));
  }
  async webpackCompile(compiler) {
    const { name } = compiler.options;
    const { nuxt, options } = this.buildContext;
    await nuxt.callHook("build:compile", { name, compiler });
    compiler.hooks.done.tap("load-resources", async (stats2) => {
      await nuxt.callHook("build:compiled", {
        name,
        compiler,
        stats: stats2
      });
      await nuxt.callHook("build:resources", this.mfs);
    });
    if (options.dev) {
      if (["client", "modern"].includes(name)) {
        return new Promise((resolve, reject) => {
          compiler.hooks.done.tap("nuxt-dev", () => resolve());
          return this.webpackDev(compiler);
        });
      }
      return new Promise((resolve, reject) => {
        const watching = compiler.watch(options.watchers.webpack, (err) => {
          if (err) {
            return reject(err);
          }
          resolve();
        });
        watching.close = pify(watching.close);
        this.compilersWatching.push(watching);
      });
    }
    compiler.run = pify(compiler.run);
    const stats = await compiler.run();
    if (stats.hasErrors()) {
      const error = new Error("Nuxt build error");
      if (options.build.quiet === true) {
        error.stack = stats.toString("errors-only");
      }
      throw error;
    }
    await nuxt.callHook("build:resources");
  }
  async webpackDev(compiler) {
    consola.debug("Creating webpack middleware...");
    const { name } = compiler.options;
    const buildOptions = this.buildContext.options.build;
    const { client, ...hotMiddlewareOptions } = buildOptions.hotMiddleware || {};
    compiler.options.watchOptions = this.buildContext.options.watchers.webpack;
    compiler.hooks.infrastructureLog.tap("webpack-dev-middleware-log", (name2) => {
      if (name2 === "webpack-dev-middleware") {
        return false;
      }
      return void 0;
    });
    this.devMiddleware[name] = pify(
      webpackDevMiddleware(
        compiler,
        {
          outputFileSystem: compiler.outputFileSystem,
          ...buildOptions.devMiddleware
        }
      )
    );
    this.devMiddleware[name].close = pify(this.devMiddleware[name].close);
    this.compilersWatching.push(this.devMiddleware[name].context.watching);
    this.hotMiddleware[name] = pify(
      webpackHotMiddleware(
        compiler,
        {
          log: false,
          heartbeat: 1e4,
          path: `/__webpack_hmr/${name}`,
          ...hotMiddlewareOptions
        }
      )
    );
    await this.buildContext.nuxt.callHook("server:devMiddleware", this.middleware);
  }
  async middleware(req, res, next) {
    const name = utils.isModernRequest(req, this.buildContext.options.modern) ? "modern" : "client";
    if (this.devMiddleware && this.devMiddleware[name]) {
      const { url } = req;
      req.url = req.originalUrl || req.url;
      await this.devMiddleware[name](req, res);
      req.url = url;
    }
    if (this.hotMiddleware && this.hotMiddleware[name]) {
      await this.hotMiddleware[name](req, res);
    }
    next();
  }
  async unwatch() {
    await Promise.all(this.compilersWatching.map((watching) => watching.close()));
  }
  async close() {
    if (this.__closed) {
      return;
    }
    this.__closed = true;
    await this.unwatch();
    for (const devMiddleware of Object.values(this.devMiddleware)) {
      await devMiddleware.close();
    }
    if (this.mfs) {
      delete this.mfs.data;
      delete this.mfs;
    }
    delete this.compilers;
    delete this.compilersWatching;
    delete this.devMiddleware;
    delete this.hotMiddleware;
  }
  forGenerate() {
    this.buildContext.target = utils.TARGETS.static;
  }
}

exports.BundleBuilder = WebpackBundler;
