webpack.js 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233
  1. /*!
  2. * @nuxt/webpack v2.15.8 (c) 2016-2021
  3. * Released under the MIT License
  4. * Repository: https://github.com/nuxt/nuxt.js
  5. * Website: https://nuxtjs.org
  6. */
  7. 'use strict';
  8. Object.defineProperty(exports, '__esModule', { value: true });
  9. const path = require('path');
  10. const pify = require('pify');
  11. const webpack = require('webpack');
  12. const Glob = require('glob');
  13. const webpackDevMiddleware = require('webpack-dev-middleware');
  14. const webpackHotMiddleware = require('webpack-hot-middleware');
  15. const consola = require('consola');
  16. const utils = require('@nuxt/utils');
  17. const MFS = require('memory-fs');
  18. const querystring = require('querystring');
  19. const HtmlWebpackPlugin = require('html-webpack-plugin');
  20. const BundleAnalyzer = require('webpack-bundle-analyzer');
  21. const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
  22. const FriendlyErrorsWebpackPlugin = require('@nuxt/friendly-errors-webpack-plugin');
  23. const EventEmitter = require('events');
  24. const hash = require('hash-sum');
  25. const lodash = require('lodash');
  26. const TimeFixPlugin = require('time-fix-plugin');
  27. const VueLoader = require('vue-loader');
  28. const ExtractCssChunksPlugin = require('extract-css-chunks-webpack-plugin');
  29. const PnpWebpackPlugin = require('pnp-webpack-plugin');
  30. const HardSourcePlugin = require('hard-source-webpack-plugin');
  31. const TerserWebpackPlugin = require('terser-webpack-plugin');
  32. const WebpackBar = require('webpackbar');
  33. const env = require('std-env');
  34. const semver = require('semver');
  35. const ufo = require('ufo');
  36. const threadLoader = require('thread-loader');
  37. const fs = require('fs');
  38. const createResolver = require('postcss-import-resolver');
  39. const nodeExternals = require('webpack-node-externals');
  40. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  41. function _interopNamespace(e) {
  42. if (e && e.__esModule) return e;
  43. var n = Object.create(null);
  44. if (e) {
  45. Object.keys(e).forEach(function (k) {
  46. if (k !== 'default') {
  47. var d = Object.getOwnPropertyDescriptor(e, k);
  48. Object.defineProperty(n, k, d.get ? d : {
  49. enumerable: true,
  50. get: function () {
  51. return e[k];
  52. }
  53. });
  54. }
  55. });
  56. }
  57. n['default'] = e;
  58. return Object.freeze(n);
  59. }
  60. const path__default = /*#__PURE__*/_interopDefaultLegacy(path);
  61. const pify__default = /*#__PURE__*/_interopDefaultLegacy(pify);
  62. const webpack__default = /*#__PURE__*/_interopDefaultLegacy(webpack);
  63. const Glob__default = /*#__PURE__*/_interopDefaultLegacy(Glob);
  64. const webpackDevMiddleware__default = /*#__PURE__*/_interopDefaultLegacy(webpackDevMiddleware);
  65. const webpackHotMiddleware__default = /*#__PURE__*/_interopDefaultLegacy(webpackHotMiddleware);
  66. const consola__default = /*#__PURE__*/_interopDefaultLegacy(consola);
  67. const MFS__default = /*#__PURE__*/_interopDefaultLegacy(MFS);
  68. const querystring__default = /*#__PURE__*/_interopDefaultLegacy(querystring);
  69. const HtmlWebpackPlugin__default = /*#__PURE__*/_interopDefaultLegacy(HtmlWebpackPlugin);
  70. const BundleAnalyzer__default = /*#__PURE__*/_interopDefaultLegacy(BundleAnalyzer);
  71. const OptimizeCSSAssetsPlugin__default = /*#__PURE__*/_interopDefaultLegacy(OptimizeCSSAssetsPlugin);
  72. const FriendlyErrorsWebpackPlugin__default = /*#__PURE__*/_interopDefaultLegacy(FriendlyErrorsWebpackPlugin);
  73. const EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
  74. const hash__default = /*#__PURE__*/_interopDefaultLegacy(hash);
  75. const TimeFixPlugin__default = /*#__PURE__*/_interopDefaultLegacy(TimeFixPlugin);
  76. const VueLoader__default = /*#__PURE__*/_interopDefaultLegacy(VueLoader);
  77. const ExtractCssChunksPlugin__default = /*#__PURE__*/_interopDefaultLegacy(ExtractCssChunksPlugin);
  78. const PnpWebpackPlugin__namespace = /*#__PURE__*/_interopNamespace(PnpWebpackPlugin);
  79. const HardSourcePlugin__default = /*#__PURE__*/_interopDefaultLegacy(HardSourcePlugin);
  80. const TerserWebpackPlugin__default = /*#__PURE__*/_interopDefaultLegacy(TerserWebpackPlugin);
  81. const WebpackBar__default = /*#__PURE__*/_interopDefaultLegacy(WebpackBar);
  82. const env__default = /*#__PURE__*/_interopDefaultLegacy(env);
  83. const semver__default = /*#__PURE__*/_interopDefaultLegacy(semver);
  84. const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
  85. const createResolver__default = /*#__PURE__*/_interopDefaultLegacy(createResolver);
  86. const nodeExternals__default = /*#__PURE__*/_interopDefaultLegacy(nodeExternals);
  87. class AsyncMFS extends MFS__default['default'] {}
  88. const syncRegex = /Sync$/;
  89. const propsToPromisify = Object.getOwnPropertyNames(MFS__default['default'].prototype).filter(n => syncRegex.test(n));
  90. for (const prop of propsToPromisify) {
  91. const asyncProp = prop.replace(syncRegex, '');
  92. const origAsync = AsyncMFS.prototype[asyncProp];
  93. AsyncMFS.prototype[asyncProp] = function (...args) {
  94. // Callback support for webpack
  95. if (origAsync && args.length && typeof args[args.length - 1] === 'function') {
  96. return origAsync.call(this, ...args)
  97. }
  98. try {
  99. return Promise.resolve(MFS__default['default'].prototype[prop].call(this, ...args))
  100. } catch (error) {
  101. return Promise.reject(error)
  102. }
  103. };
  104. }
  105. class CorsPlugin {
  106. constructor ({ crossorigin }) {
  107. this.crossorigin = crossorigin;
  108. }
  109. apply (compiler) {
  110. const ID = 'vue-cors-plugin';
  111. compiler.hooks.compilation.tap(ID, (compilation) => {
  112. HtmlWebpackPlugin__default['default'].getHooks(compilation).alterAssetTagGroups.tap(ID, (data) => {
  113. if (!this.crossorigin) {
  114. return
  115. }
  116. [...data.headTags, ...data.bodyTags].forEach((tag) => {
  117. if (['script', 'link'].includes(tag.tagName)) {
  118. if (tag.attributes) {
  119. tag.attributes.crossorigin = this.crossorigin;
  120. }
  121. }
  122. });
  123. });
  124. });
  125. }
  126. }
  127. /*
  128. * This file is based on @vue/cli-service (MIT) ModernModePlugin
  129. * https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/webpack/ModernModePlugin.js
  130. */
  131. const legacyTemplateTags = {};
  132. const legacyTemplateWatcher = new EventEmitter__default['default']();
  133. class ModernModePlugin {
  134. constructor ({ targetDir, isModernBuild, noUnsafeInline }) {
  135. this.targetDir = targetDir;
  136. this.isModernBuild = isModernBuild;
  137. this.noUnsafeInline = noUnsafeInline;
  138. }
  139. apply (compiler) {
  140. if (!this.isModernBuild) {
  141. this.applyLegacy(compiler);
  142. } else {
  143. this.applyModern(compiler);
  144. }
  145. }
  146. getLegacyTemplateTags (name) {
  147. return new Promise((resolve) => {
  148. const tags = legacyTemplateTags[name];
  149. if (tags) {
  150. return resolve(tags)
  151. }
  152. return legacyTemplateWatcher.once(name, () => {
  153. const tags = legacyTemplateTags[name];
  154. return tags && resolve(tags)
  155. })
  156. })
  157. }
  158. applyLegacy (compiler) {
  159. const ID = 'nuxt-legacy-bundle';
  160. compiler.hooks.compilation.tap(ID, (compilation) => {
  161. HtmlWebpackPlugin__default['default'].getHooks(compilation).alterAssetTagGroups.tap(ID, (data) => {
  162. HtmlWebpackPlugin__default['default'].getHooks(compilation).afterEmit.tap(ID, ({ outputName }) => {
  163. // get stats, write to disk
  164. legacyTemplateTags[data.plugin.options.filename] = data.bodyTags;
  165. legacyTemplateWatcher.emit(outputName);
  166. });
  167. return data
  168. });
  169. });
  170. }
  171. applyModern (compiler) {
  172. const ID = 'nuxt-modern-bundle';
  173. compiler.hooks.compilation.tap(ID, (compilation) => {
  174. HtmlWebpackPlugin__default['default'].getHooks(compilation).alterAssetTagGroups.tapPromise(ID, async (data) => {
  175. // use <script type="module"> for modern assets
  176. data.bodyTags.forEach((tag) => {
  177. if (tag.tagName === 'script' && tag.attributes) {
  178. tag.attributes.type = 'module';
  179. }
  180. });
  181. // use <link rel="modulepreload"> instead of <link rel="preload">
  182. // for modern assets
  183. data.headTags.forEach((tag) => {
  184. if (tag.tagName === 'link' &&
  185. tag.attributes.rel === 'preload' &&
  186. tag.attributes.as === 'script') {
  187. tag.attributes.rel = 'modulepreload';
  188. }
  189. });
  190. // inject links for legacy assets as <script nomodule>
  191. const fileName = data.plugin.options.filename;
  192. const legacyScriptTags = (await this.getLegacyTemplateTags(fileName))
  193. .filter(a => a.tagName === 'script' && a.attributes);
  194. for (const a of legacyScriptTags) {
  195. a.attributes.nomodule = true;
  196. data.bodyTags.push(a);
  197. }
  198. if (this.noUnsafeInline) {
  199. // inject the fix as an external script
  200. const safariFixFilename = 'safari-nomodule-fix.js';
  201. const safariFixPath = legacyScriptTags[0].attributes.src
  202. .split('/')
  203. .slice(0, -1)
  204. .concat([safariFixFilename])
  205. .join('/');
  206. compilation.assets[safariFixFilename] = {
  207. source: () => Buffer.from(utils.safariNoModuleFix),
  208. size: () => Buffer.byteLength(utils.safariNoModuleFix)
  209. };
  210. data.bodyTags.push({
  211. tagName: 'script',
  212. closeTag: true,
  213. attributes: {
  214. src: safariFixPath
  215. }
  216. });
  217. } else {
  218. // inject Safari 10 nomodule fix
  219. data.bodyTags.push({
  220. tagName: 'script',
  221. closeTag: true,
  222. innerHTML: utils.safariNoModuleFix
  223. });
  224. }
  225. delete legacyTemplateTags[fileName];
  226. return data
  227. });
  228. });
  229. }
  230. }
  231. /**
  232. * This file is based on Vue.js (MIT) webpack plugins
  233. * https://github.com/vuejs/vue/blob/dev/src/server/webpack-plugin/util.js
  234. */
  235. const validate = (compiler) => {
  236. if (compiler.options.target !== 'node') {
  237. consola__default['default'].warn('webpack config `target` should be "node".');
  238. }
  239. if (compiler.options.output && compiler.options.output.libraryTarget !== 'commonjs2') {
  240. consola__default['default'].warn('webpack config `output.libraryTarget` should be "commonjs2".');
  241. }
  242. if (!compiler.options.externals) {
  243. consola__default['default'].info(
  244. 'It is recommended to externalize dependencies in the server build for ' +
  245. 'better build performance.'
  246. );
  247. }
  248. };
  249. const isJSRegExp = /\.js(\?[^.]+)?$/;
  250. const isJS = file => isJSRegExp.test(file);
  251. const extractQueryPartJS = file => isJSRegExp.exec(file)[1];
  252. const isCSS = file => /\.css(\?[^.]+)?$/.test(file);
  253. /**
  254. * This file is based on Vue.js (MIT) webpack plugins
  255. * https://github.com/vuejs/vue/blob/dev/src/server/webpack-plugin/client.js
  256. */
  257. class VueSSRClientPlugin {
  258. constructor (options = {}) {
  259. this.options = Object.assign({
  260. filename: null
  261. }, options);
  262. }
  263. apply (compiler) {
  264. compiler.hooks.emit.tapAsync('vue-client-plugin', (compilation, cb) => {
  265. const stats = compilation.getStats().toJson();
  266. const allFiles = lodash.uniq(stats.assets
  267. .map(a => a.name));
  268. const initialFiles = lodash.uniq(Object.keys(stats.entrypoints)
  269. .map(name => stats.entrypoints[name].assets)
  270. .reduce((assets, all) => all.concat(assets), [])
  271. .filter(file => isJS(file) || isCSS(file)));
  272. const asyncFiles = allFiles
  273. .filter(file => isJS(file) || isCSS(file))
  274. .filter(file => !initialFiles.includes(file));
  275. const assetsMapping = {};
  276. stats.assets
  277. .filter(({ name }) => isJS(name))
  278. .forEach(({ name, chunkNames }) => {
  279. const componentHash = hash__default['default'](chunkNames.join('|'));
  280. if (!assetsMapping[componentHash]) {
  281. assetsMapping[componentHash] = [];
  282. }
  283. assetsMapping[componentHash].push(name);
  284. });
  285. const manifest = {
  286. publicPath: stats.publicPath,
  287. all: allFiles,
  288. initial: initialFiles,
  289. async: asyncFiles,
  290. modules: { /* [identifier: string]: Array<index: number> */ },
  291. assetsMapping
  292. };
  293. const { entrypoints, namedChunkGroups } = stats;
  294. const assetModules = stats.modules.filter(m => m.assets.length);
  295. const fileToIndex = file => manifest.all.indexOf(file);
  296. stats.modules.forEach((m) => {
  297. // Ignore modules duplicated in multiple chunks
  298. if (m.chunks.length === 1) {
  299. const [cid] = m.chunks;
  300. const chunk = stats.chunks.find(c => c.id === cid);
  301. if (!chunk || !chunk.files) {
  302. return
  303. }
  304. const id = m.identifier.replace(/\s\w+$/, ''); // remove appended hash
  305. const filesSet = new Set(chunk.files.map(fileToIndex));
  306. for (const chunkName of chunk.names) {
  307. if (!entrypoints[chunkName]) {
  308. const chunkGroup = namedChunkGroups[chunkName];
  309. if (chunkGroup) {
  310. for (const asset of chunkGroup.assets) {
  311. filesSet.add(fileToIndex(asset));
  312. }
  313. }
  314. }
  315. }
  316. const files = Array.from(filesSet);
  317. manifest.modules[hash__default['default'](id)] = files;
  318. // In production mode, modules may be concatenated by scope hoisting
  319. // Include ConcatenatedModule for not losing module-component mapping
  320. if (Array.isArray(m.modules)) {
  321. for (const concatenatedModule of m.modules) {
  322. const id = hash__default['default'](concatenatedModule.identifier.replace(/\s\w+$/, ''));
  323. if (!manifest.modules[id]) {
  324. manifest.modules[id] = files;
  325. }
  326. }
  327. }
  328. // Find all asset modules associated with the same chunk
  329. assetModules.forEach((m) => {
  330. if (m.chunks.includes(cid)) {
  331. files.push.apply(files, m.assets.map(fileToIndex));
  332. }
  333. });
  334. }
  335. });
  336. const src = JSON.stringify(manifest, null, 2);
  337. compilation.assets[this.options.filename] = {
  338. source: () => src,
  339. size: () => src.length
  340. };
  341. cb();
  342. });
  343. }
  344. }
  345. // https://github.com/webpack-contrib/thread-loader
  346. // https://github.com/webpack-contrib/cache-loader
  347. class PerfLoader {
  348. constructor (name, buildContext, { resolveModule }) {
  349. this.name = name;
  350. this.buildContext = buildContext;
  351. this.workerPools = PerfLoader.defaultPools({ dev: buildContext.options.dev });
  352. this.resolveModule = resolveModule;
  353. return new Proxy(this, {
  354. get (target, name) {
  355. return target[name] ? target[name] : target.use.bind(target, name)
  356. }
  357. })
  358. }
  359. static defaultPools ({ dev }) {
  360. const poolTimeout = dev ? Infinity : 2000;
  361. return {
  362. js: { name: 'js', poolTimeout },
  363. css: { name: 'css', poolTimeout }
  364. }
  365. }
  366. static warmupAll ({ dev, resolveModule }) {
  367. const pools = PerfLoader.defaultPools({ dev });
  368. PerfLoader.warmup(pools.js, [
  369. resolveModule('babel-loader'),
  370. resolveModule('@babel/preset-env')
  371. ]);
  372. PerfLoader.warmup(pools.css, [resolveModule('css-loader')]);
  373. }
  374. static warmup (...args) {
  375. threadLoader.warmup(...args);
  376. }
  377. use (poolName) {
  378. const loaders = [];
  379. if (this.buildContext.buildOptions.cache) {
  380. loaders.push({
  381. loader: this.resolveModule('cache-loader'),
  382. options: {
  383. cacheDirectory: path__default['default'].resolve(`node_modules/.cache/cache-loader/${this.name}`)
  384. }
  385. });
  386. }
  387. if (this.buildContext.buildOptions.parallel) {
  388. const pool = this.workerPools[poolName];
  389. if (pool) {
  390. loaders.push({
  391. loader: this.resolveModule('thread-loader'),
  392. options: pool
  393. });
  394. }
  395. }
  396. return loaders
  397. }
  398. }
  399. const orderPresets$1 = {
  400. cssnanoLast (names) {
  401. const nanoIndex = names.indexOf('cssnano');
  402. if (nanoIndex !== names.length - 1) {
  403. names.push(names.splice(nanoIndex, 1)[0]);
  404. }
  405. return names
  406. },
  407. presetEnvLast (names) {
  408. const nanoIndex = names.indexOf('postcss-preset-env');
  409. if (nanoIndex !== names.length - 1) {
  410. names.push(names.splice(nanoIndex, 1)[0]);
  411. }
  412. return names
  413. },
  414. presetEnvAndCssnanoLast (names) {
  415. return orderPresets$1.cssnanoLast(orderPresets$1.presetEnvLast(names))
  416. }
  417. };
  418. function postcssConfigFileWarning$1 () {
  419. if (postcssConfigFileWarning$1.executed) {
  420. return
  421. }
  422. consola__default['default'].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.');
  423. postcssConfigFileWarning$1.executed = true;
  424. }
  425. class PostcssConfig$1 {
  426. constructor (buildContext) {
  427. this.buildContext = buildContext;
  428. }
  429. get postcssOptions () {
  430. return this.buildContext.buildOptions.postcss
  431. }
  432. get postcssImportAlias () {
  433. const alias = { ...this.buildContext.options.alias };
  434. for (const key in alias) {
  435. if (key.startsWith('~')) {
  436. continue
  437. }
  438. const newKey = '~' + key;
  439. if (!alias[newKey]) {
  440. alias[newKey] = alias[key];
  441. }
  442. }
  443. return alias
  444. }
  445. get defaultConfig () {
  446. const { dev, srcDir, rootDir, modulesDir } = this.buildContext.options;
  447. return {
  448. sourceMap: this.buildContext.buildOptions.cssSourceMap,
  449. plugins: {
  450. // https://github.com/postcss/postcss-import
  451. 'postcss-import': {
  452. resolve: createResolver__default['default']({
  453. alias: this.postcssImportAlias,
  454. modules: [srcDir, rootDir, ...modulesDir]
  455. })
  456. },
  457. // https://github.com/postcss/postcss-url
  458. 'postcss-url': {},
  459. // https://github.com/csstools/postcss-preset-env
  460. 'postcss-preset-env': this.preset || {},
  461. cssnano: dev
  462. ? false
  463. : {
  464. preset: ['default', {
  465. // Keep quotes in font values to prevent from HEX conversion
  466. // https://github.com/nuxt/nuxt.js/issues/6306
  467. minifyFontValues: { removeQuotes: false }
  468. }]
  469. }
  470. },
  471. // Array, String or Function
  472. order: 'presetEnvAndCssnanoLast'
  473. }
  474. }
  475. searchConfigFile () {
  476. // Search for postCSS config file and use it if exists
  477. // https://github.com/michael-ciniawsky/postcss-load-config
  478. // TODO: Remove in Nuxt 3
  479. const { srcDir, rootDir } = this.buildContext.options;
  480. for (const dir of [srcDir, rootDir]) {
  481. for (const file of [
  482. 'postcss.config.js',
  483. '.postcssrc.js',
  484. '.postcssrc',
  485. '.postcssrc.json',
  486. '.postcssrc.yaml'
  487. ]) {
  488. const configFile = path__default['default'].resolve(dir, file);
  489. if (fs__default['default'].existsSync(configFile)) {
  490. postcssConfigFileWarning$1();
  491. return configFile
  492. }
  493. }
  494. }
  495. }
  496. configFromFile () {
  497. const loaderConfig = (this.postcssOptions && this.postcssOptions.config) || {};
  498. loaderConfig.path = loaderConfig.path || this.searchConfigFile();
  499. if (loaderConfig.path) {
  500. return {
  501. sourceMap: this.buildContext.buildOptions.cssSourceMap,
  502. config: loaderConfig
  503. }
  504. }
  505. }
  506. normalize (config) {
  507. // TODO: Remove in Nuxt 3
  508. if (Array.isArray(config)) {
  509. consola__default['default'].warn('Using an Array as `build.postcss` will be deprecated in Nuxt 3. Please switch to the object' +
  510. ' declaration');
  511. config = { plugins: config };
  512. }
  513. return config
  514. }
  515. sortPlugins ({ plugins, order }) {
  516. const names = Object.keys(plugins);
  517. if (typeof order === 'string') {
  518. order = orderPresets$1[order];
  519. }
  520. return typeof order === 'function' ? order(names, orderPresets$1) : (order || names)
  521. }
  522. loadPlugins (config) {
  523. const { plugins } = config;
  524. if (utils.isPureObject(plugins)) {
  525. // Map postcss plugins into instances on object mode once
  526. config.plugins = this.sortPlugins(config)
  527. .map((p) => {
  528. const plugin = this.buildContext.nuxt.resolver.requireModule(p, { paths: [__dirname] });
  529. const opts = plugins[p];
  530. if (opts === false) {
  531. return false // Disabled
  532. }
  533. return plugin(opts)
  534. })
  535. .filter(Boolean);
  536. }
  537. }
  538. config () {
  539. /* istanbul ignore if */
  540. if (!this.postcssOptions) {
  541. return false
  542. }
  543. let config = this.configFromFile();
  544. if (config) {
  545. return config
  546. }
  547. config = this.normalize(lodash.cloneDeep(this.postcssOptions));
  548. // Apply default plugins
  549. if (utils.isPureObject(config)) {
  550. if (config.preset) {
  551. this.preset = config.preset;
  552. delete config.preset;
  553. }
  554. if (Array.isArray(config.plugins)) {
  555. lodash.defaults(config, this.defaultConfig);
  556. } else {
  557. // Keep the order of default plugins
  558. config = lodash.merge({}, this.defaultConfig, config);
  559. this.loadPlugins(config);
  560. }
  561. return config
  562. }
  563. }
  564. }
  565. const orderPresets = {
  566. cssnanoLast (names) {
  567. const nanoIndex = names.indexOf('cssnano');
  568. if (nanoIndex !== names.length - 1) {
  569. names.push(names.splice(nanoIndex, 1)[0]);
  570. }
  571. return names
  572. },
  573. presetEnvLast (names) {
  574. const nanoIndex = names.indexOf('postcss-preset-env');
  575. if (nanoIndex !== names.length - 1) {
  576. names.push(names.splice(nanoIndex, 1)[0]);
  577. }
  578. return names
  579. },
  580. presetEnvAndCssnanoLast (names) {
  581. return orderPresets.cssnanoLast(orderPresets.presetEnvLast(names))
  582. }
  583. };
  584. function postcssConfigFileWarning () {
  585. if (postcssConfigFileWarning.executed) {
  586. return
  587. }
  588. consola__default['default'].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.');
  589. postcssConfigFileWarning.executed = true;
  590. }
  591. class PostcssConfig {
  592. constructor (buildContext) {
  593. this.buildContext = buildContext;
  594. }
  595. get cssSourceMap () {
  596. return this.buildContext.buildOptions.cssSourceMap
  597. }
  598. get postcssOptions () {
  599. return this.buildContext.buildOptions.postcss
  600. }
  601. get postcssImportAlias () {
  602. const alias = { ...this.buildContext.options.alias };
  603. for (const key in alias) {
  604. if (key.startsWith('~')) {
  605. continue
  606. }
  607. const newKey = '~' + key;
  608. if (!alias[newKey]) {
  609. alias[newKey] = alias[key];
  610. }
  611. }
  612. return alias
  613. }
  614. get defaultPostcssOptions () {
  615. const { dev, srcDir, rootDir, modulesDir } = this.buildContext.options;
  616. return {
  617. plugins: {
  618. // https://github.com/postcss/postcss-import
  619. 'postcss-import': {
  620. resolve: createResolver__default['default']({
  621. alias: this.postcssImportAlias,
  622. modules: [srcDir, rootDir, ...modulesDir]
  623. })
  624. },
  625. // https://github.com/postcss/postcss-url
  626. 'postcss-url': {},
  627. // https://github.com/csstools/postcss-preset-env
  628. // TODO: enable when https://github.com/csstools/postcss-preset-env/issues/191 gets closed
  629. // 'postcss-preset-env': this.preset || {},
  630. cssnano: dev
  631. ? false
  632. : {
  633. preset: ['default', {
  634. // Keep quotes in font values to prevent from HEX conversion
  635. // https://github.com/nuxt/nuxt.js/issues/6306
  636. minifyFontValues: { removeQuotes: false }
  637. }]
  638. }
  639. },
  640. // Array, String or Function
  641. order: 'presetEnvAndCssnanoLast'
  642. }
  643. }
  644. searchConfigFile () {
  645. // Search for postCSS config file and use it if exists
  646. // https://github.com/michael-ciniawsky/postcss-load-config
  647. // TODO: Remove in Nuxt 3
  648. const { srcDir, rootDir } = this.buildContext.options;
  649. for (const dir of [srcDir, rootDir]) {
  650. for (const file of [
  651. 'postcss.config.js',
  652. '.postcssrc.js',
  653. '.postcssrc',
  654. '.postcssrc.json',
  655. '.postcssrc.yaml'
  656. ]) {
  657. const configFile = path__default['default'].resolve(dir, file);
  658. if (fs__default['default'].existsSync(configFile)) {
  659. postcssConfigFileWarning();
  660. return configFile
  661. }
  662. }
  663. }
  664. }
  665. configFromFile () {
  666. const loaderConfig = (this.postcssOptions && this.postcssOptions.config) || {};
  667. loaderConfig.path = loaderConfig.path || this.searchConfigFile();
  668. if (loaderConfig.path) {
  669. return {
  670. config: loaderConfig
  671. }
  672. }
  673. }
  674. normalize (postcssOptions) {
  675. // TODO: Remove in Nuxt 3
  676. if (Array.isArray(postcssOptions)) {
  677. consola__default['default'].warn('Using an Array as `build.postcss` will be deprecated in Nuxt 3. Please switch to the object' +
  678. ' declaration');
  679. postcssOptions = { plugins: postcssOptions };
  680. }
  681. return postcssOptions
  682. }
  683. sortPlugins ({ plugins, order }) {
  684. const names = Object.keys(plugins);
  685. if (typeof order === 'string') {
  686. order = orderPresets[order];
  687. }
  688. return typeof order === 'function' ? order(names, orderPresets) : (order || names)
  689. }
  690. loadPlugins (postcssOptions) {
  691. const { plugins } = postcssOptions;
  692. if (utils.isPureObject(plugins)) {
  693. // Map postcss plugins into instances on object mode once
  694. postcssOptions.plugins = this.sortPlugins(postcssOptions)
  695. .map((p) => {
  696. const plugin = this.buildContext.nuxt.resolver.requireModule(p, { paths: [__dirname] });
  697. const opts = plugins[p];
  698. if (opts === false) {
  699. return false // Disabled
  700. }
  701. return plugin(opts)
  702. })
  703. .filter(Boolean);
  704. }
  705. }
  706. config () {
  707. /* istanbul ignore if */
  708. if (!this.postcssOptions) {
  709. return false
  710. }
  711. let postcssOptions = this.configFromFile();
  712. if (postcssOptions) {
  713. return {
  714. postcssOptions,
  715. sourceMap: this.cssSourceMap
  716. }
  717. }
  718. postcssOptions = this.normalize(lodash.cloneDeep(this.postcssOptions));
  719. // Apply default plugins
  720. if (utils.isPureObject(postcssOptions)) {
  721. if (postcssOptions.preset) {
  722. this.preset = postcssOptions.preset;
  723. delete postcssOptions.preset;
  724. }
  725. if (Array.isArray(postcssOptions.plugins)) {
  726. lodash.defaults(postcssOptions, this.defaultPostcssOptions);
  727. } else {
  728. // Keep the order of default plugins
  729. postcssOptions = lodash.merge({}, this.defaultPostcssOptions, postcssOptions);
  730. this.loadPlugins(postcssOptions);
  731. }
  732. const { execute } = postcssOptions;
  733. delete postcssOptions.execute;
  734. delete postcssOptions.order;
  735. return {
  736. execute,
  737. postcssOptions,
  738. sourceMap: this.cssSourceMap
  739. }
  740. }
  741. }
  742. }
  743. class StyleLoader {
  744. constructor (buildContext, { isServer, perfLoader, resolveModule }) {
  745. this.buildContext = buildContext;
  746. this.isServer = isServer;
  747. this.perfLoader = perfLoader;
  748. this.resolveModule = resolveModule;
  749. const { postcss: postcssOptions } = buildContext.options.build;
  750. if (postcssOptions) {
  751. const postcss = require(resolveModule('postcss'));
  752. // postcss >= v8
  753. if (!postcss.vendor) {
  754. this.postcssConfig = new PostcssConfig(buildContext);
  755. } else {
  756. this.postcssConfig = new PostcssConfig$1(buildContext);
  757. }
  758. }
  759. }
  760. get extractCSS () {
  761. return this.buildContext.buildOptions.extractCSS
  762. }
  763. get exportOnlyLocals () {
  764. return Boolean(this.isServer && this.extractCSS)
  765. }
  766. isUrlResolvingEnabled (url, resourcePath) {
  767. // Ignore absolute URLs, it will be handled by serve-static.
  768. return !url.startsWith('/')
  769. }
  770. normalize (loaders) {
  771. loaders = utils.wrapArray(loaders);
  772. return loaders.map(loader => (typeof loader === 'string' ? { loader } : loader))
  773. }
  774. styleResource (ext) {
  775. const { buildOptions: { styleResources }, options: { rootDir } } = this.buildContext;
  776. const extResource = styleResources[ext];
  777. // style-resources-loader
  778. // https://github.com/yenshih/style-resources-loader
  779. if (!extResource) {
  780. return
  781. }
  782. const patterns = utils.wrapArray(extResource).map(p => path__default['default'].resolve(rootDir, p));
  783. return {
  784. loader: this.resolveModule('style-resources-loader'),
  785. options: Object.assign(
  786. { patterns },
  787. styleResources.options || {}
  788. )
  789. }
  790. }
  791. postcss () {
  792. // postcss-loader
  793. // https://github.com/postcss/postcss-loader
  794. if (!this.postcssConfig) {
  795. return
  796. }
  797. const config = this.postcssConfig.config();
  798. if (!config) {
  799. return
  800. }
  801. return {
  802. loader: this.resolveModule('postcss-loader'),
  803. options: Object.assign({ sourceMap: this.buildContext.buildOptions.cssSourceMap }, config)
  804. }
  805. }
  806. css (options) {
  807. const cssLoader = { loader: this.resolveModule('css-loader'), options };
  808. if (!options.url) {
  809. options.url = this.isUrlResolvingEnabled;
  810. }
  811. if (this.exportOnlyLocals) {
  812. options.modules = {
  813. ...options.modules,
  814. exportOnlyLocals: true
  815. };
  816. return [cssLoader]
  817. }
  818. return [this.styleLoader(), cssLoader]
  819. }
  820. cssModules (options) {
  821. return this.css(options)
  822. }
  823. extract () {
  824. if (this.extractCSS) {
  825. const isDev = this.buildContext.options.dev;
  826. return {
  827. loader: ExtractCssChunksPlugin__default['default'].loader,
  828. options: {
  829. // TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132
  830. // https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/161#issuecomment-500162574
  831. reloadAll: isDev,
  832. hmr: isDev
  833. }
  834. }
  835. }
  836. }
  837. styleLoader () {
  838. return this.extract() || {
  839. loader: this.resolveModule('vue-style-loader'),
  840. options: this.buildContext.buildOptions.loaders.vueStyle
  841. }
  842. }
  843. apply (ext, loaders = []) {
  844. const { css, cssModules } = this.buildContext.buildOptions.loaders;
  845. const customLoaders = [].concat(
  846. this.postcss(),
  847. this.normalize(loaders),
  848. this.styleResource(ext)
  849. ).filter(Boolean);
  850. css.importLoaders = cssModules.importLoaders = customLoaders.length;
  851. return [
  852. // This matches <style module>
  853. {
  854. resourceQuery: /module/,
  855. use: this.perfLoader.css().concat(
  856. this.cssModules(cssModules),
  857. customLoaders
  858. )
  859. },
  860. // This matches plain <style> or <style scoped>
  861. {
  862. use: this.perfLoader.css().concat(
  863. this.css(css),
  864. customLoaders
  865. )
  866. }
  867. ]
  868. }
  869. }
  870. class WarningIgnorePlugin {
  871. constructor (filter) {
  872. this.filter = filter;
  873. }
  874. apply (compiler) /* istanbul ignore next */ {
  875. compiler.hooks.done.tap('warnfix-plugin', (stats) => {
  876. stats.compilation.warnings = stats.compilation.warnings.filter(this.filter);
  877. });
  878. }
  879. }
  880. const reservedVueTags = [
  881. // HTML tags
  882. 'html', 'body', 'base', 'head', 'link', 'meta', 'style', 'title', 'address',
  883. 'article', 'aside', 'footer', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
  884. 'hgroup', 'nav', 'section', 'div', 'dd', 'dl', 'dt', 'figcaption', 'figure',
  885. 'picture', 'hr', 'img', 'li', 'main', 'ol', 'p', 'pre', 'ul', 'a', 'b', 'abbr',
  886. 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark',
  887. 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub',
  888. 'sup', 'time', 'u', 'var', 'wbr', 'area', 'audio', 'map', 'track', 'video',
  889. 'embed', 'object', 'param', 'source', 'canvas', 'script', 'noscript', 'del',
  890. 'ins', 'caption', 'col', 'colgroup', 'table', 'thead', 'tbody', 'td', 'th', 'tr',
  891. 'button', 'datalist', 'fieldset', 'form', 'input', 'label', 'legend', 'meter',
  892. 'optgroup', 'option', 'output', 'progress', 'select', 'textarea', 'details',
  893. 'dialog', 'menu', 'menuitem', 'summary', 'content', 'element', 'shadow', 'template',
  894. 'blockquote', 'iframe', 'tfoot',
  895. // SVG tags
  896. 'svg', 'animate', 'circle', 'clippath', 'cursor', 'defs', 'desc', 'ellipse', 'filter',
  897. 'font-face', 'foreignObject', 'g', 'glyph', 'image', 'line', 'marker', 'mask',
  898. 'missing-glyph', 'path', 'pattern', 'polygon', 'polyline', 'rect', 'switch', 'symbol',
  899. 'text', 'textpath', 'tspan', 'use', 'view',
  900. // Vue built-in tags
  901. 'slot', 'component'
  902. ];
  903. class WebpackBaseConfig {
  904. constructor (builder) {
  905. this.builder = builder;
  906. this.buildContext = builder.buildContext;
  907. this.resolveModule = id => utils.tryResolve(id, [this.buildContext.options.rootDir, __dirname]) || id;
  908. }
  909. get colors () {
  910. return {
  911. client: 'green',
  912. server: 'orange',
  913. modern: 'blue'
  914. }
  915. }
  916. get nuxtEnv () {
  917. return {
  918. isDev: this.dev,
  919. isServer: this.isServer,
  920. isClient: !this.isServer,
  921. isModern: Boolean(this.isModern),
  922. isLegacy: Boolean(!this.isModern)
  923. }
  924. }
  925. get mode () {
  926. return this.dev ? 'development' : 'production'
  927. }
  928. get target () {
  929. return this.buildContext.target
  930. }
  931. get dev () {
  932. return this.buildContext.options.dev
  933. }
  934. get loaders () {
  935. if (!this._loaders) {
  936. this._loaders = lodash.cloneDeep(this.buildContext.buildOptions.loaders);
  937. // sass-loader<8 support (#6460)
  938. const sassLoaderPKG = utils.getPKG('sass-loader');
  939. if (sassLoaderPKG && semver__default['default'].lt(sassLoaderPKG.version, '8.0.0')) {
  940. const { sass } = this._loaders;
  941. sass.indentedSyntax = sass.sassOptions.indentedSyntax;
  942. delete sass.sassOptions.indentedSyntax;
  943. }
  944. }
  945. return this._loaders
  946. }
  947. get modulesToTranspile () {
  948. return [
  949. /\.vue\.js/i, // include SFCs in node_modules
  950. /consola\/src/,
  951. /ufo/, // exports modern syntax for browser field
  952. ...this.normalizeTranspile({ pathNormalize: true })
  953. ]
  954. }
  955. normalizeTranspile ({ pathNormalize = false } = {}) {
  956. const transpile = [];
  957. for (let pattern of this.buildContext.buildOptions.transpile) {
  958. if (typeof pattern === 'function') {
  959. pattern = pattern(this.nuxtEnv);
  960. }
  961. if (pattern instanceof RegExp) {
  962. transpile.push(pattern);
  963. } else if (typeof pattern === 'string') {
  964. const posixModule = pattern.replace(/\\/g, '/');
  965. transpile.push(new RegExp(lodash.escapeRegExp(
  966. pathNormalize ? path__default['default'].normalize(posixModule) : posixModule
  967. )));
  968. }
  969. }
  970. return transpile
  971. }
  972. getBabelOptions () {
  973. const envName = this.name;
  974. const { buildOptions: { corejs }, options: { rootDir } } = this.buildContext;
  975. const options = {
  976. ...this.buildContext.buildOptions.babel,
  977. envName
  978. };
  979. if (options.configFile || options.babelrc) {
  980. return options
  981. }
  982. if (typeof options.plugins === 'function') {
  983. options.plugins = options.plugins(
  984. {
  985. envName,
  986. ...this.nuxtEnv
  987. }
  988. );
  989. }
  990. // Auto detect corejs version
  991. let corejsVersion = corejs;
  992. if (corejsVersion === 'auto') {
  993. try {
  994. corejsVersion = Number.parseInt(utils.requireModule('core-js/package.json', rootDir).version.split('.')[0]);
  995. } catch (_err) {
  996. corejsVersion = 2;
  997. }
  998. } else {
  999. corejsVersion = Number.parseInt(corejsVersion);
  1000. }
  1001. if (![2, 3].includes(corejsVersion)) {
  1002. consola__default['default'].warn(`Invalid corejs version ${corejsVersion}! Please set "build.corejs" to either "auto", 2 or 3.`);
  1003. corejsVersion = 2;
  1004. }
  1005. const defaultPreset = [this.resolveModule('@nuxt/babel-preset-app'), {
  1006. corejs: {
  1007. version: corejsVersion
  1008. }
  1009. }];
  1010. if (typeof options.presets === 'function') {
  1011. options.presets = options.presets(
  1012. {
  1013. envName,
  1014. ...this.nuxtEnv
  1015. },
  1016. defaultPreset
  1017. );
  1018. }
  1019. if (!options.presets) {
  1020. options.presets = [defaultPreset];
  1021. }
  1022. return options
  1023. }
  1024. getFileName (key) {
  1025. let fileName = this.buildContext.buildOptions.filenames[key];
  1026. if (typeof fileName === 'function') {
  1027. fileName = fileName(this.nuxtEnv);
  1028. }
  1029. if (this.dev) {
  1030. const hash = /\[(chunkhash|contenthash|hash)(?::(\d+))?]/.exec(fileName);
  1031. if (hash) {
  1032. consola__default['default'].warn(`Notice: Please do not use ${hash[1]} in dev mode to prevent memory leak`);
  1033. }
  1034. }
  1035. if (this.buildContext.buildOptions.analyze && !fileName.includes('[name]')) {
  1036. fileName = '[name].' + fileName;
  1037. }
  1038. return fileName
  1039. }
  1040. env () {
  1041. const env = {
  1042. 'process.env.NODE_ENV': JSON.stringify(this.mode),
  1043. 'process.mode': JSON.stringify(this.mode),
  1044. 'process.dev': this.dev,
  1045. 'process.static': this.target === utils.TARGETS.static,
  1046. 'process.target': JSON.stringify(this.target)
  1047. };
  1048. if (this.buildContext.buildOptions.aggressiveCodeRemoval) {
  1049. env['typeof process'] = JSON.stringify(this.isServer ? 'object' : 'undefined');
  1050. env['typeof window'] = JSON.stringify(!this.isServer ? 'object' : 'undefined');
  1051. env['typeof document'] = JSON.stringify(!this.isServer ? 'object' : 'undefined');
  1052. }
  1053. Object.entries(this.buildContext.options.env).forEach(([key, value]) => {
  1054. env['process.env.' + key] =
  1055. ['boolean', 'number'].includes(typeof value)
  1056. ? value
  1057. : JSON.stringify(value);
  1058. });
  1059. return env
  1060. }
  1061. output () {
  1062. const {
  1063. options: { buildDir, router },
  1064. buildOptions: { publicPath }
  1065. } = this.buildContext;
  1066. return {
  1067. path: path__default['default'].resolve(buildDir, 'dist', this.isServer ? 'server' : 'client'),
  1068. filename: this.getFileName('app'),
  1069. futureEmitAssets: true, // TODO: Remove when using webpack 5
  1070. chunkFilename: this.getFileName('chunk'),
  1071. publicPath: utils.isUrl(publicPath) ? publicPath : ufo.isRelative(publicPath) ? publicPath.replace(/^\.+\//, '/') : utils.urlJoin(router.base, publicPath)
  1072. }
  1073. }
  1074. optimization () {
  1075. const optimization = lodash.cloneDeep(this.buildContext.buildOptions.optimization);
  1076. if (optimization.minimize && optimization.minimizer === undefined) {
  1077. optimization.minimizer = this.minimizer();
  1078. }
  1079. return optimization
  1080. }
  1081. resolve () {
  1082. // Prioritize nested node_modules in webpack search path (#2558)
  1083. const webpackModulesDir = ['node_modules'].concat(this.buildContext.options.modulesDir);
  1084. const resolvePath = [
  1085. ...(global.__NUXT_PREPATHS__ || []),
  1086. this.buildContext.options.rootDir,
  1087. __dirname,
  1088. ...(global.__NUXT_PATHS__ || []),
  1089. utils.resolveModule('@nuxt/vue-app'),
  1090. utils.resolveModule('@nuxt/babel-preset-app')
  1091. ];
  1092. const resolvePlugins = [PnpWebpackPlugin__namespace].concat(resolvePath.map(p => PnpWebpackPlugin__namespace.moduleLoader(p)));
  1093. return {
  1094. resolve: {
  1095. extensions: ['.wasm', '.mjs', '.js', '.json', '.vue', '.jsx'],
  1096. alias: this.alias(),
  1097. modules: webpackModulesDir,
  1098. plugins: resolvePlugins
  1099. },
  1100. resolveLoader: {
  1101. modules: [
  1102. path__default['default'].resolve(__dirname, '../node_modules'),
  1103. ...webpackModulesDir
  1104. ],
  1105. plugins: resolvePlugins
  1106. }
  1107. }
  1108. }
  1109. minimizer () {
  1110. const minimizer = [];
  1111. const { terser, cache } = this.buildContext.buildOptions;
  1112. // https://github.com/webpack-contrib/terser-webpack-plugin
  1113. if (terser) {
  1114. minimizer.push(
  1115. new TerserWebpackPlugin__default['default'](Object.assign({
  1116. cache,
  1117. extractComments: {
  1118. condition: 'some',
  1119. filename: 'LICENSES'
  1120. },
  1121. terserOptions: {
  1122. compress: {
  1123. ecma: this.isModern ? 2015 : undefined
  1124. },
  1125. mangle: {
  1126. reserved: reservedVueTags
  1127. }
  1128. }
  1129. }, terser))
  1130. );
  1131. }
  1132. return minimizer
  1133. }
  1134. alias () {
  1135. return {
  1136. ...this.buildContext.options.alias,
  1137. 'vue-meta': this.resolveModule(`vue-meta${this.isServer ? '' : '/dist/vue-meta.esm.browser.js'}`)
  1138. }
  1139. }
  1140. rules () {
  1141. const perfLoader = new PerfLoader(this.name, this.buildContext, { resolveModule: this.resolveModule });
  1142. const styleLoader = new StyleLoader(
  1143. this.buildContext,
  1144. { isServer: this.isServer, perfLoader, resolveModule: this.resolveModule }
  1145. );
  1146. const babelLoader = {
  1147. loader: this.resolveModule('babel-loader'),
  1148. options: this.getBabelOptions()
  1149. };
  1150. return [
  1151. {
  1152. test: /\.vue$/i,
  1153. loader: this.resolveModule('vue-loader'),
  1154. options: this.loaders.vue
  1155. },
  1156. {
  1157. test: /\.pug$/i,
  1158. oneOf: [
  1159. {
  1160. resourceQuery: /^\?vue/i,
  1161. use: [{
  1162. loader: this.resolveModule('pug-plain-loader'),
  1163. options: this.loaders.pugPlain
  1164. }]
  1165. },
  1166. {
  1167. use: [
  1168. this.resolveModule('raw-loader'),
  1169. {
  1170. loader: this.resolveModule('pug-plain-loader'),
  1171. options: this.loaders.pugPlain
  1172. }
  1173. ]
  1174. }
  1175. ]
  1176. },
  1177. {
  1178. test: /\.m?jsx?$/i,
  1179. exclude: (file) => {
  1180. file = file.split(/node_modules(.*)/)[1];
  1181. // not exclude files outside node_modules
  1182. if (!file) {
  1183. return false
  1184. }
  1185. // item in transpile can be string or regex object
  1186. return !this.modulesToTranspile.some(module => module.test(file))
  1187. },
  1188. use: perfLoader.js().concat(babelLoader)
  1189. },
  1190. {
  1191. test: /\.css$/i,
  1192. oneOf: styleLoader.apply('css')
  1193. },
  1194. {
  1195. test: /\.p(ost)?css$/i,
  1196. oneOf: styleLoader.apply('postcss')
  1197. },
  1198. {
  1199. test: /\.less$/i,
  1200. oneOf: styleLoader.apply('less', {
  1201. loader: this.resolveModule('less-loader'),
  1202. options: this.loaders.less
  1203. })
  1204. },
  1205. {
  1206. test: /\.sass$/i,
  1207. oneOf: styleLoader.apply('sass', {
  1208. loader: this.resolveModule('sass-loader'),
  1209. options: this.loaders.sass
  1210. })
  1211. },
  1212. {
  1213. test: /\.scss$/i,
  1214. oneOf: styleLoader.apply('scss', {
  1215. loader: this.resolveModule('sass-loader'),
  1216. options: this.loaders.scss
  1217. })
  1218. },
  1219. {
  1220. test: /\.styl(us)?$/i,
  1221. oneOf: styleLoader.apply('stylus', {
  1222. loader: this.resolveModule('stylus-loader'),
  1223. options: this.loaders.stylus
  1224. })
  1225. },
  1226. {
  1227. test: /\.(png|jpe?g|gif|svg|webp|avif)$/i,
  1228. use: [{
  1229. loader: this.resolveModule('url-loader'),
  1230. options: Object.assign(
  1231. this.loaders.imgUrl,
  1232. { name: this.getFileName('img') }
  1233. )
  1234. }]
  1235. },
  1236. {
  1237. test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
  1238. use: [{
  1239. loader: this.resolveModule('url-loader'),
  1240. options: Object.assign(
  1241. this.loaders.fontUrl,
  1242. { name: this.getFileName('font') }
  1243. )
  1244. }]
  1245. },
  1246. {
  1247. test: /\.(webm|mp4|ogv)$/i,
  1248. use: [{
  1249. loader: this.resolveModule('file-loader'),
  1250. options: Object.assign(
  1251. this.loaders.file,
  1252. { name: this.getFileName('video') }
  1253. )
  1254. }]
  1255. }
  1256. ]
  1257. }
  1258. plugins () {
  1259. const plugins = [];
  1260. const { nuxt, buildOptions } = this.buildContext;
  1261. // Add timefix-plugin before others plugins
  1262. if (this.dev) {
  1263. plugins.push(new TimeFixPlugin__default['default']());
  1264. }
  1265. // CSS extraction)
  1266. if (buildOptions.extractCSS) {
  1267. plugins.push(new ExtractCssChunksPlugin__default['default'](Object.assign({
  1268. filename: this.getFileName('css'),
  1269. chunkFilename: this.getFileName('css')
  1270. }, buildOptions.extractCSS)));
  1271. }
  1272. plugins.push(new VueLoader__default['default'].VueLoaderPlugin());
  1273. plugins.push(...(buildOptions.plugins || []));
  1274. plugins.push(new WarningIgnorePlugin(this.warningIgnoreFilter()));
  1275. // Build progress indicator
  1276. plugins.push(new WebpackBar__default['default']({
  1277. name: this.name,
  1278. color: this.colors[this.name],
  1279. reporters: [
  1280. 'basic',
  1281. 'fancy',
  1282. 'profile',
  1283. 'stats'
  1284. ],
  1285. basic: !buildOptions.quiet && env__default['default'].minimalCLI,
  1286. fancy: !buildOptions.quiet && !env__default['default'].minimalCLI,
  1287. profile: !buildOptions.quiet && buildOptions.profile,
  1288. stats: !buildOptions.quiet && !this.dev && buildOptions.stats,
  1289. reporter: {
  1290. change: (_, { shortPath }) => {
  1291. if (!this.isServer) {
  1292. nuxt.callHook('bundler:change', shortPath);
  1293. }
  1294. },
  1295. done: (buildContext) => {
  1296. if (buildContext.hasErrors) {
  1297. nuxt.callHook('bundler:error');
  1298. }
  1299. },
  1300. allDone: () => {
  1301. nuxt.callHook('bundler:done');
  1302. },
  1303. progress ({ statesArray }) {
  1304. nuxt.callHook('bundler:progress', statesArray);
  1305. }
  1306. }
  1307. }));
  1308. if (buildOptions.hardSource) {
  1309. // https://github.com/mzgoddard/hard-source-webpack-plugin
  1310. plugins.push(new HardSourcePlugin__default['default']({
  1311. info: {
  1312. level: 'warn'
  1313. },
  1314. ...buildOptions.hardSource
  1315. }));
  1316. }
  1317. return plugins
  1318. }
  1319. warningIgnoreFilter () {
  1320. const filters = [
  1321. // Hide warnings about plugins without a default export (#1179)
  1322. warn => warn.name === 'ModuleDependencyWarning' &&
  1323. warn.message.includes('export \'default\'') &&
  1324. warn.message.includes('nuxt_plugin_'),
  1325. ...(this.buildContext.buildOptions.warningIgnoreFilters || [])
  1326. ];
  1327. return warn => !filters.some(ignoreFilter => ignoreFilter(warn))
  1328. }
  1329. extendConfig (config) {
  1330. const { extend } = this.buildContext.buildOptions;
  1331. if (typeof extend === 'function') {
  1332. const extendedConfig = extend.call(
  1333. this.builder, config, { loaders: this.loaders, ...this.nuxtEnv }
  1334. ) || config;
  1335. const pragma = /@|#/;
  1336. const { devtool } = extendedConfig;
  1337. if (typeof devtool === 'string' && pragma.test(devtool)) {
  1338. extendedConfig.devtool = devtool.replace(pragma, '');
  1339. consola__default['default'].warn(`devtool has been normalized to ${extendedConfig.devtool} as webpack documented value`);
  1340. }
  1341. return extendedConfig
  1342. }
  1343. return config
  1344. }
  1345. config () {
  1346. const config = {
  1347. name: this.name,
  1348. mode: this.mode,
  1349. devtool: this.devtool,
  1350. optimization: this.optimization(),
  1351. output: this.output(),
  1352. performance: {
  1353. maxEntrypointSize: 1000 * 1024,
  1354. hints: this.dev ? false : 'warning'
  1355. },
  1356. module: {
  1357. rules: this.rules()
  1358. },
  1359. plugins: this.plugins(),
  1360. ...this.resolve()
  1361. };
  1362. // Clone deep avoid leaking config between Client and Server
  1363. const extendedConfig = lodash.cloneDeep(this.extendConfig(config));
  1364. return extendedConfig
  1365. }
  1366. }
  1367. class WebpackClientConfig extends WebpackBaseConfig {
  1368. constructor (builder) {
  1369. super(builder);
  1370. this.name = 'client';
  1371. this.isServer = false;
  1372. this.isModern = false;
  1373. }
  1374. get devtool () {
  1375. if (!this.dev) {
  1376. return false
  1377. }
  1378. const scriptPolicy = this.getCspScriptPolicy();
  1379. const noUnsafeEval = scriptPolicy && !scriptPolicy.includes('\'unsafe-eval\'');
  1380. return noUnsafeEval
  1381. ? 'cheap-module-source-map'
  1382. : 'cheap-module-eval-source-map'
  1383. }
  1384. getCspScriptPolicy () {
  1385. const { csp } = this.buildContext.options.render;
  1386. if (csp) {
  1387. const { policies = {} } = csp;
  1388. return policies['script-src'] || policies['default-src'] || []
  1389. }
  1390. }
  1391. env () {
  1392. return Object.assign(
  1393. super.env(),
  1394. {
  1395. 'process.env.VUE_ENV': JSON.stringify('client'),
  1396. 'process.browser': true,
  1397. 'process.client': true,
  1398. 'process.server': false,
  1399. 'process.modern': false
  1400. }
  1401. )
  1402. }
  1403. optimization () {
  1404. const optimization = super.optimization();
  1405. const { splitChunks } = optimization;
  1406. const { cacheGroups } = splitChunks;
  1407. // Small, known and common modules which are usually used project-wise
  1408. // Sum of them may not be more than 244 KiB
  1409. if (
  1410. this.buildContext.buildOptions.splitChunks.commons === true &&
  1411. cacheGroups.commons === undefined
  1412. ) {
  1413. cacheGroups.commons = {
  1414. 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)[\\/]/,
  1415. chunks: 'all',
  1416. name: true,
  1417. priority: 10
  1418. };
  1419. }
  1420. return optimization
  1421. }
  1422. minimizer () {
  1423. const minimizer = super.minimizer();
  1424. const { optimizeCSS } = this.buildContext.buildOptions;
  1425. // https://github.com/NMFR/optimize-css-assets-webpack-plugin
  1426. // https://github.com/webpack-contrib/mini-css-extract-plugin#minimizing-for-production
  1427. // TODO: Remove OptimizeCSSAssetsPlugin when upgrading to webpack 5
  1428. if (optimizeCSS) {
  1429. minimizer.push(new OptimizeCSSAssetsPlugin__default['default'](Object.assign({}, optimizeCSS)));
  1430. }
  1431. return minimizer
  1432. }
  1433. alias () {
  1434. const aliases = super.alias();
  1435. for (const p of this.buildContext.plugins) {
  1436. if (!aliases[p.name]) {
  1437. // Do not load server-side plugins on client-side
  1438. aliases[p.name] = p.mode === 'server' ? './empty.js' : p.src;
  1439. }
  1440. }
  1441. return aliases
  1442. }
  1443. plugins () {
  1444. const plugins = super.plugins();
  1445. const { buildOptions, options: { appTemplatePath, buildDir, modern, render } } = this.buildContext;
  1446. // Generate output HTML for SSR
  1447. if (buildOptions.ssr) {
  1448. plugins.push(
  1449. new HtmlWebpackPlugin__default['default']({
  1450. filename: '../server/index.ssr.html',
  1451. template: appTemplatePath,
  1452. minify: buildOptions.html.minify,
  1453. inject: false // Resources will be injected using bundleRenderer
  1454. })
  1455. );
  1456. }
  1457. plugins.push(
  1458. new HtmlWebpackPlugin__default['default']({
  1459. filename: '../server/index.spa.html',
  1460. template: appTemplatePath,
  1461. minify: buildOptions.html.minify,
  1462. inject: true
  1463. }),
  1464. new VueSSRClientPlugin({
  1465. filename: `../server/${this.name}.manifest.json`
  1466. }),
  1467. new webpack__default['default'].DefinePlugin(this.env())
  1468. );
  1469. if (this.dev) {
  1470. // TODO: webpackHotUpdate is not defined: https://github.com/webpack/webpack/issues/6693
  1471. plugins.push(new webpack__default['default'].HotModuleReplacementPlugin());
  1472. }
  1473. // Webpack Bundle Analyzer
  1474. // https://github.com/webpack-contrib/webpack-bundle-analyzer
  1475. if (!this.dev && buildOptions.analyze) {
  1476. const statsDir = path__default['default'].resolve(buildDir, 'stats');
  1477. plugins.push(new BundleAnalyzer__default['default'].BundleAnalyzerPlugin(Object.assign({
  1478. analyzerMode: 'static',
  1479. defaultSizes: 'gzip',
  1480. generateStatsFile: true,
  1481. openAnalyzer: !buildOptions.quiet,
  1482. reportFilename: path__default['default'].resolve(statsDir, `${this.name}.html`),
  1483. statsFilename: path__default['default'].resolve(statsDir, `${this.name}.json`)
  1484. }, buildOptions.analyze)));
  1485. }
  1486. if (modern) {
  1487. const scriptPolicy = this.getCspScriptPolicy();
  1488. const noUnsafeInline = scriptPolicy && !scriptPolicy.includes('\'unsafe-inline\'');
  1489. plugins.push(new ModernModePlugin({
  1490. targetDir: path__default['default'].resolve(buildDir, 'dist', 'client'),
  1491. isModernBuild: this.isModern,
  1492. noUnsafeInline
  1493. }));
  1494. }
  1495. if (render.crossorigin) {
  1496. plugins.push(new CorsPlugin({
  1497. crossorigin: render.crossorigin
  1498. }));
  1499. }
  1500. return plugins
  1501. }
  1502. config () {
  1503. const config = super.config();
  1504. const {
  1505. options: { router, buildDir },
  1506. buildOptions: { hotMiddleware, quiet, friendlyErrors }
  1507. } = this.buildContext;
  1508. const { client = {} } = hotMiddleware || {};
  1509. const { ansiColors, overlayStyles, ...options } = client;
  1510. const hotMiddlewareClientOptions = {
  1511. reload: true,
  1512. timeout: 30000,
  1513. ansiColors: JSON.stringify(ansiColors),
  1514. overlayStyles: JSON.stringify(overlayStyles),
  1515. path: `${router.base}/__webpack_hmr/${this.name}`.replace(/\/\//g, '/'),
  1516. ...options,
  1517. name: this.name
  1518. };
  1519. const hotMiddlewareClientOptionsStr = querystring__default['default'].stringify(hotMiddlewareClientOptions);
  1520. // Entry points
  1521. config.entry = Object.assign({}, config.entry, {
  1522. app: [path__default['default'].resolve(buildDir, 'client.js')]
  1523. });
  1524. // Add HMR support
  1525. if (this.dev) {
  1526. config.entry.app.unshift(
  1527. // https://github.com/webpack-contrib/webpack-hot-middleware/issues/53#issuecomment-162823945
  1528. this.resolveModule('eventsource-polyfill'),
  1529. // https://github.com/glenjamin/webpack-hot-middleware#config
  1530. `${this.resolveModule('webpack-hot-middleware/client')}?${hotMiddlewareClientOptionsStr}`
  1531. );
  1532. }
  1533. // Add friendly error plugin
  1534. if (this.dev && !quiet && friendlyErrors) {
  1535. config.plugins.push(
  1536. new FriendlyErrorsWebpackPlugin__default['default']({
  1537. clearConsole: false,
  1538. reporter: 'consola',
  1539. logLevel: 'WARNING'
  1540. })
  1541. );
  1542. }
  1543. return config
  1544. }
  1545. }
  1546. class WebpackModernConfig extends WebpackClientConfig {
  1547. constructor (...args) {
  1548. super(...args);
  1549. this.name = 'modern';
  1550. this.isModern = true;
  1551. }
  1552. env () {
  1553. return Object.assign(super.env(), {
  1554. 'process.modern': true
  1555. })
  1556. }
  1557. }
  1558. class VueSSRServerPlugin {
  1559. constructor (options = {}) {
  1560. this.options = Object.assign({
  1561. filename: null
  1562. }, options);
  1563. }
  1564. apply (compiler) {
  1565. validate(compiler);
  1566. compiler.hooks.emit.tapAsync('vue-server-plugin', (compilation, cb) => {
  1567. const stats = compilation.getStats().toJson();
  1568. const [entryName] = Object.keys(stats.entrypoints);
  1569. const entryInfo = stats.entrypoints[entryName];
  1570. if (!entryInfo) {
  1571. // #5553
  1572. return cb()
  1573. }
  1574. const entryAssets = entryInfo.assets.filter(isJS);
  1575. if (entryAssets.length > 1) {
  1576. throw new Error(
  1577. 'Server-side bundle should have one single entry file. ' +
  1578. 'Avoid using CommonsChunkPlugin in the server config.'
  1579. )
  1580. }
  1581. const [entry] = entryAssets;
  1582. if (!entry || typeof entry !== 'string') {
  1583. throw new Error(
  1584. `Entry "${entryName}" not found. Did you specify the correct entry option?`
  1585. )
  1586. }
  1587. const bundle = {
  1588. entry,
  1589. files: {},
  1590. maps: {}
  1591. };
  1592. stats.assets.forEach((asset) => {
  1593. if (isJS(asset.name)) {
  1594. const queryPart = extractQueryPartJS(asset.name);
  1595. if (queryPart !== undefined) {
  1596. bundle.files[asset.name] = asset.name.replace(queryPart, '');
  1597. } else {
  1598. bundle.files[asset.name] = asset.name;
  1599. }
  1600. } else if (asset.name.match(/\.js\.map$/)) {
  1601. bundle.maps[asset.name.replace(/\.map$/, '')] = asset.name;
  1602. } else {
  1603. // Do not emit non-js assets for server
  1604. delete compilation.assets[asset.name];
  1605. }
  1606. });
  1607. const src = JSON.stringify(bundle, null, 2);
  1608. compilation.assets[this.options.filename] = {
  1609. source: () => src,
  1610. size: () => src.length
  1611. };
  1612. cb();
  1613. });
  1614. }
  1615. }
  1616. const nativeFileExtensions = [
  1617. '.json',
  1618. '.js'
  1619. ];
  1620. class WebpackServerConfig extends WebpackBaseConfig {
  1621. constructor (...args) {
  1622. super(...args);
  1623. this.name = 'server';
  1624. this.isServer = true;
  1625. }
  1626. get devtool () {
  1627. return 'cheap-module-source-map'
  1628. }
  1629. get externalsAllowlist () {
  1630. return [
  1631. this.isNonNativeImport.bind(this),
  1632. ...this.normalizeTranspile()
  1633. ]
  1634. }
  1635. /**
  1636. * files *not* ending on js|json should be processed by webpack
  1637. *
  1638. * this might generate false-positives for imports like
  1639. * - "someFile.umd" (actually requiring someFile.umd.js)
  1640. * - "some.folder" (some.folder being a directory containing a package.json)
  1641. */
  1642. isNonNativeImport (modulePath) {
  1643. const extname = path__default['default'].extname(modulePath);
  1644. return extname !== '' && !nativeFileExtensions.includes(extname)
  1645. }
  1646. env () {
  1647. return Object.assign(
  1648. super.env(),
  1649. {
  1650. 'process.env.VUE_ENV': JSON.stringify('server'),
  1651. 'process.browser': false,
  1652. 'process.client': false,
  1653. 'process.server': true,
  1654. 'process.modern': false
  1655. }
  1656. )
  1657. }
  1658. optimization () {
  1659. const { _minifyServer } = this.buildContext.buildOptions;
  1660. return {
  1661. splitChunks: false,
  1662. minimizer: _minifyServer ? this.minimizer() : []
  1663. }
  1664. }
  1665. resolve () {
  1666. const resolveConfig = super.resolve();
  1667. resolveConfig.resolve.mainFields = ['main', 'module'];
  1668. return resolveConfig
  1669. }
  1670. alias () {
  1671. const aliases = super.alias();
  1672. for (const p of this.buildContext.plugins) {
  1673. if (!aliases[p.name]) {
  1674. // Do not load client-side plugins on server-side
  1675. aliases[p.name] = p.mode === 'client' ? './empty.js' : p.src;
  1676. }
  1677. }
  1678. return aliases
  1679. }
  1680. plugins () {
  1681. const plugins = super.plugins();
  1682. plugins.push(
  1683. new VueSSRServerPlugin({ filename: `${this.name}.manifest.json` }),
  1684. new webpack.DefinePlugin(this.env())
  1685. );
  1686. const { serverURLPolyfill } = this.buildContext.options.build;
  1687. if (serverURLPolyfill) {
  1688. plugins.push(new webpack.ProvidePlugin({
  1689. URL: [serverURLPolyfill, 'URL'],
  1690. URLSearchParams: [serverURLPolyfill, 'URLSearchParams']
  1691. }));
  1692. }
  1693. return plugins
  1694. }
  1695. config () {
  1696. const config = super.config();
  1697. Object.assign(config, {
  1698. target: 'node',
  1699. node: false,
  1700. entry: Object.assign({}, config.entry, {
  1701. app: [path__default['default'].resolve(this.buildContext.options.buildDir, 'server.js')]
  1702. }),
  1703. output: Object.assign({}, config.output, {
  1704. filename: 'server.js',
  1705. chunkFilename: '[name].js',
  1706. libraryTarget: 'commonjs2'
  1707. }),
  1708. performance: {
  1709. hints: false,
  1710. maxEntrypointSize: Infinity,
  1711. maxAssetSize: Infinity
  1712. },
  1713. externals: [].concat(config.externals || [])
  1714. });
  1715. // https://webpack.js.org/configuration/externals/#externals
  1716. // https://github.com/liady/webpack-node-externals
  1717. // https://vue-loader.vuejs.org/migrating.html#ssr-externals
  1718. if (!this.buildContext.buildOptions.standalone) {
  1719. this.buildContext.options.modulesDir.forEach((dir) => {
  1720. if (fs__default['default'].existsSync(dir)) {
  1721. config.externals.push(
  1722. nodeExternals__default['default']({
  1723. allowlist: this.externalsAllowlist,
  1724. modulesDir: dir
  1725. })
  1726. );
  1727. }
  1728. });
  1729. }
  1730. return config
  1731. }
  1732. }
  1733. const WebpackConfigs = /*#__PURE__*/Object.freeze({
  1734. __proto__: null,
  1735. client: WebpackClientConfig,
  1736. modern: WebpackModernConfig,
  1737. server: WebpackServerConfig
  1738. });
  1739. const glob = pify__default['default'](Glob__default['default']);
  1740. class WebpackBundler {
  1741. constructor (buildContext) {
  1742. this.buildContext = buildContext;
  1743. // Class fields
  1744. this.compilers = [];
  1745. this.compilersWatching = [];
  1746. this.devMiddleware = {};
  1747. this.hotMiddleware = {};
  1748. // Bind middleware to self
  1749. this.middleware = this.middleware.bind(this);
  1750. // Initialize shared MFS for dev
  1751. if (this.buildContext.options.dev) {
  1752. this.mfs = new AsyncMFS();
  1753. }
  1754. }
  1755. getWebpackConfig (name) {
  1756. const Config = WebpackConfigs[name.toLowerCase()]; // eslint-disable-line import/namespace
  1757. if (!Config) {
  1758. throw new Error(`Unsupported webpack config ${name}`)
  1759. }
  1760. const config = new Config(this);
  1761. return config.config()
  1762. }
  1763. async build () {
  1764. const { options } = this.buildContext;
  1765. const webpackConfigs = [
  1766. this.getWebpackConfig('Client')
  1767. ];
  1768. if (options.modern) {
  1769. webpackConfigs.push(this.getWebpackConfig('Modern'));
  1770. }
  1771. if (options.build.ssr) {
  1772. webpackConfigs.push(this.getWebpackConfig('Server'));
  1773. }
  1774. await this.buildContext.nuxt.callHook('webpack:config', webpackConfigs);
  1775. // Check styleResource existence
  1776. const { styleResources } = this.buildContext.options.build;
  1777. if (styleResources && Object.keys(styleResources).length) {
  1778. consola__default['default'].warn(
  1779. 'Using styleResources without the @nuxtjs/style-resources is not suggested and can lead to severe performance issues.',
  1780. 'Please use https://github.com/nuxt-community/style-resources-module'
  1781. );
  1782. for (const ext of Object.keys(styleResources)) {
  1783. await Promise.all(utils.wrapArray(styleResources[ext]).map(async (p) => {
  1784. const styleResourceFiles = await glob(path__default['default'].resolve(this.buildContext.options.rootDir, p));
  1785. if (!styleResourceFiles || styleResourceFiles.length === 0) {
  1786. throw new Error(`Style Resource not found: ${p}`)
  1787. }
  1788. }));
  1789. }
  1790. }
  1791. // Configure compilers
  1792. this.compilers = webpackConfigs.map((config) => {
  1793. const compiler = webpack__default['default'](config);
  1794. // In dev, write files in memory FS
  1795. if (options.dev) {
  1796. compiler.outputFileSystem = this.mfs;
  1797. }
  1798. return compiler
  1799. });
  1800. // Warm up perfLoader before build
  1801. if (options.build.parallel) {
  1802. consola__default['default'].info('Warming up worker pools');
  1803. PerfLoader.warmupAll({ dev: options.dev, resolveModule: id => utils.tryResolve(id, __filename) || id });
  1804. consola__default['default'].success('Worker pools ready');
  1805. }
  1806. // Start Builds
  1807. const runner = options.dev ? utils.parallel : utils.sequence;
  1808. await runner(this.compilers, compiler => this.webpackCompile(compiler));
  1809. }
  1810. async webpackCompile (compiler) {
  1811. const { name } = compiler.options;
  1812. const { nuxt, options } = this.buildContext;
  1813. await nuxt.callHook('build:compile', { name, compiler });
  1814. // Load renderer resources after build
  1815. compiler.hooks.done.tap('load-resources', async (stats) => {
  1816. await nuxt.callHook('build:compiled', {
  1817. name,
  1818. compiler,
  1819. stats
  1820. });
  1821. // Reload renderer
  1822. await nuxt.callHook('build:resources', this.mfs);
  1823. });
  1824. // --- Dev Build ---
  1825. if (options.dev) {
  1826. // Client Build, watch is started by dev-middleware
  1827. if (['client', 'modern'].includes(name)) {
  1828. return new Promise((resolve, reject) => {
  1829. compiler.hooks.done.tap('nuxt-dev', () => resolve());
  1830. return this.webpackDev(compiler)
  1831. })
  1832. }
  1833. // Server, build and watch for changes
  1834. return new Promise((resolve, reject) => {
  1835. const watching = compiler.watch(options.watchers.webpack, (err) => {
  1836. if (err) {
  1837. return reject(err)
  1838. }
  1839. resolve();
  1840. });
  1841. watching.close = pify__default['default'](watching.close);
  1842. this.compilersWatching.push(watching);
  1843. })
  1844. }
  1845. // --- Production Build ---
  1846. compiler.run = pify__default['default'](compiler.run);
  1847. const stats = await compiler.run();
  1848. if (stats.hasErrors()) {
  1849. // non-quiet mode: errors will be printed by webpack itself
  1850. const error = new Error('Nuxt build error');
  1851. if (options.build.quiet === true) {
  1852. error.stack = stats.toString('errors-only');
  1853. }
  1854. throw error
  1855. }
  1856. // Await for renderer to load resources (programmatic, tests and generate)
  1857. await nuxt.callHook('build:resources');
  1858. }
  1859. async webpackDev (compiler) {
  1860. consola__default['default'].debug('Creating webpack middleware...');
  1861. const { name } = compiler.options;
  1862. const buildOptions = this.buildContext.options.build;
  1863. const { client, ...hotMiddlewareOptions } = buildOptions.hotMiddleware || {};
  1864. compiler.options.watchOptions = this.buildContext.options.watchers.webpack;
  1865. compiler.hooks.infrastructureLog.tap('webpack-dev-middleware-log', (name) => {
  1866. if (name === 'webpack-dev-middleware') {
  1867. return false
  1868. }
  1869. return undefined
  1870. });
  1871. // Create webpack dev middleware
  1872. this.devMiddleware[name] = pify__default['default'](
  1873. webpackDevMiddleware__default['default'](
  1874. compiler, {
  1875. outputFileSystem: compiler.outputFileSystem,
  1876. ...buildOptions.devMiddleware
  1877. })
  1878. );
  1879. this.devMiddleware[name].close = pify__default['default'](this.devMiddleware[name].close);
  1880. this.compilersWatching.push(this.devMiddleware[name].context.watching);
  1881. this.hotMiddleware[name] = pify__default['default'](
  1882. webpackHotMiddleware__default['default'](
  1883. compiler, {
  1884. log: false,
  1885. heartbeat: 10000,
  1886. path: `/__webpack_hmr/${name}`,
  1887. ...hotMiddlewareOptions
  1888. })
  1889. );
  1890. // Register devMiddleware on server
  1891. await this.buildContext.nuxt.callHook('server:devMiddleware', this.middleware);
  1892. }
  1893. async middleware (req, res, next) {
  1894. const name = utils.isModernRequest(req, this.buildContext.options.modern) ? 'modern' : 'client';
  1895. if (this.devMiddleware && this.devMiddleware[name]) {
  1896. const { url } = req;
  1897. req.url = req.originalUrl || req.url;
  1898. await this.devMiddleware[name](req, res);
  1899. req.url = url;
  1900. }
  1901. if (this.hotMiddleware && this.hotMiddleware[name]) {
  1902. await this.hotMiddleware[name](req, res);
  1903. }
  1904. next();
  1905. }
  1906. async unwatch () {
  1907. await Promise.all(this.compilersWatching.map(watching => watching.close()));
  1908. }
  1909. async close () {
  1910. if (this.__closed) {
  1911. return
  1912. }
  1913. this.__closed = true;
  1914. // Unwatch
  1915. await this.unwatch();
  1916. // Stop webpack middleware
  1917. for (const devMiddleware of Object.values(this.devMiddleware)) {
  1918. await devMiddleware.close();
  1919. }
  1920. // Cleanup MFS
  1921. if (this.mfs) {
  1922. delete this.mfs.data;
  1923. delete this.mfs;
  1924. }
  1925. // Cleanup more resources
  1926. delete this.compilers;
  1927. delete this.compilersWatching;
  1928. delete this.devMiddleware;
  1929. delete this.hotMiddleware;
  1930. }
  1931. forGenerate () {
  1932. this.buildContext.target = utils.TARGETS.static;
  1933. }
  1934. }
  1935. exports.BundleBuilder = WebpackBundler;