diff --git a/packages/nextjs/.eslintrc.js b/packages/nextjs/.eslintrc.js index 857887cc1c15..4e6b28a60fdf 100644 --- a/packages/nextjs/.eslintrc.js +++ b/packages/nextjs/.eslintrc.js @@ -11,4 +11,12 @@ module.exports = { rules: { '@sentry-internal/sdk/no-async-await': 'off', }, + overrides: [ + { + files: ['scripts/**/*.ts'], + parserOptions: { + project: ['../../tsconfig.dev.json'], + }, + }, + ], }; diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 99fa45a0ee66..1770224d626e 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -45,11 +45,11 @@ "scripts": { "build": "run-p build:rollup build:types", "build:dev": "run-s build", - "build:rollup": "rollup -c rollup.npm.config.js", + "build:rollup": "ts-node scripts/buildRollup.ts", "build:types": "tsc -p tsconfig.types.json", "build:watch": "run-p build:rollup:watch build:types:watch", "build:dev:watch": "run-s build:watch", - "build:rollup:watch": "rollup -c rollup.npm.config.js --watch", + "build:rollup:watch": "nodemon --ext ts --watch src scripts/buildRollup.ts", "build:types:watch": "tsc -p tsconfig.types.json --watch", "build:npm": "ts-node ../../scripts/prepack.ts && npm pack ./build", "circularDepCheck": "madge --circular src/index.client.ts && madge --circular --exclude 'config/types\\.ts' src/index.server.ts # see https://github.com/pahen/madge/issues/306", diff --git a/packages/nextjs/rollup.npm.config.js b/packages/nextjs/rollup.npm.config.js index 88249bb2458a..761b0aba3b83 100644 --- a/packages/nextjs/rollup.npm.config.js +++ b/packages/nextjs/rollup.npm.config.js @@ -14,12 +14,12 @@ export default [ ), ...makeNPMConfigVariants( makeBaseNPMConfig({ - entrypoints: ['src/config/prefixLoaderTemplate.ts'], + entrypoints: ['src/config/templates/prefixLoaderTemplate.ts'], packageSpecificConfig: { output: { // preserve the original file structure (i.e., so that everything is still relative to `src`) - entryFileNames: 'config/[name].js', + entryFileNames: 'config/templates/[name].js', // this is going to be add-on code, so it doesn't need the trappings of a full module (and in fact actively // shouldn't have them, lest they muck with the module to which we're adding it) @@ -31,7 +31,7 @@ export default [ ), ...makeNPMConfigVariants( makeBaseNPMConfig({ - entrypoints: ['src/config/prefixLoader.ts'], + entrypoints: ['src/config/loaders/prefixLoader.ts'], packageSpecificConfig: { output: { @@ -39,7 +39,7 @@ export default [ exports: 'default', // preserve the original file structure (i.e., so that everything is still relative to `src`) - entryFileNames: 'config/[name].js', + entryFileNames: 'config/loaders/[name].js', }, }, }), diff --git a/packages/nextjs/scripts/buildRollup.ts b/packages/nextjs/scripts/buildRollup.ts new file mode 100644 index 000000000000..0bf01ba51e4c --- /dev/null +++ b/packages/nextjs/scripts/buildRollup.ts @@ -0,0 +1,24 @@ +import * as childProcess from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; + +/** + * Run the given shell command, piping the shell process's `stdin`, `stdout`, and `stderr` to that of the current + * process. Returns contents of `stdout`. + */ +function run(cmd: string, options?: childProcess.ExecSyncOptions): string | Buffer { + return childProcess.execSync(cmd, { stdio: 'inherit', ...options }); +} + +run('yarn rollup -c rollup.npm.config.js'); + +// Regardless of whether nextjs is using the CJS or ESM version of our SDK, we want the code from our templates to be in +// ESM (since we'll be adding it onto page files which are themselves written in ESM), so copy the ESM versions of the +// templates over into the CJS build directory. (Building only the ESM version and sticking it in both locations is +// something which in theory Rollup could do, but it would mean refactoring our Rollup helper functions, which isn't +// worth it just for this.) +const cjsTemplateDir = 'build/cjs/config/templates/'; +const esmTemplateDir = 'build/esm/config/templates/'; +fs.readdirSync(esmTemplateDir).forEach(templateFile => + fs.copyFileSync(path.join(esmTemplateDir, templateFile), path.join(cjsTemplateDir, templateFile)), +); diff --git a/packages/nextjs/src/config/prefixLoader.ts b/packages/nextjs/src/config/loaders/prefixLoader.ts similarity index 67% rename from packages/nextjs/src/config/prefixLoader.ts rename to packages/nextjs/src/config/loaders/prefixLoader.ts index 29a1e66c73bd..5e95a32e8342 100644 --- a/packages/nextjs/src/config/prefixLoader.ts +++ b/packages/nextjs/src/config/loaders/prefixLoader.ts @@ -1,27 +1,22 @@ import * as fs from 'fs'; import * as path from 'path'; +import { LoaderThis } from './types'; + type LoaderOptions = { distDir: string; }; -// TODO Use real webpack types -type LoaderThis = { - // Webpack 4 - query?: LoaderOptions; - // Webpack 5 - getOptions?: () => LoaderOptions; - addDependency: (filepath: string) => void; -}; /** * Inject templated code into the beginning of a module. */ -function prefixLoader(this: LoaderThis, userCode: string): string { +function prefixLoader(this: LoaderThis, userCode: string): string { // We know one or the other will be defined, depending on the version of webpack being used // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const { distDir } = this.getOptions ? this.getOptions() : this.query!; - const templatePath = path.resolve(__dirname, 'prefixLoaderTemplate.js'); + const templatePath = path.resolve(__dirname, '../templates/prefixLoaderTemplate.js'); + // make sure the template is included when runing `webpack watch` this.addDependency(templatePath); // Fill in the placeholder diff --git a/packages/nextjs/src/config/loaders/types.ts b/packages/nextjs/src/config/loaders/types.ts new file mode 100644 index 000000000000..aa79b5c1d5e7 --- /dev/null +++ b/packages/nextjs/src/config/loaders/types.ts @@ -0,0 +1,10 @@ +// TODO Use real webpack types +export type LoaderThis = { + // Loader options in Webpack 4 + query?: Options; + // Loader options in Webpack 5 + getOptions?: () => Options; + + // Function to add outside file used by loader to `watch` process + addDependency: (filepath: string) => void; +}; diff --git a/packages/nextjs/src/config/prefixLoaderTemplate.ts b/packages/nextjs/src/config/templates/prefixLoaderTemplate.ts similarity index 60% rename from packages/nextjs/src/config/prefixLoaderTemplate.ts rename to packages/nextjs/src/config/templates/prefixLoaderTemplate.ts index 7f529262e53f..9bce6accc6be 100644 --- a/packages/nextjs/src/config/prefixLoaderTemplate.ts +++ b/packages/nextjs/src/config/templates/prefixLoaderTemplate.ts @@ -1,5 +1,6 @@ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any (global as any).__rewriteFramesDistDir__ = '__DIST_DIR__'; -// We need this to make this file an ESM module, which TS requires when using `isolatedModules`. +// We need this to make this file an ESM module, which TS requires when using `isolatedModules`, but it doesn't affect +// the end result - Rollup recognizes that it's a no-op and doesn't include it when building our code. export {}; diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index 9432bad34ed5..13c970657811 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -65,7 +65,7 @@ export function constructWebpackConfigFunction( // Support non-default output directories by making the output path (easy to get here at build-time) // available to the server SDK's default `RewriteFrames` instance (which needs it at runtime), by // injecting code to attach it to `global`. - loader: path.resolve(__dirname, 'prefixLoader.js'), + loader: path.resolve(__dirname, 'loaders/prefixLoader.js'), options: { distDir: userNextConfig.distDir || '.next', },