Files
30-seconds-of-code/node_modules/gatsby/dist/utils/webpack-utils.js
2019-08-20 15:52:05 +02:00

511 lines
13 KiB
JavaScript

"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
const autoprefixer = require(`autoprefixer`);
const flexbugs = require(`postcss-flexbugs-fixes`);
const TerserPlugin = require(`terser-webpack-plugin`);
const MiniCssExtractPlugin = require(`mini-css-extract-plugin`);
const OptimizeCssAssetsPlugin = require(`optimize-css-assets-webpack-plugin`);
const isWsl = require(`is-wsl`);
const GatsbyWebpackStatsExtractor = require(`./gatsby-webpack-stats-extractor`);
const builtinPlugins = require(`./webpack-plugins`);
const eslintConfig = require(`./eslint-config`);
/**
* A factory method that produces an atoms namespace
*/
module.exports = async ({
stage,
program
}) => {
const assetRelativeRoot = `static/`;
const vendorRegex = /(node_modules|bower_components)/;
const supportedBrowsers = program.browserslist;
const PRODUCTION = !stage.includes(`develop`);
const isSSR = stage.includes(`html`);
const makeExternalOnly = original => (options = {}) => {
let rule = original(options);
rule.include = vendorRegex;
return rule;
};
const makeInternalOnly = original => (options = {}) => {
let rule = original(options);
rule.exclude = vendorRegex;
return rule;
};
let ident = 0;
const loaders = {
json: (options = {}) => {
return {
options,
loader: require.resolve(`json-loader`)
};
},
yaml: (options = {}) => {
return {
options,
loader: require.resolve(`yaml-loader`)
};
},
null: (options = {}) => {
return {
options,
loader: require.resolve(`null-loader`)
};
},
raw: (options = {}) => {
return {
options,
loader: require.resolve(`raw-loader`)
};
},
style: (options = {}) => {
return {
options,
loader: require.resolve(`style-loader`)
};
},
miniCssExtract: (options = {}) => {
return {
options,
// use MiniCssExtractPlugin only on production builds
loader: PRODUCTION ? MiniCssExtractPlugin.loader : require.resolve(`style-loader`)
};
},
css: (options = {}) => {
return {
loader: isSSR ? require.resolve(`css-loader/locals`) : require.resolve(`css-loader`),
options: Object.assign({
sourceMap: !PRODUCTION,
camelCase: `dashesOnly`,
// https://github.com/webpack-contrib/css-loader/issues/406
localIdentName: `[name]--[local]--[hash:base64:5]`
}, options)
};
},
postcss: (options = {}) => {
let {
plugins,
overrideBrowserslist = supportedBrowsers
} = options,
postcssOpts = (0, _objectWithoutPropertiesLoose2.default)(options, ["plugins", "overrideBrowserslist"]);
return {
loader: require.resolve(`postcss-loader`),
options: Object.assign({
ident: `postcss-${++ident}`,
sourceMap: !PRODUCTION,
plugins: loader => {
plugins = (typeof plugins === `function` ? plugins(loader) : plugins) || [];
return [flexbugs, autoprefixer({
overrideBrowserslist,
flexbox: `no-2009`
}), ...plugins];
}
}, postcssOpts)
};
},
file: (options = {}) => {
return {
loader: require.resolve(`file-loader`),
options: Object.assign({
name: `${assetRelativeRoot}[name]-[hash].[ext]`
}, options)
};
},
url: (options = {}) => {
return {
loader: require.resolve(`url-loader`),
options: Object.assign({
limit: 10000,
name: `${assetRelativeRoot}[name]-[hash].[ext]`
}, options)
};
},
js: options => {
return {
options: Object.assign({
stage
}, options),
loader: require.resolve(`./babel-loader`)
};
},
dependencies: options => {
return {
options,
loader: require.resolve(`babel-loader`)
};
},
eslint: (schema = ``) => {
const options = eslintConfig(schema);
return {
options,
loader: require.resolve(`eslint-loader`)
};
},
imports: (options = {}) => {
return {
options,
loader: require.resolve(`imports-loader`)
};
},
exports: (options = {}) => {
return {
options,
loader: require.resolve(`exports-loader`)
};
}
/**
* Rules
*/
};
const rules = {};
/**
* JavaScript loader via babel, includes userland code
* and packages that depend on `gatsby`
*/
{
let js = (_ref = {}) => {
let {
modulesThatUseGatsby = []
} = _ref,
options = (0, _objectWithoutPropertiesLoose2.default)(_ref, ["modulesThatUseGatsby"]);
return {
test: /\.(js|mjs|jsx)$/,
include: modulePath => {
// when it's not coming from node_modules we treat it as a source file.
if (!vendorRegex.test(modulePath)) {
return true;
} // If the module uses Gatsby as a dependency
// we want to treat it as src so we can extract queries
return modulesThatUseGatsby.some(module => modulePath.includes(module.path));
},
type: `javascript/auto`,
use: [loaders.js(Object.assign({}, options, {
configFile: true,
compact: true
}))]
};
};
rules.js = js;
}
/**
* Node_modules JavaScript loader via babel
* Excludes core-js & babel-runtime to speedup babel transpilation
* Excludes modules that use Gatsby since the `rules.js` already transpiles those
*/
{
let dependencies = ({
modulesThatUseGatsby = []
} = {}) => {
const jsOptions = {
babelrc: false,
configFile: false,
compact: false,
presets: [require.resolve(`babel-preset-gatsby/dependencies`)],
// If an error happens in a package, it's possible to be
// because it was compiled. Thus, we don't want the browser
// debugger to show the original code. Instead, the code
// being evaluated would be much more helpful.
sourceMaps: false,
cacheIdentifier: `${stage}---gatsby-dependencies@${require(`babel-preset-gatsby/package.json`).version}`
};
return {
test: /\.(js|mjs)$/,
exclude: modulePath => {
if (vendorRegex.test(modulePath)) {
// If dep uses Gatsby, exclude
if (modulesThatUseGatsby.some(module => modulePath.includes(module.path))) {
return true;
} // If dep is babel-runtime or core-js, exclude
if (/@babel(?:\/|\\{1,2})runtime|core-js/.test(modulePath)) {
return true;
} // If dep is in node_modules and none of the above, include
return false;
} // If dep is user land code, exclude
return true;
},
type: `javascript/auto`,
use: [loaders.dependencies(jsOptions)]
};
};
rules.dependencies = dependencies;
}
{
let eslint = schema => {
return {
enforce: `pre`,
test: /\.jsx?$/,
exclude: vendorRegex,
use: [loaders.eslint(schema)]
};
};
rules.eslint = eslint;
}
rules.yaml = () => {
return {
test: /\.ya?ml/,
use: [loaders.json(), loaders.yaml()]
};
};
/**
* Font loader
*/
rules.fonts = () => {
return {
use: [loaders.url()],
test: /\.(eot|otf|ttf|woff(2)?)(\?.*)?$/
};
};
/**
* Loads image assets, inlines images via a data URI if they are below
* the size threshold
*/
rules.images = () => {
return {
use: [loaders.url()],
test: /\.(ico|svg|jpg|jpeg|png|gif|webp)(\?.*)?$/
};
};
/**
* Loads audio and video and inlines them via a data URI if they are below
* the size threshold
*/
rules.media = () => {
return {
use: [loaders.url()],
test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/
};
};
/**
* Loads assets without inlining
*/
rules.miscAssets = () => {
return {
use: [loaders.file()],
test: /\.pdf$/
};
};
/**
* CSS style loader.
*/
{
const css = (_ref2 = {}) => {
let {
browsers
} = _ref2,
options = (0, _objectWithoutPropertiesLoose2.default)(_ref2, ["browsers"]);
const use = [loaders.css(Object.assign({}, options, {
importLoaders: 1
})), loaders.postcss({
browsers
})];
if (!isSSR) use.unshift(loaders.miniCssExtract({
hmr: !options.modules
}));
return {
use,
test: /\.css$/
};
};
/**
* CSS style loader, _excludes_ node_modules.
*/
css.internal = makeInternalOnly(css);
css.external = makeExternalOnly(css);
const cssModules = options => {
const rule = css(Object.assign({}, options, {
modules: true
}));
delete rule.exclude;
rule.test = /\.module\.css$/;
return rule;
};
rules.css = css;
rules.cssModules = cssModules;
}
/**
* PostCSS loader.
*/
{
const postcss = options => {
return {
test: /\.css$/,
use: [loaders.css({
importLoaders: 1
}), loaders.postcss(options)]
};
};
/**
* PostCSS loader, _excludes_ node_modules.
*/
postcss.internal = makeInternalOnly(postcss);
postcss.external = makeExternalOnly(postcss);
rules.postcss = postcss;
}
/**
* Plugins
*/
const plugins = Object.assign({}, builtinPlugins);
/**
* Minify JavaScript code without regard for IE8. Attempts
* to parallelize the work to save time. Generally only add in Production
*/
plugins.minifyJs = (_ref3 = {}) => {
let {
terserOptions
} = _ref3,
options = (0, _objectWithoutPropertiesLoose2.default)(_ref3, ["terserOptions"]);
return new TerserPlugin(Object.assign({
cache: true,
// We can't use parallel in WSL because of https://github.com/gatsbyjs/gatsby/issues/6540
// This issue was fixed in https://github.com/gatsbyjs/gatsby/pull/12636
parallel: !isWsl,
exclude: /\.min\.js/,
sourceMap: true,
terserOptions: Object.assign({
ie8: false,
mangle: {
safari10: true
},
parse: {
ecma: 8
},
compress: {
ecma: 5
},
output: {
ecma: 5
}
}, terserOptions)
}, options));
};
plugins.minifyCss = (options = {
cssProcessorPluginOptions: {
preset: [`default`, {
svgo: {
full: true,
plugins: [{
// potentially destructive plugins removed - see https://github.com/gatsbyjs/gatsby/issues/15629
// convertShapeToPath: true,
// removeViewBox: true,
removeUselessDefs: true,
addAttributesToSVGElement: true,
addClassesToSVGElement: true,
cleanupAttrs: true,
cleanupEnableBackground: true,
cleanupIDs: true,
cleanupListOfValues: true,
cleanupNumericValues: true,
collapseGroups: true,
convertColors: true,
convertPathData: true,
convertStyleToAttrs: true,
convertTransform: true,
inlineStyles: true,
mergePaths: true,
minifyStyles: true,
moveElemsAttrsToGroup: true,
moveGroupAttrsToElems: true,
prefixIds: true,
removeAttributesBySelector: true,
removeAttrs: true,
removeComments: true,
removeDesc: true,
removeDimensions: true,
removeDoctype: true,
removeEditorsNSData: true,
removeElementsByAttr: true,
removeEmptyAttrs: true,
removeEmptyContainers: true,
removeEmptyText: true,
removeHiddenElems: true,
removeMetadata: true,
removeNonInheritableGroupAttrs: true,
removeOffCanvasPaths: true,
removeRasterImages: true,
removeScriptElement: true,
removeStyleElement: true,
removeTitle: true,
removeUnknownsAndDefaults: true,
removeUnusedNS: true,
removeUselessStrokeAndFill: true,
removeXMLNS: true,
removeXMLProcInst: true,
reusePaths: true,
sortAttrs: true
}]
}
}]
}
}) => new OptimizeCssAssetsPlugin(options);
/**
* Extracts css requires into a single file;
* includes some reasonable defaults
*/
plugins.extractText = options => new MiniCssExtractPlugin(Object.assign({
filename: `[name].[contenthash].css`,
chunkFilename: `[name].[contenthash].css`
}, options));
plugins.moment = () => plugins.ignore(/^\.\/locale$/, /moment$/);
plugins.extractStats = options => new GatsbyWebpackStatsExtractor(options);
return {
loaders,
rules: rules,
plugins: plugins
};
};
//# sourceMappingURL=webpack-utils.js.map