From bb77f3a0d0968d6d566e9a25fdb933997b2204be Mon Sep 17 00:00:00 2001 From: Hasan Ayan Date: Tue, 13 Jul 2021 00:38:08 +0300 Subject: [PATCH 1/4] added module federation suppport. thi plugin now injects additional SENTRY_RELEASES variable into global scope as an object that holds versions for all apps keyed by [project]@[org] --- package.json | 6 ++++- src/__tests__/index.spec.js | 40 +++++++++++++++++++++++++---- src/index.js | 51 +++++++++++++++++++++++++++++++++++++ src/sentry.loader.js | 11 ++++++-- yarn.lock | 10 +++++++- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 01b1b51e..d0035416 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,9 @@ "dependencies": { "@sentry/cli": "^1.67.1" }, + "peerDependencies": { + "webpack-sources": "*" + }, "devDependencies": { "codecov": "^3.5.0", "eslint": "^5.16.0", @@ -30,7 +33,8 @@ "npm-run-all": "^4.1.5", "prettier": "^1.18.2", "prettier-check": "^2.0.0", - "webpack": "^4.39.3" + "webpack": "^4.39.3", + "webpack-sources": "^2.3.0" }, "scripts": { "lint": "run-s lint:prettier lint:eslint", diff --git a/src/__tests__/index.spec.js b/src/__tests__/index.spec.js index e78c61d6..aefecc83 100644 --- a/src/__tests__/index.spec.js +++ b/src/__tests__/index.spec.js @@ -82,7 +82,15 @@ describe('CLI configuration', () => { test('only creates a single CLI instance', () => { const sentryCliPlugin = new SentryCliPlugin({}); - sentryCliPlugin.apply({ hooks: { afterEmit: { tapAsync: jest.fn() } } }); + sentryCliPlugin.apply({ + hooks: { + afterEmit: { tapAsync: jest.fn() }, + make: { tapAsync: jest.fn() }, + }, + options: { + plugins: [], + }, + }); expect(SentryCliMock.mock.instances.length).toBe(1); }); }); @@ -91,20 +99,36 @@ describe('afterEmitHook', () => { let compiler; let compilation; let compilationDoneCallback; + let makeCallback; beforeEach(() => { compiler = { + options: { + plugins: [], + }, hooks: { afterEmit: { tapAsync: jest.fn((name, callback) => callback(compilation, compilationDoneCallback) ), }, + make: { + tapAsync: jest.fn((name, callback) => + callback(compilation, makeCallback) + ), + }, }, }; - compilation = { errors: [], hash: 'someHash' }; + compilation = { + errors: [], + hash: 'someHash', + hooks: { + afterCodeGeneration: { tap: jest.fn() }, + }, + }; compilationDoneCallback = jest.fn(); + makeCallback = jest.fn(); }); test('calls `hooks.afterEmit.tapAsync()`', () => { @@ -121,7 +145,7 @@ describe('afterEmitHook', () => { const sentryCliPlugin = new SentryCliPlugin(); // Simulate Webpack <= 2 - compiler = { plugin: jest.fn() }; + compiler = { plugin: jest.fn(), options: { plugins: [] } }; sentryCliPlugin.apply(compiler); expect(compiler.plugin).toHaveBeenCalledWith( @@ -343,7 +367,10 @@ describe('module rule overrides', () => { beforeEach(() => { sentryCliPlugin = new SentryCliPlugin({ release: '42', include: 'src' }); compiler = { - hooks: { afterEmit: { tapAsync: jest.fn() } }, + hooks: { + afterEmit: { tapAsync: jest.fn() }, + make: { tapAsync: jest.fn() }, + }, options: { module: {} }, }; }); @@ -402,7 +429,10 @@ describe('entry point overrides', () => { beforeEach(() => { sentryCliPlugin = new SentryCliPlugin({ release: '42', include: 'src' }); compiler = { - hooks: { afterEmit: { tapAsync: jest.fn() } }, + hooks: { + afterEmit: { tapAsync: jest.fn() }, + make: { tapAsync: jest.fn() }, + }, options: { module: { rules: [] } }, }; }); diff --git a/src/index.js b/src/index.js index 5bbe7601..22f8d6ef 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ const SentryCli = require('@sentry/cli'); const path = require('path'); const util = require('util'); +const { RawSource } = require('webpack-sources'); const SENTRY_LOADER = path.resolve(__dirname, 'sentry.loader.js'); const SENTRY_MODULE = path.resolve(__dirname, 'sentry-webpack.module.js'); @@ -69,6 +70,46 @@ function attachAfterEmitHook(compiler, callback) { } } +function attachAfterCodeGenerationHook(compiler, options) { + const moduleFederationPlugin = + compiler.options.plugins && + compiler.options.plugins.find( + x => x.constructor.name === 'ModuleFederationPlugin' + ); + + if (!moduleFederationPlugin) { + return; + } + + compiler.hooks.make.tapAsync('SentryCliPlugin', (compilation, cb) => { + options.releasePromise.then(version => { + compilation.hooks.afterCodeGeneration.tap('SentryCliPlugin', () => { + compilation.modules.forEach(module => { + // eslint-disable-next-line no-underscore-dangle + if (module._name !== options.remoteModuleName) return; + const sourceMap = compilation.codeGenerationResults.get(module) + .sources; + const rawSource = sourceMap.get('javascript'); + sourceMap.set( + 'javascript', + new RawSource( + `${rawSource.source()} +(function (){ +var globalThis = (typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}); +globalThis.SENTRY_RELEASES = globalThis.SENTRY_RELEASES || {}; +globalThis.SENTRY_RELEASES["${options.project}@${ + options.org + }"] = {"id":"${version}"}; +})();` + ) + ); + }); + }); + cb(); + }); + }); +} + class SentryCliPlugin { constructor(options = {}) { const defaults = { @@ -299,6 +340,8 @@ class SentryCliPlugin { loader: SENTRY_LOADER, options: { releasePromise: this.release, + org: this.options.org || process.env.SENTRY_ORG, + project: this.options.project || process.env.SENTRY_PROJECT, }, }; @@ -314,6 +357,8 @@ class SentryCliPlugin { loader: SENTRY_LOADER, options: { releasePromise: this.release, + org: this.options.org || process.env.SENTRY_ORG, + project: this.options.project || process.env.SENTRY_PROJECT, }, }, ], @@ -475,6 +520,12 @@ class SentryCliPlugin { this.injectRelease(compilerOptions); } + attachAfterCodeGenerationHook(compiler, { + releasePromise: this.release, + org: this.options.org || process.env.SENTRY_ORG, + project: this.options.project || process.env.SENTRY_PROJECT, + }); + attachAfterEmitHook(compiler, (compilation, cb) => { if (!this.options.include || !this.options.include.length) { ensure(compilerOptions, 'output', Object); diff --git a/src/sentry.loader.js b/src/sentry.loader.js index 95f2634c..3a153be0 100644 --- a/src/sentry.loader.js +++ b/src/sentry.loader.js @@ -1,8 +1,15 @@ module.exports = function sentryLoader(content, map, meta) { - const { releasePromise } = this.query; + const { releasePromise, org, project } = this.query; const callback = this.async(); releasePromise.then(version => { - const sentryRelease = `(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}).SENTRY_RELEASE={id:"${version}"};`; + let sentryRelease = `const _global = (typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}); _global.SENTRY_RELEASE={id:"${version}"};`; + if (project) { + const key = org ? `${project}@${org}` : project; + sentryRelease += ` + _global.SENTRY_RELEASES=_global.SENTRY_RELEASES||{}; + _global.SENTRY_RELEASES["${key}"]={id:"${version}"}; + `; + } callback(null, sentryRelease, map, meta); }); }; diff --git a/yarn.lock b/yarn.lock index 541ba9b5..ba468276 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4785,7 +4785,7 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -source-list-map@^2.0.0: +source-list-map@^2.0.0, source-list-map@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== @@ -5458,6 +5458,14 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-list-map "^2.0.0" source-map "~0.6.1" +webpack-sources@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.0.tgz#9ed2de69b25143a4c18847586ad9eccb19278cfa" + integrity sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ== + dependencies: + source-list-map "^2.0.1" + source-map "^0.6.1" + webpack@^4.39.3: version "4.46.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" From dd76958a47526a83c729990e2179d62fe12b0cd7 Mon Sep 17 00:00:00 2001 From: Hasan Ayan Date: Tue, 13 Jul 2021 01:08:45 +0300 Subject: [PATCH 2/4] fix: remoteEntry module name --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 22f8d6ef..e90b44e1 100644 --- a/src/index.js +++ b/src/index.js @@ -86,7 +86,7 @@ function attachAfterCodeGenerationHook(compiler, options) { compilation.hooks.afterCodeGeneration.tap('SentryCliPlugin', () => { compilation.modules.forEach(module => { // eslint-disable-next-line no-underscore-dangle - if (module._name !== options.remoteModuleName) return; + if (module._name !== moduleFederationPlugin._options.name) return; const sourceMap = compilation.codeGenerationResults.get(module) .sources; const rawSource = sourceMap.get('javascript'); From a3d062e142dc1af67d2c923da543b18648a3ebd1 Mon Sep 17 00:00:00 2001 From: Hasan Ayan Date: Wed, 21 Jul 2021 12:01:29 +0300 Subject: [PATCH 3/4] attachAfterCodeGenerationHook only if it exists --- src/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/index.js b/src/index.js index e90b44e1..394cda30 100644 --- a/src/index.js +++ b/src/index.js @@ -71,7 +71,11 @@ function attachAfterEmitHook(compiler, callback) { } function attachAfterCodeGenerationHook(compiler, options) { + if (!compiler.hooks || !compiler.hooks.make) { + return; + } const moduleFederationPlugin = + compiler.options && compiler.options.plugins && compiler.options.plugins.find( x => x.constructor.name === 'ModuleFederationPlugin' From 6edc8e6556d7b25b53d25ea97e408850c47cc4e3 Mon Sep 17 00:00:00 2001 From: Hasan Ayan Date: Sat, 24 Jul 2021 12:17:53 +0300 Subject: [PATCH 4/4] remove webpack-sources dependency --- package.json | 6 +----- src/index.js | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 72cffe89..02065428 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,6 @@ "dependencies": { "@sentry/cli": "^1.67.2" }, - "peerDependencies": { - "webpack-sources": "*" - }, "devDependencies": { "codecov": "^3.5.0", "eslint": "^5.16.0", @@ -33,8 +30,7 @@ "npm-run-all": "^4.1.5", "prettier": "^1.18.2", "prettier-check": "^2.0.0", - "webpack": "^4.39.3", - "webpack-sources": "^2.3.0" + "webpack": "^4.39.3" }, "scripts": { "lint": "run-s lint:prettier lint:eslint", diff --git a/src/index.js b/src/index.js index 71372094..1c283a81 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,6 @@ const SentryCli = require('@sentry/cli'); const path = require('path'); const util = require('util'); -const { RawSource } = require('webpack-sources'); const SENTRY_LOADER = path.resolve(__dirname, 'sentry.loader.js'); const SENTRY_MODULE = path.resolve(__dirname, 'sentry-webpack.module.js'); @@ -85,6 +84,8 @@ function attachAfterCodeGenerationHook(compiler, options) { return; } + const { RawSource } = require('webpack-sources'); + compiler.hooks.make.tapAsync('SentryCliPlugin', (compilation, cb) => { options.releasePromise.then(version => { compilation.hooks.afterCodeGeneration.tap('SentryCliPlugin', () => {