UNPKG

@gasket/plugin-nextjs

Version:
151 lines (150 loc) 6.59 kB
/// <reference types="@gasket/plugin-webpack" /> Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { externalizeGasketCore: function() { return externalizeGasketCore; }, replaceGasketFiles: function() { return replaceGasketFiles; }, validateNoGasketCore: function() { return validateNoGasketCore; }, webpackConfig: function() { return webpackConfigHook; } }); const _module = require("module"); const _path = require("path"); const _tryresolve = /*#__PURE__*/ _interop_require_default(require("./utils/try-resolve.cjs")); const _url = require("url"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const require1 = (0, _module.createRequire)(require("url").pathToFileURL(__filename).toString()); // Matches: @gasket/plugin-* or @*/gasket-plugin-* const isGasketPluginPath = /(@gasket\/plugin-|@[\w-]+\/gasket-plugin-)/; const isGasketCore = /@gasket[/\\]core$/; // Generate empty module programmatically to avoid committing a file const fileName = (0, _url.fileURLToPath)(require("url").pathToFileURL(__filename).toString()); const dirName = (0, _path.dirname)(fileName); const emptyModulePath = (0, _path.join)(dirName, 'noop-replacement.cjs'); /** * Function to validate that '@gasket/core' is not used in browser code. * If '@gasket/core' is found in the module request, an error is thrown. * @param {{ request: string, dependencyType?: string }} ctx - The context object containing the request string. * @param {(error?: Error | null, result?: any) => void} callback - The externals callback. * @returns {void} */ function validateNoGasketCore(ctx, callback) { if (isGasketCore.test(ctx.request)) { return callback(new Error('@gasket/core should not be used in browser code.')); } return callback(); } /** * Externalize @gasket/core in the server build. * We do this to enable GASKET_ENV to be picked up and passed to the plugins. * Otherwise, unique builds per environment would be required. * @param {{ request: string, dependencyType?: string }} ctx - The context object containing the request string. * @param {(error?: Error | null, result?: any) => void} callback - The externals callback. * @returns {void|*} Returns void or the result of the callback */ function externalizeGasketCore(ctx, callback) { if (isGasketCore.test(ctx.request)) { const externalsType = ctx.dependencyType === 'esm' ? 'module' : 'commonjs'; return callback(null, [ externalsType, ctx.request ].join(' ')); } return callback(); } /** * Setup webpack resolve aliases * @param {import('webpack').Configuration} webpackConfig * The webpack configuration object * @param {string} root - Gasket config root path * @returns {Function} Exclude function to exclude modules from the bundle */ function setupResolveAliases(webpackConfig, root) { var _webpackConfig, _webpackConfig_resolve; (_webpackConfig = webpackConfig).resolve ?? (_webpackConfig.resolve = {}); (_webpackConfig_resolve = webpackConfig.resolve).alias ?? (_webpackConfig_resolve.alias = {}); // This is only needed for configuring webpack and should not be bundled to avoid require function warnings webpackConfig.resolve.alias[require1.resolve('./utils/try-resolve.cjs')] = false; const exclude = (moduleName)=>{ const resolved = (0, _tryresolve.default)(moduleName, [ root ]); if (resolved) { webpackConfig.resolve.alias[resolved] = false; } }; return exclude; } /** * Setup client-side externals * @param {import('webpack').Configuration} webpackConfig * The webpack configuration object * @param {Function} exclude - Function to exclude modules from the bundle * @returns {void} */ function setupClientExternals(webpackConfig, exclude) { exclude('./gasket.js'); exclude('./src/gasket.js'); exclude('./gasket.cjs'); exclude('./src/gasket.cjs'); exclude('./gasket.ts'); exclude('./src/gasket.ts'); exclude('./dist/gasket.js'); /** @type {any[]} */ webpackConfig.externals.unshift(validateNoGasketCore); } /** * Replace create.js and webpack-config.js files with empty.cjs * @param {import('webpack').WebpackPluginInstance} webpack - The webpack plugin instance * @param {import('webpack').Configuration} webpackConfig - The webpack configuration * @returns {import('webpack').Configuration} The modified webpack configuration */ function replaceGasketFiles(webpack, webpackConfig) { var // Replace create.js and webpack-config.js files with empty.cjs // These files are build-time only and use Node APIs that don't work in Edge runtime or RSC // Replace them with an empty module so imports still work but don't bundle Node APIs // Apply to all builds (server, edge, RSC) to prevent Node API errors // Only replace files in Gasket plugin paths (@gasket/plugin-* or @*/gasket-plugin-*) _webpackConfig; (_webpackConfig = webpackConfig).plugins ?? (_webpackConfig.plugins = []); webpackConfig.plugins.push(new webpack.NormalModuleReplacementPlugin(/(create|webpack-config)\.m?c?js$/, (resource)=>{ // Only replace if the resource is from a Gasket plugin // Check both context (module path) and request (import path) const context = resource.context || ''; const request = resource.request || ''; if (isGasketPluginPath.test(context) || isGasketPluginPath.test(request)) { resource.request = emptyModulePath; } })); return webpackConfig; } /** * Webpack configuration hook for Next.js integration * @type {import('@gasket/core').HookHandler<'webpackConfig'>} * @returns {import('webpack').Configuration} Modified webpack configuration */ function webpackConfigHook(gasket, webpackConfig, { webpack, isServer }) { const exclude = setupResolveAliases(webpackConfig, gasket.config.root); if (Array.isArray(webpackConfig.externals)) { if (!isServer) { setupClientExternals(webpackConfig, exclude); } } else { throw new Error('Expected webpackConfig.externals to be an array'); } webpackConfig.plugins.push(new webpack.EnvironmentPlugin({ GASKET_ENV: gasket.config.env })); return replaceGasketFiles(webpack, webpackConfig); }