import { ConcatSource } from 'webpack-sources' import { IS_BUNDLED_PAGE_REGEX, ROUTE_NAME_REGEX } from 'next-server/constants' export default class PagesPlugin { apply (compiler) { compiler.hooks.compilation.tap('PagesPlugin', (compilation) => { // This hook is triggered right before a module gets wrapped into it's initializing function, // For example when you look at the source of a bundle you'll see an object holding `'pages/_app.js': function(module, etc, etc)` // This hook triggers right before that code is added and wraps the module into `__NEXT_REGISTER_PAGE` when the module is a page // The reason we're doing this is that we don't want to execute the page code which has potential side effects before switching to a route compilation.moduleTemplates.javascript.hooks.render.tap('PagesPluginRenderPageRegister', (moduleSourcePostModule, module, options) => { const {chunk} = options // check if the current module is the entry module, we only want to wrap the topmost module if (chunk.entryModule !== module) { return moduleSourcePostModule } // Check if the chunk is a page if (!IS_BUNDLED_PAGE_REGEX.test(chunk.name)) { return moduleSourcePostModule } // Match the route the chunk belongs to let routeName = ROUTE_NAME_REGEX.exec(chunk.name)[1] // We need to convert \ into / when we are in windows // to get the proper route name // Here we need to do windows check because it's possible // to have "\" in the filename in unix. // Anyway if someone did that, he'll be having issues here. // But that's something we cannot avoid. if (/^win/.test(process.platform)) { routeName = routeName.replace(/\\/g, '/') } routeName = `/${routeName.replace(/(^|\/)index$/, '')}` const source = new ConcatSource( `(window.__NEXT_P=window.__NEXT_P||[]).push(['${routeName}', function() {\n`, moduleSourcePostModule, '\nreturn { page: module.exports.default }', '}]);' ) return source }) }) } }