gatsby
Version:
Blazing fast modern site generator for React
807 lines (786 loc) • 31.9 kB
JavaScript
var _path = require("./path");
var _gatsbyDependents = require("./gatsby-dependents");
var _webpackUtils = require("./webpack-utils");
var _localEslintConfigFinder = require("./local-eslint-config-finder");
var _gatsbyWebpackVirtualModules = require("./gatsby-webpack-virtual-modules");
var _staticQueryMapper = require("./webpack/plugins/static-query-mapper");
var _forceCssHmrForEdgeCases = require("./webpack/plugins/force-css-hmr-for-edge-cases");
var _webpackLogging = require("./webpack/plugins/webpack-logging");
var _browserslist = require("./browserslist");
var _module = require("module");
var _enginesHelpers = require("./engines-helpers");
var _constants = require("../constants");
var _babelLoader = require("./babel-loader");
var _partialHydration = require("./webpack/plugins/partial-hydration");
var _resolveJsFilePath = require("../bootstrap/resolve-js-file-path");
const crypto = require(`crypto`);
const fs = require(`fs-extra`);
const path = require(`path`);
const dotenv = require(`dotenv`);
const {
CoreJSResolver
} = require(`./webpack/plugins/corejs-resolver`);
const {
CacheFolderResolver
} = require(`./webpack/plugins/cache-folder-resolver`);
const {
store
} = require(`../redux`);
const {
actions
} = require(`../redux/actions`);
const {
getPublicPath
} = require(`./get-public-path`);
const debug = require(`debug`)(`gatsby:webpack-config`);
const reporter = require(`gatsby-cli/lib/reporter`);
const apiRunnerNode = require(`./api-runner-node`);
const FRAMEWORK_BUNDLES = [`react`, `react-dom`, `scheduler`, `prop-types`];
// This regex ignores nested copies of framework libraries so they're bundled with their issuer
const FRAMEWORK_BUNDLES_REGEX = new RegExp(`(?<!node_modules.*)[\\\\/]node_modules[\\\\/](${FRAMEWORK_BUNDLES.join(`|`)})[\\\\/]`);
// Four stages or modes:
// 1) develop: for `gatsby develop` command, hot reload and CSS injection into page
// 2) develop-html: same as develop without react-hmre in the babel config for html renderer
// 3) build-javascript: Build JS and CSS chunks for production
// 4) build-html: build all HTML files
module.exports = async (program, directory, suppliedStage, port, {
parentSpan
} = {}) => {
let fastRefreshPlugin;
const modulesThatUseGatsby = await (0, _gatsbyDependents.getGatsbyDependents)();
const directoryPath = (0, _path.withBasePath)(directory);
// We combine develop & develop-html stages for purposes of generating the
// webpack config.
const stage = suppliedStage;
const {
rules,
loaders,
plugins
} = (0, _webpackUtils.createWebpackUtils)(stage, program);
const {
assetPrefix,
pathPrefix,
trailingSlash
} = store.getState().config;
const publicPath = getPublicPath({
assetPrefix,
pathPrefix,
...program
});
const isPartialHydrationEnabled = (process.env.GATSBY_PARTIAL_HYDRATION === `true` || process.env.GATSBY_PARTIAL_HYDRATION === `1`) && "5" === `5`;
function processEnv(stage, defaultNodeEnv) {
debug(`Building env for "${stage}"`);
// node env should be DEVELOPMENT | PRODUCTION as these are commonly used in node land
// this variable is used inside webpack
const nodeEnv = process.env.NODE_ENV || `${defaultNodeEnv}`;
// config env is dependent on the env that it's run, this can be anything from staging-production
// this allows you to set use different .env environments or conditions in gatsby files
const configEnv = process.env.GATSBY_ACTIVE_ENV || nodeEnv;
const envFile = path.join(process.cwd(), `./.env.${configEnv}`);
let parsed = {};
try {
parsed = dotenv.parse(fs.readFileSync(envFile, {
encoding: `utf8`
}));
} catch (err) {
if (err.code !== `ENOENT`) {
reporter.error(`There was a problem processing the .env file (${envFile})`, err);
}
}
const target = stage === `build-html` || stage === `develop-html` ? `node` : `web`;
const envObject = Object.keys(parsed).reduce((acc, key) => {
acc[key] = JSON.stringify(parsed[key]);
return acc;
}, {});
const gatsbyVarObject = Object.keys(process.env).reduce((acc, key) => {
if (target === `node` || key.match(/^GATSBY_/)) {
acc[key] = JSON.stringify(process.env[key]);
}
return acc;
}, {});
// Don't allow overwriting of NODE_ENV, PUBLIC_DIR as to not break gatsby things
envObject.NODE_ENV = JSON.stringify(nodeEnv);
envObject.PUBLIC_DIR = JSON.stringify(`${process.cwd()}/public`);
envObject.BUILD_STAGE = JSON.stringify(stage);
envObject.CYPRESS_SUPPORT = JSON.stringify(process.env.CYPRESS_SUPPORT);
envObject.GATSBY_QUERY_ON_DEMAND = JSON.stringify(!!process.env.GATSBY_QUERY_ON_DEMAND);
if (stage === `develop`) {
envObject.GATSBY_SOCKET_IO_DEFAULT_TRANSPORT = JSON.stringify(process.env.GATSBY_SOCKET_IO_DEFAULT_TRANSPORT || `websocket`);
}
const mergedEnvVars = Object.assign(envObject, gatsbyVarObject);
return Object.keys(mergedEnvVars).reduce((acc, key) => {
acc[`process.env.${key}`] = mergedEnvVars[key];
return acc;
}, {
"process.env": `({})`
});
}
debug(`Loading webpack config for stage "${stage}"`);
function getOutput() {
switch (stage) {
case `develop`:
return {
path: directory,
filename: `[name].js`,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// Point sourcemap entries to original disk location (format as URL on Windows)
publicPath: process.env.GATSBY_WEBPACK_PUBLICPATH || `/`,
devtoolModuleFilenameTemplate: info => path.resolve(info.absoluteResourcePath).replace(/\\/g, `/`),
// Avoid React cross-origin errors
// See https://reactjs.org/docs/cross-origin-errors.html
crossOriginLoading: `anonymous`
};
case `build-html`:
case `develop-html`:
// Generate the file needed to SSR pages.
// Deleted by build-html.js, since it's not needed for production.
return {
path: directoryPath(_constants.ROUTES_DIRECTORY),
filename: `[name].js`,
chunkFilename: `[name].js`,
library: {
type: `commonjs`
},
publicPath: (0, _path.withTrailingSlash)(publicPath)
};
case `build-javascript`:
return {
filename: `[name]-[contenthash].js`,
chunkFilename: `[name]-[contenthash].js`,
path: directoryPath(`public`),
publicPath: (0, _path.withTrailingSlash)(publicPath)
};
default:
throw new Error(`The state requested ${stage} doesn't exist.`);
}
}
function getEntry() {
switch (stage) {
case `develop`:
return (0, _browserslist.hasES6ModuleSupport)(directory) ? {
commons: [directoryPath(`.cache/app`)]
} : {
polyfill: directoryPath(`.cache/polyfill-entry`),
commons: [directoryPath(`.cache/app`)]
};
case `develop-html`:
return {
"render-page": process.env.GATSBY_EXPERIMENTAL_DEV_SSR ? directoryPath(`.cache/ssr-develop-static-entry`) : directoryPath(`.cache/develop-static-entry`)
};
case `build-html`:
{
return {
"render-page": directoryPath(`.cache/static-entry`)
};
}
case `build-javascript`:
return (0, _browserslist.hasES6ModuleSupport)(directory) ? {
app: directoryPath(`.cache/production-app`)
} : {
polyfill: directoryPath(`.cache/polyfill-entry`),
app: directoryPath(`.cache/production-app`)
};
default:
throw new Error(`The state requested ${stage} doesn't exist.`);
}
}
function getPlugins() {
var _process$env$GATSBY_W, _process$env$GATSBY_W2;
let configPlugins = [plugins.moment(),
// Add a few global variables. Set NODE_ENV to production (enables
// optimizations for React) and what the link prefix is (__PATH_PREFIX__).
plugins.define({
...processEnv(stage, `development`),
__BASE_PATH__: JSON.stringify(program.prefixPaths ? pathPrefix : ``),
__PATH_PREFIX__: JSON.stringify(program.prefixPaths ? publicPath : ``),
__ASSET_PREFIX__: JSON.stringify(program.prefixPaths ? assetPrefix : ``),
__TRAILING_SLASH__: JSON.stringify(trailingSlash),
// TODO Improve asset passing to pages
BROWSER_ESM_ONLY: JSON.stringify((0, _browserslist.hasES6ModuleSupport)(directory)),
"global.hasPartialHydration": isPartialHydrationEnabled
}), plugins.virtualModules(), new _babelLoader.BabelConfigItemsCacheInvalidatorPlugin(), ((_process$env$GATSBY_W = process.env.GATSBY_WEBPACK_LOGGING) === null || _process$env$GATSBY_W === void 0 ? void 0 : (_process$env$GATSBY_W2 = _process$env$GATSBY_W.split(`,`)) === null || _process$env$GATSBY_W2 === void 0 ? void 0 : _process$env$GATSBY_W2.includes(stage)) && new _webpackLogging.WebpackLoggingPlugin(program.directory, reporter, program.verbose)].filter(Boolean);
switch (stage) {
case `develop`:
{
configPlugins = configPlugins.concat([fastRefreshPlugin = plugins.fastRefresh({
modulesThatUseGatsby
}), new _forceCssHmrForEdgeCases.ForceCssHMRForEdgeCases(), plugins.hotModuleReplacement(), plugins.noEmitOnErrors(), new _staticQueryMapper.StaticQueryMapper(store)]).filter(Boolean);
configPlugins.push(plugins.extractText({
filename: `[name].css`,
chunkFilename: `[id].css`
}));
if (process.env.GATSBY_EXPERIMENTAL_DEV_SSR) {
configPlugins.push(plugins.extractStats());
}
const isCustomEslint = (0, _localEslintConfigFinder.hasLocalEslint)(program.directory);
// if no local eslint config, then add gatsby config
if (!isCustomEslint) {
configPlugins.push(plugins.eslint());
}
// Enforce fast-refresh rules even with local eslint config
if (isCustomEslint) {
configPlugins.push(plugins.eslintRequired());
}
break;
}
case `build-javascript`:
{
configPlugins = configPlugins.concat([plugins.extractText({
filename: `[name].[contenthash].css`,
chunkFilename: `[name].[contenthash].css`
}),
// Write out stats object mapping named dynamic imports (aka page
// components) to all their async chunks.
plugins.extractStats(), new _staticQueryMapper.StaticQueryMapper(store), isPartialHydrationEnabled ? new _partialHydration.PartialHydrationPlugin(path.join(directory, `.cache`, `partial-hydration`, `manifest.json`), reporter) : null]).filter(Boolean);
break;
}
case `develop-html`:
case `build-html`:
{
// Add global fetch in node environments
configPlugins.push(plugins.provide({
fetch: require.resolve(`node-fetch`),
"global.fetch": require.resolve(`node-fetch`)
}));
break;
}
}
return configPlugins;
}
function getDevtool() {
switch (stage) {
case `develop`:
return `eval-cheap-module-source-map`;
// use a normal `source-map` for the html phases since
// it gives better line and column numbers
case `develop-html`:
case `build-html`:
case `build-javascript`:
return `source-map`;
default:
return false;
}
}
function getMode() {
switch (stage) {
case `develop`:
case `develop-html`:
return `development`;
case `build-javascript`:
case `build-html`:
default:
return `production`;
}
}
function getModule() {
// Common config for every env.
// prettier-ignore
let configRules = [
// Webpack expects extensions when importing ESM modules as that's what the spec describes.
// Not all libraries have adapted so we don't enforce its behaviour
// @see https://github.com/webpack/webpack/issues/11467
{
test: /\.mjs$/i,
resolve: {
byDependency: {
esm: {
fullySpecified: false
}
}
}
}, {
test: /\.js$/i,
descriptionData: {
type: `module`
},
resolve: {
byDependency: {
esm: {
fullySpecified: false
}
}
}
}, rules.js({
modulesThatUseGatsby
}), rules.yaml(), rules.fonts(), rules.images(), rules.media(), rules.miscAssets()];
// TODO(v5): Remove since this is only useful during Gatsby 4 publishes
if ("5" !== `5`) {
configRules.push({
test: require.resolve(`@gatsbyjs/reach-router/es/index`),
type: `javascript/auto`,
use: [{
loader: require.resolve(`./reach-router-add-basecontext-export-loader`)
}]
});
}
// Speedup 🏎️💨 the build! We only include transpilation of node_modules on javascript production builds
// TODO create gatsby plugin to enable this behaviour on develop (only when people are requesting this feature)
if (stage === `build-javascript` && !(0, _browserslist.hasES6ModuleSupport)(directory)) {
configRules.push(rules.dependencies({
modulesThatUseGatsby
}));
}
switch (stage) {
case `develop`:
{
configRules = configRules.concat([{
oneOf: [rules.cssModules(), rules.css()]
}]);
break;
}
case `build-html`:
case `develop-html`:
// We don't deal with CSS at all when building the HTML.
// The 'null' loader is used to prevent 'module not found' errors.
// On the other hand CSS modules loaders are necessary.
// prettier-ignore
configRules = configRules.concat([{
oneOf: [rules.cssModules(), {
...rules.css(),
use: [loaders.null()]
}]
}]);
break;
case `build-javascript`:
// We don't deal with CSS at all when building JavaScript but we still
// need to process the CSS so offline-plugin knows about the various
// assets referenced in your CSS.
//
// It's also necessary to process CSS Modules so your JS knows the
// classNames to use.
configRules = configRules.concat([{
oneOf: [rules.cssModules(), rules.css()]
}]);
break;
}
// TODO(v5): Remove since this is only useful during Gatsby 4 publishes
// Removes it from the client payload as it's not used there
if ("5" !== `5`) {
configRules.push({
test: /react-server-dom-webpack/,
use: loaders.null()
});
}
return {
rules: configRules
};
}
function getPackageRoot(pkg) {
return path.dirname(require.resolve(`${pkg}/package.json`));
}
function getResolve(stage) {
const {
program
} = store.getState();
const resolve = {
// Use the program's extension list (generated via the
// 'resolvableExtensions' API hook).
extensions: [...program.extensions],
alias: {
gatsby$: directoryPath(path.join(`.cache`, `gatsby-browser-entry.js`)),
// Using directories for module resolution is mandatory because
// relative path imports are used sometimes
// See https://stackoverflow.com/a/49455609/6420957 for more details
"@babel/runtime": getPackageRoot(`@babel/runtime`),
"@reach/router": getPackageRoot(`@gatsbyjs/reach-router`),
"react-lifecycles-compat": directoryPath(`.cache/react-lifecycles-compat.js`),
"react-server-dom-webpack": getPackageRoot(`react-server-dom-webpack`),
"@pmmmwh/react-refresh-webpack-plugin": getPackageRoot(`@pmmmwh/react-refresh-webpack-plugin`),
"socket.io-client": getPackageRoot(`socket.io-client`),
"webpack-hot-middleware": getPackageRoot(`@gatsbyjs/webpack-hot-middleware`),
$virtual: (0, _gatsbyWebpackVirtualModules.getAbsolutePathForVirtualModule)(`$virtual`)
},
plugins: [new CoreJSResolver(), new CacheFolderResolver(path.join(program.directory, `.cache`))]
};
const target = stage === `build-html` || stage === `develop-html` ? `node` : `web`;
if (target === `web`) {
// TODO(v5): Remove since this is only useful during Gatsby 4 publishes
if ("5" !== `5`) {
resolve.alias[`@reach/router`] = path.join(getPackageRoot(`@gatsbyjs/reach-router`), `es`);
}
resolve.alias[`gatsby-core-utils/create-content-digest`] = directoryPath(`.cache/create-content-digest-browser-shim`);
}
if (stage === `build-javascript` && program.profile) {
resolve.alias[`react-dom$`] = `react-dom/profiling`;
resolve.alias[`scheduler/tracing`] = `scheduler/tracing-profiling`;
}
// SSR can have many react versions as some packages use their own version. React works best with 1 version.
// By resolving react,react-dom from gatsby we'll get the site versions of react & react-dom because it's specified as a peerdependency.
//
// we need to put this below our resolve.alias for profiling as webpack picks the first one that matches
// @see https://github.com/gatsbyjs/gatsby/issues/31098
resolve.alias[`react`] = getPackageRoot(`react`);
resolve.alias[`react-dom`] = getPackageRoot(`react-dom`);
return resolve;
}
function getResolveLoader() {
const root = [path.resolve(directory, `node_modules`)];
const userLoaderDirectoryPath = path.resolve(directory, `loaders`);
try {
if (fs.statSync(userLoaderDirectoryPath).isDirectory()) {
root.push(userLoaderDirectoryPath);
}
} catch (err) {
debug(`Error resolving user loaders directory`, err);
}
return {
modules: [...root, path.join(__dirname, `../loaders`), `node_modules`]
};
}
const config = {
name: stage,
// Context is the base directory for resolving the entry option.
context: directory,
entry: getEntry(),
output: getOutput(),
module: getModule(),
plugins: getPlugins(),
devtool: getDevtool(),
// Turn off performance hints as we (for now) don't want to show the normal
// webpack output anywhere.
performance: {
hints: false
},
mode: getMode(),
resolveLoader: getResolveLoader(),
resolve: getResolve(stage)
};
if (stage === `build-html` || stage === `develop-html`) {
config.target = `node14.15`;
} else {
config.target = [`web`, `es5`];
}
const isCssModule = module => module.type === `css/mini-extract`;
if (stage === `develop`) {
config.optimization = {
splitChunks: {
chunks: `all`,
cacheGroups: {
default: false,
defaultVendors: false,
framework: {
chunks: `all`,
name: `framework`,
test: FRAMEWORK_BUNDLES_REGEX,
priority: 40,
// Don't let webpack eliminate this chunk (prevents this chunk from becoming a part of the commons chunk)
enforce: true
},
// Bundle all css & lazy css into one stylesheet to make sure lazy components do not break
// TODO make an exception for css-modules
styles: {
test(module) {
return isCssModule(module);
},
name: `commons`,
priority: 40,
enforce: true
}
}
},
minimize: false
};
}
if (stage === `build-html` || stage === `develop-html`) {
config.optimization = {
// TODO fix our partial hydration manifest
mangleExports: !isPartialHydrationEnabled,
minimize: false
};
if (stage === `build-html`) {
config.optimization.splitChunks = {
chunks: `async`,
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
};
} else {
config.optimization.splitChunks = {
cacheGroups: {
default: false,
defaultVendors: false
}
};
}
}
if (stage === `build-javascript`) {
const componentsCount = store.getState().components.size;
const splitChunks = {
chunks: `all`,
cacheGroups: {
default: false,
defaultVendors: false,
framework: {
chunks: `all`,
name: `framework`,
// Important: If you change something here, also update "gatsby-plugin-preact"
test: module => {
var _module$rawRequest;
// Packages like gatsby-plugin-image might import from "react-dom/server". We don't want to include react-dom-server in the framework bundle.
// A rawRequest might look like these:
// - "react-dom/server"
// - "node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.min.js"
// Use a "/" before "react-dom-server" so that we don't match packages that contain "react-dom-server" in their name
if ((module === null || module === void 0 ? void 0 : module.rawRequest) === `react-dom/server` || module !== null && module !== void 0 && (_module$rawRequest = module.rawRequest) !== null && _module$rawRequest !== void 0 && _module$rawRequest.includes(`/react-dom-server`)) {
return false;
}
return FRAMEWORK_BUNDLES_REGEX.test(module.nameForCondition());
},
priority: 40,
// Don't let webpack eliminate this chunk (prevents this chunk from becoming a part of the commons chunk)
enforce: true
},
// if a module is bigger than 160kb from node_modules we make a separate chunk for it
lib: {
test(module) {
return !isCssModule(module) && module.size() > 160000 && /node_modules[/\\]/.test(module.identifier());
},
name(module) {
const hash = crypto.createHash(`sha1`);
if (!module.libIdent) {
throw new Error(`Encountered unknown module type: ${module.type}. Please open an issue.`);
}
hash.update(module.libIdent({
context: program.directory
}));
return hash.digest(`hex`).substring(0, 8);
},
priority: 30,
minChunks: 1,
reuseExistingChunk: true
},
commons: {
name: `commons`,
// if a chunk is used on all components we put it in commons (we need at least 2 components)
minChunks: Math.max(componentsCount, 2),
priority: 20
},
// If a chunk is used in at least 2 components we create a separate chunk
shared: {
test(module, {
chunkGraph
}) {
for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
if (chunk.canBeInitial()) {
return false;
}
}
return !isCssModule(module);
},
name(module, chunks) {
const hash = crypto.createHash(`sha1`).update(chunks.reduce((acc, chunk) => acc + chunk.name, ``)).digest(`hex`);
return hash;
},
priority: 10,
minChunks: 2,
reuseExistingChunk: true
},
// Bundle all css & lazy css into one stylesheet to make sure lazy components do not break
// TODO make an exception for css-modules
styles: {
test(module) {
return isCssModule(module);
},
name: `styles`,
priority: 40,
enforce: true
}
},
// We load our pages async through async-requires, maxInitialRequests doesn't have an effect on chunks derived from page components.
// By default webpack has set maxAsyncRequests to 6, in some cases this isn't enough an actually makes the bundle size blow up.
// We've set maxAsyncRequests to Infinity to negate this. This could potentionally exceed the 25 initial requests that we set before
// sadly I do not have a better solution.
maxAsyncRequests: Infinity,
maxInitialRequests: 25,
minSize: 20000
};
config.optimization = {
runtimeChunk: {
name: `webpack-runtime`
},
// TODO fix our partial hydration manifest
mangleExports: !isPartialHydrationEnabled,
splitChunks,
minimizer: [
// TODO: maybe this option should be noMinimize?
!program.noUglify && plugins.minifyJs(program.profile ? {
terserOptions: {
keep_classnames: true,
keep_fnames: true
}
} : {}), plugins.minifyCss()].filter(Boolean)
};
}
if (stage === `build-html` || stage === `develop-html`) {
// externalize react, react-dom when develop-html or build-html(when not generating engines)
const shouldMarkPackagesAsExternal = stage === `develop-html` || !(0, _enginesHelpers.shouldGenerateEngines)();
// tracking = build-html (when not generating engines)
const shouldTrackBuiltins = stage === `build-html` && !(0, _enginesHelpers.shouldGenerateEngines)();
// removes node internals from bundle
// https://webpack.js.org/configuration/externals/#externalspresets
config.externalsPresets = {
// use it only when not tracking builtins (tracking builtins provide their own fallbacks)
node: !shouldTrackBuiltins
};
config.externals = [];
if (shouldMarkPackagesAsExternal) {
// Packages we want to externalize to save some build time
// https://github.com/gatsbyjs/gatsby/pull/14208#pullrequestreview-240178728
// const externalList = [`common-tags`, `lodash`, `semver`, /^lodash\//]
// Packages we want to externalize because meant to be user-provided
const userExternalList = [`react`, /^react-dom\//];
const checkItem = (item, request) => {
if (typeof item === `string` && item === request) {
return true;
} else if (item instanceof RegExp && item.test(request)) {
return true;
}
return false;
};
config.externals.push(function ({
context,
getResolve,
request
}, callback) {
// allows us to resolve webpack aliases from our config
// helpful for when react is aliased to preact-compat
// Force commonjs as we're in node land
const resolver = getResolve({
dependencyType: `commonjs`
});
// User modules that do not need to be part of the bundle
if (userExternalList.some(item => checkItem(item, request))) {
// TODO figure out to make preact work with this too
resolver(context, request, (err, newRequest) => {
if (err) {
callback(err);
return;
}
callback(null, newRequest);
});
return;
}
// TODO look into re-enabling, breaks builds right now because of esm
// User modules that do not need to be part of the bundle
// if (externalList.some(item => checkItem(item, request))) {
// resolver(context, request, (err, request) => {
// if (err) {
// callback(err)
// return
// }
// callback(null, `commonjs2 ${request}`)
// })
// return
// }
callback();
});
}
if (shouldTrackBuiltins) {
if (stage === `build-html`) {
const builtinModulesToTrack = [`fs`, `http`, `http2`, `https`, `child_process`];
const builtinsExternalsDictionary = _module.builtinModules.reduce((acc, builtinModule) => {
if (builtinModulesToTrack.includes(builtinModule)) {
const builtinModuleTracked = path.join(program.directory, `.cache`, `ssr-builtin-trackers`, builtinModule);
acc[builtinModule] = `commonjs ${builtinModuleTracked}`;
acc[`node:${builtinModule}`] = `commonjs ${builtinModuleTracked}`;
} else {
acc[builtinModule] = `commonjs ${builtinModule}`;
acc[`node:${builtinModule}`] = `commonjs ${builtinModule}`;
}
return acc;
}, {});
config.externals.unshift(builtinsExternalsDictionary);
}
}
}
if (stage === `develop`) {
config.externals = {
"socket.io-client": `io`
};
}
if (stage === `build-javascript` || stage === `build-html` || stage === `develop` || stage === `develop-html`) {
const cacheLocation = path.join(program.directory, `.cache`, `webpack`, `stage-` + stage);
const pluginsPathsPromises = store.getState().flattenedPlugins.filter(plugin => plugin.nodeAPIs.includes(`onCreateWebpackConfig`)).map(async plugin => {
var _plugin$resolvedCompi;
return (_plugin$resolvedCompi = plugin.resolvedCompiledGatsbyNode) !== null && _plugin$resolvedCompi !== void 0 ? _plugin$resolvedCompi : await (0, _resolveJsFilePath.resolveJSFilepath)({
rootDir: plugin.resolve,
filePath: path.join(plugin.resolve, `gatsby-node`)
});
});
const pluginsPaths = await Promise.all(pluginsPathsPromises);
const cacheConfig = {
type: `filesystem`,
name: stage,
cacheLocation,
buildDependencies: {
config: [__filename, ...pluginsPaths]
}
};
config.cache = cacheConfig;
}
store.dispatch(actions.replaceWebpackConfig(config));
const getConfig = () => store.getState().webpack;
await apiRunnerNode(`onCreateWebpackConfig`, {
getConfig,
// we will converge to build-html later on but for now this was the fastest way to get SSR to work
stage,
rules,
loaders,
plugins,
parentSpan
});
if (fastRefreshPlugin) {
// Fast refresh plugin has `include` option that determines
// wether HMR code gets injected. We need to make sure all custom loaders
// (like .ts or .mdx) that use our babel-loader will be taken into account
// when deciding which modules get fast-refresh HMR addition.
const fastRefreshIncludes = [];
const babelLoaderLoc = require.resolve(`./babel-loader`);
for (const rule of getConfig().module.rules) {
var _use$loader, _use;
if (!rule.use && !rule.loader) {
continue;
}
let use = rule.use;
if (typeof use === `function`) {
use = rule.use({});
}
const ruleLoaders = Array.isArray(use) ? use.map(useEntry => typeof useEntry === `string` ? useEntry : useEntry.loader) : [(_use$loader = (_use = use) === null || _use === void 0 ? void 0 : _use.loader) !== null && _use$loader !== void 0 ? _use$loader : rule.loader];
const hasBabelLoader = ruleLoaders.some(loader => loader === babelLoaderLoc);
if (hasBabelLoader) {
fastRefreshIncludes.push(rule.test);
}
}
// start with default include of fast refresh plugin
const includeRegex = /\.([jt]sx?|flow)$/i;
includeRegex.test = modulePath => {
// drop query param from request (i.e. ?type=component for mdx-loader)
// so loader rule test work well
const queryParamStartIndex = modulePath.indexOf(`?`);
if (queryParamStartIndex !== -1) {
modulePath = modulePath.slice(0, queryParamStartIndex);
}
return fastRefreshIncludes.some(re => re.test(modulePath));
};
fastRefreshPlugin.options.include = includeRegex;
}
return getConfig();
};
//# sourceMappingURL=webpack.config.js.map
;