"use strict";exports.__esModule=true;exports.renderScriptError=renderScriptError;exports.default=void 0;var _middleware=require("@next/react-dev-overlay/lib/middleware");var _webpackDevMiddleware=_interopRequireDefault(require("next/dist/compiled/webpack-dev-middleware"));var _webpackHotMiddleware=_interopRequireDefault(require("next/dist/compiled/webpack-hot-middleware"));var _path=require("path");var _webpack=_interopRequireDefault(require("webpack"));var _entries=require("../build/entries");var _output=require("../build/output");var _webpackConfig=_interopRequireDefault(require("../build/webpack-config"));var _constants=require("../lib/constants");var _recursiveDelete=require("../lib/recursive-delete");var _constants2=require("../next-server/lib/constants");var _router=require("../next-server/server/router");var _errorOverlayMiddleware=_interopRequireDefault(require("./lib/error-overlay-middleware"));var _findPageFile=require("./lib/find-page-file");var _onDemandEntryHandler=_interopRequireWildcard(require("./on-demand-entry-handler"));function _getRequireWildcardCache(){if(typeof WeakMap!=="function")return null;var cache=new WeakMap();_getRequireWildcardCache=function(){return cache;};return cache;}function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}if(obj===null||typeof obj!=="object"&&typeof obj!=="function"){return{default:obj};}var cache=_getRequireWildcardCache();if(cache&&cache.has(obj)){return cache.get(obj);}var newObj={};var hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;if(desc&&(desc.get||desc.set)){Object.defineProperty(newObj,key,desc);}else{newObj[key]=obj[key];}}}newObj.default=obj;if(cache){cache.set(obj,newObj);}return newObj;}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}async function renderScriptError(res,error){// Asks CDNs and others to not to cache the errored page
res.setHeader('Cache-Control','no-cache, no-store, max-age=0, must-revalidate');if(error.code==='ENOENT'||error.message==='INVALID_BUILD_ID'){res.statusCode=404;res.end('404 - Not Found');return;}console.error(error.stack);res.statusCode=500;res.end('500 - Internal Error');}function addCorsSupport(req,res){const isApiRoute=req.url.match(_constants.API_ROUTE);// API routes handle their own CORS headers
if(isApiRoute){return{preflight:false};}if(!req.headers.origin){return{preflight:false};}res.setHeader('Access-Control-Allow-Origin',req.headers.origin);res.setHeader('Access-Control-Allow-Methods','OPTIONS, GET');// Based on https://github.com/primus/access-control/blob/4cf1bc0e54b086c91e6aa44fb14966fa5ef7549c/index.js#L158
if(req.headers['access-control-request-headers']){res.setHeader('Access-Control-Allow-Headers',req.headers['access-control-request-headers']);}if(req.method==='OPTIONS'){res.writeHead(200);res.end();return{preflight:true};}return{preflight:false};}const matchNextPageBundleRequest=(0,_router.route)('/_next/static/:buildId/pages/:path*.js(\\.map|)');// Recursively look up the issuer till it ends up at the root
function findEntryModule(issuer){if(issuer.issuer){return findEntryModule(issuer.issuer);}return issuer;}function erroredPages(compilation,options={enhanceName:name=>name}){const failedPages={};for(const error of compilation.errors){if(!error.origin){continue;}const entryModule=findEntryModule(error.origin);const{name}=entryModule;if(!name){continue;}// Only pages have to be reloaded
if(!_constants2.IS_BUNDLED_PAGE_REGEX.test(name)){continue;}const enhancedName=options.enhanceName(name);if(!failedPages[enhancedName]){failedPages[enhancedName]=[];}failedPages[enhancedName].push(error);}return failedPages;}class HotReloader{constructor(dir,{config,pagesDir,buildId,previewProps}){this.dir=void 0;this.buildId=void 0;this.middlewares=void 0;this.pagesDir=void 0;this.webpackDevMiddleware=void 0;this.webpackHotMiddleware=void 0;this.initialized=void 0;this.config=void 0;this.stats=void 0;this.serverStats=void 0;this.serverPrevDocumentHash=void 0;this.prevChunkNames=void 0;this.onDemandEntries=void 0;this.previewProps=void 0;this.buildId=buildId;this.dir=dir;this.middlewares=[];this.pagesDir=pagesDir;this.webpackDevMiddleware=null;this.webpackHotMiddleware=null;this.initialized=false;this.stats=null;this.serverStats=null;this.serverPrevDocumentHash=null;this.config=config;this.previewProps=previewProps;}async run(req,res,parsedUrl){// Usually CORS support is not needed for the hot-reloader (this is dev only feature)
// With when the app runs for multi-zones support behind a proxy,
// the current page is trying to access this URL via assetPrefix.
// That's when the CORS support is needed.
const{preflight}=addCorsSupport(req,res);if(preflight){return;}// When a request comes in that is a page bundle, e.g. /_next/static/<buildid>/pages/index.js
// we have to compile the page using on-demand-entries, this middleware will handle doing that
// by adding the page to on-demand-entries, waiting till it's done
// and then the bundle will be served like usual by the actual route in server/index.js
const handlePageBundleRequest=async(pageBundleRes,parsedPageBundleUrl)=>{const{pathname}=parsedPageBundleUrl;const params=matchNextPageBundleRequest(pathname);if(!params){return{};}if(params.buildId!==this.buildId){return{};}const page=`/${params.path.join('/')}`;if(page==='/_error'||_constants2.BLOCKED_PAGES.indexOf(page)===-1){try{await this.ensurePage(page);}catch(error){await renderScriptError(pageBundleRes,error);return{finished:true};}const bundlePath=(0,_path.join)(this.dir,this.config.distDir,'server/static/development/pages',page+'.js');// Make sure to 404 for AMP first pages
try{var _mod$config;const mod=require(bundlePath);if((mod===null||mod===void 0?void 0:(_mod$config=mod.config)===null||_mod$config===void 0?void 0:_mod$config.amp)===true){pageBundleRes.statusCode=404;pageBundleRes.end();return{finished:true};}}catch(_){}const errors=await this.getCompilationErrors(page);if(errors.length>0){await renderScriptError(pageBundleRes,errors[0]);return{finished:true};}}return{};};const{finished}=await handlePageBundleRequest(res,parsedUrl);for(const fn of this.middlewares){await new Promise((resolve,reject)=>{fn(req,res,err=>{if(err)return reject(err);resolve();});});}return{finished};}async clean(){return(0,_recursiveDelete.recursiveDelete)((0,_path.join)(this.dir,this.config.distDir),/^cache/);}async getWebpackConfig(){const pagePaths=await Promise.all([(0,_findPageFile.findPageFile)(this.pagesDir,'/_app',this.config.pageExtensions),(0,_findPageFile.findPageFile)(this.pagesDir,'/_document',this.config.pageExtensions)]);const pages=(0,_entries.createPagesMapping)(pagePaths.filter(i=>i!==null),this.config.pageExtensions);const entrypoints=(0,_entries.createEntrypoints)(/* dev */true,pages,'server',this.buildId,this.previewProps,this.config,[]);let additionalClientEntrypoints={};additionalClientEntrypoints[_constants2.CLIENT_STATIC_FILES_RUNTIME_AMP]=`.${_path.sep}`+(0,_path.relative)(this.dir,(0,_path.join)(_constants.NEXT_PROJECT_ROOT_DIST_CLIENT,'dev','amp-dev'));additionalClientEntrypoints[_constants2.CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH]=require.resolve(`@next/react-refresh-utils/runtime`);return Promise.all([(0,_webpackConfig.default)(this.dir,{dev:true,isServer:false,config:this.config,buildId:this.buildId,pagesDir:this.pagesDir,entrypoints:{...entrypoints.client,...additionalClientEntrypoints}}),(0,_webpackConfig.default)(this.dir,{dev:true,isServer:true,config:this.config,buildId:this.buildId,pagesDir:this.pagesDir,entrypoints:entrypoints.server})]);}async start(){await this.clean();const configs=await this.getWebpackConfig();const multiCompiler=(0,_webpack.default)(configs);const buildTools=await this.prepareBuildTools(multiCompiler);this.assignBuildTools(buildTools)// [Client, Server]
;[this.stats,this.serverStats]=(await this.waitUntilValid()).stats;}async stop(webpackDevMiddleware){const middleware=webpackDevMiddleware||this.webpackDevMiddleware;if(middleware){return new Promise((resolve,reject)=>{;middleware.close(err=>{if(err)return reject(err);resolve();});});}}assignBuildTools({webpackDevMiddleware,webpackHotMiddleware,onDemandEntries}){this.webpackDevMiddleware=webpackDevMiddleware;this.webpackHotMiddleware=webpackHotMiddleware;this.onDemandEntries=onDemandEntries;this.middlewares=[webpackDevMiddleware,// must come before hotMiddleware
onDemandEntries.middleware(),webpackHotMiddleware,(0,_errorOverlayMiddleware.default)({dir:this.dir}),(0,_middleware.getOverlayMiddleware)({rootDirectory:this.dir,stats:()=>this.stats,serverStats:()=>this.serverStats})];}async prepareBuildTools(multiCompiler){(0,_output.watchCompilers)(multiCompiler.compilers[0],multiCompiler.compilers[1]);// This plugin watches for changes to _document.js and notifies the client side that it should reload the page
multiCompiler.compilers[1].hooks.done.tap('NextjsHotReloaderForServer',stats=>{this.serverStats=stats;if(!this.initialized){return;}const{compilation}=stats;// We only watch `_document` for changes on the server compilation
// the rest of the files will be triggered by the client compilation
const documentChunk=compilation.chunks.find(c=>c.name===(0,_path.normalize)(`static/${this.buildId}/pages/_document.js`));// If the document chunk can't be found we do nothing
if(!documentChunk){console.warn('_document.js chunk not found');return;}// Initial value
if(this.serverPrevDocumentHash===null){this.serverPrevDocumentHash=documentChunk.hash;return;}// If _document.js didn't change we don't trigger a reload
if(documentChunk.hash===this.serverPrevDocumentHash){return;}// Notify reload to reload the page, as _document.js was changed (different hash)
this.send('reloadPage');this.serverPrevDocumentHash=documentChunk.hash;});multiCompiler.compilers[0].hooks.done.tap('NextjsHotReloaderForClient',stats=>{const{compilation}=stats;const chunkNames=new Set(compilation.chunks.map(c=>c.name).filter(name=>_constants2.IS_BUNDLED_PAGE_REGEX.test(name)));if(this.initialized){// detect chunks which have to be replaced with a new template
// e.g, pages/index.js <-> pages/_error.js
const addedPages=diff(chunkNames,this.prevChunkNames);const removedPages=diff(this.prevChunkNames,chunkNames);if(addedPages.size>0){for(const addedPage of addedPages){let page='/'+_constants2.ROUTE_NAME_REGEX.exec(addedPage)[1].replace(/\\/g,'/');page=page==='/index'?'/':page;this.send('addedPage',page);}}if(removedPages.size>0){for(const removedPage of removedPages){let page='/'+_constants2.ROUTE_NAME_REGEX.exec(removedPage)[1].replace(/\\/g,'/');page=page==='/index'?'/':page;this.send('removedPage',page);}}}this.initialized=true;this.stats=stats;this.prevChunkNames=chunkNames;});// We don’t watch .git/ .next/ and node_modules for changes
const ignored=[/[\\/]\.git[\\/]/,/[\\/]\.next[\\/]/,/[\\/]node_modules[\\/]/];let webpackDevMiddlewareConfig={publicPath:`/_next/static/webpack`,noInfo:true,logLevel:'silent',watchOptions:{ignored},writeToDisk:true};if(this.config.webpackDevMiddleware){console.log(`> Using "webpackDevMiddleware" config function defined in ${this.config.configOrigin}.`);webpackDevMiddlewareConfig=this.config.webpackDevMiddleware(webpackDevMiddlewareConfig);}const webpackDevMiddleware=(0,_webpackDevMiddleware.default)(multiCompiler,webpackDevMiddlewareConfig);const webpackHotMiddleware=(0,_webpackHotMiddleware.default)(multiCompiler.compilers[0],{path:'/_next/webpack-hmr',log:false,heartbeat:2500});const onDemandEntries=(0,_onDemandEntryHandler.default)(webpackDevMiddleware,multiCompiler,{buildId:this.buildId,pagesDir:this.pagesDir,pageExtensions:this.config.pageExtensions,...this.config.onDemandEntries});return{webpackDevMiddleware,webpackHotMiddleware,onDemandEntries};}waitUntilValid(){return new Promise(resolve=>{this.webpackDevMiddleware.waitUntilValid(resolve);});}async getCompilationErrors(page){const normalizedPage=(0,_onDemandEntryHandler.normalizePage)(page);if(this.stats.hasErrors()){const{compilation}=this.stats;const failedPages=erroredPages(compilation,{enhanceName(name){return'/'+_constants2.ROUTE_NAME_REGEX.exec(name)[1];}});// If there is an error related to the requesting page we display it instead of the first error
if(failedPages[normalizedPage]&&failedPages[normalizedPage].length>0){return failedPages[normalizedPage];}// If none were found we still have to show the other errors
return this.stats.compilation.errors;}return[];}send(action,...args){this.webpackHotMiddleware.publish({action,data:args});}async ensurePage(page){// Make sure we don't re-build or dispose prebuilt pages
if(page!=='/_error'&&_constants2.BLOCKED_PAGES.indexOf(page)!==-1){return;}return this.onDemandEntries.ensurePage(page);}}exports.default=HotReloader;function diff(a,b){return new Set([...a].filter(v=>!b.has(v)));}
//# sourceMappingURL=hot-reloader.js.map