diff --git a/.changeset/soft-css-sourcemaps.md b/.changeset/soft-css-sourcemaps.md new file mode 100644 index 0000000000..c93d31fe0a --- /dev/null +++ b/.changeset/soft-css-sourcemaps.md @@ -0,0 +1,5 @@ +--- +"@posthog/webpack-plugin": patch +--- + +Include emitted CSS assets with adjacent source maps when processing webpack sourcemaps. diff --git a/packages/webpack-plugin/jest.config.mjs b/packages/webpack-plugin/jest.config.mjs new file mode 100644 index 0000000000..42891d5457 --- /dev/null +++ b/packages/webpack-plugin/jest.config.mjs @@ -0,0 +1,12 @@ +import { createDefaultPreset } from 'ts-jest' + +const tsJestTransformCfg = createDefaultPreset().transform + +/** @type {import('jest').Config} **/ +export default { + testEnvironment: 'node', + testPathIgnorePatterns: ['/node_modules/', '/dist/'], + transform: { + ...tsJestTransformCfg, + }, +} diff --git a/packages/webpack-plugin/package.json b/packages/webpack-plugin/package.json index 8652e2b015..d86f11ea3d 100644 --- a/packages/webpack-plugin/package.json +++ b/packages/webpack-plugin/package.json @@ -34,7 +34,9 @@ "devDependencies": { "@posthog-tooling/tsconfig-base": "workspace:*", "@rslib/core": "catalog:", + "@types/jest": "catalog:", "jest": "catalog:", + "ts-jest": "catalog:", "webpack": "^5" }, "scripts": { diff --git a/packages/webpack-plugin/src/index.ts b/packages/webpack-plugin/src/index.ts index 6e7196e848..6812c12d42 100644 --- a/packages/webpack-plugin/src/index.ts +++ b/packages/webpack-plugin/src/index.ts @@ -58,14 +58,24 @@ export class PosthogWebpackPlugin { return } - const filePaths: string[] = [] + const filePaths = new Set() chunkArray.forEach((chunk) => chunk.files.forEach((file) => { const chunkPath = path.resolve(outputDirectory, file) - filePaths.push(chunkPath) + filePaths.add(chunkPath) }) ) - await runSourcemapCli(config, { filePaths }) + compilation.getAssets().forEach((asset) => { + if (asset.name.endsWith('.css')) { + const mapAssetName = `${asset.name}.map` + if (compilation.getAsset(mapAssetName)) { + filePaths.add(path.resolve(outputDirectory, asset.name)) + filePaths.add(path.resolve(outputDirectory, mapAssetName)) + } + } + }) + + await runSourcemapCli(config, { filePaths: Array.from(filePaths) }) } } diff --git a/packages/webpack-plugin/test/index.spec.ts b/packages/webpack-plugin/test/index.spec.ts new file mode 100644 index 0000000000..4a8901a26f --- /dev/null +++ b/packages/webpack-plugin/test/index.spec.ts @@ -0,0 +1,70 @@ +import path from 'path' +import type webpack from 'webpack' +import { runSourcemapCli } from '@posthog/plugin-utils' +import { PosthogWebpackPlugin } from '../src/index' +import type { ResolvedPluginConfig } from '../src/config' + +jest.mock('@posthog/plugin-utils', () => ({ + runSourcemapCli: jest.fn().mockResolvedValue(undefined), +})) + +const runSourcemapCliMock = runSourcemapCli as jest.MockedFunction + +const config: ResolvedPluginConfig = { + personalApiKey: 'phx_test', + projectId: '1', + host: 'https://us.i.posthog.com', + logLevel: 'info', + cliBinaryPath: 'posthog-cli', + sourcemaps: { + enabled: true, + deleteAfterUpload: true, + }, +} + +type TestAsset = { name: string } +type TestChunk = { files: Set } + +function createCompilation(outputDirectory: string, chunks: TestChunk[], assets: TestAsset[]): webpack.Compilation { + return { + outputOptions: { path: outputDirectory }, + chunks: new Set(chunks), + getAssets: () => assets, + getAsset: (name: string) => assets.find((asset) => asset.name === name), + } as unknown as webpack.Compilation +} + +describe('PosthogWebpackPlugin', () => { + beforeEach(() => { + runSourcemapCliMock.mockClear() + }) + + it('passes emitted CSS assets with adjacent source maps to the sourcemap CLI', async () => { + const outputDirectory = path.resolve('/tmp/posthog-webpack-plugin') + const plugin = new PosthogWebpackPlugin(config, true) + const compilation = createCompilation( + outputDirectory, + [ + { + files: new Set(['static/chunks/app.js', 'static/chunks/app.js.map']), + }, + ], + [ + { name: 'static/css/app.css' }, + { name: 'static/css/app.css.map' }, + { name: 'static/css/no-map.css' }, + ] + ) + + await plugin.processSourceMaps(compilation, config) + + expect(runSourcemapCliMock).toHaveBeenCalledWith(config, { + filePaths: [ + path.resolve(outputDirectory, 'static/chunks/app.js'), + path.resolve(outputDirectory, 'static/chunks/app.js.map'), + path.resolve(outputDirectory, 'static/css/app.css'), + path.resolve(outputDirectory, 'static/css/app.css.map'), + ], + }) + }) +}) diff --git a/packages/webpack-plugin/tsconfig.json b/packages/webpack-plugin/tsconfig.json index 783027a2dc..8283f67fd8 100644 --- a/packages/webpack-plugin/tsconfig.json +++ b/packages/webpack-plugin/tsconfig.json @@ -9,5 +9,6 @@ "declarationMap": true, "moduleResolution": "bundler", "module": "ES6" - } + }, + "include": ["src/**/*.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 17b3005307..5b36b70795 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1598,10 +1598,16 @@ importers: version: link:../../tooling/tsconfig-base '@rslib/core': specifier: 'catalog:' - version: 0.10.6(@microsoft/api-extractor@7.55.1(@types/node@24.10.13))(typescript@5.9.3) + version: 0.10.6(@microsoft/api-extractor@7.55.1(@types/node@22.19.1))(typescript@5.8.2) + '@types/jest': + specifier: 'catalog:' + version: 29.5.14 jest: specifier: 'catalog:' - version: 29.7.0(@types/node@24.10.13)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@24.10.13)(typescript@5.9.3)) + version: 29.7.0(@types/node@22.19.1)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.8.2)) + ts-jest: + specifier: 'catalog:' + version: 29.4.11(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.1)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.8.2)))(typescript@5.8.2) webpack: specifier: ^5 version: 5.102.1(esbuild@0.25.10) @@ -21487,6 +21493,15 @@ snapshots: '@microsoft/api-extractor': 7.55.1(@types/node@22.16.5) typescript: 5.8.2 + '@rslib/core@0.10.6(@microsoft/api-extractor@7.55.1(@types/node@22.19.1))(typescript@5.8.2)': + dependencies: + '@rsbuild/core': 1.4.8 + rsbuild-plugin-dts: 0.10.6(@microsoft/api-extractor@7.55.1(@types/node@22.19.1))(@rsbuild/core@1.4.8)(typescript@5.8.2) + tinyglobby: 0.2.17 + optionalDependencies: + '@microsoft/api-extractor': 7.55.1(@types/node@22.19.1) + typescript: 5.8.2 + '@rslib/core@0.10.6(@microsoft/api-extractor@7.55.1(@types/node@24.10.13))(typescript@5.8.2)': dependencies: '@rsbuild/core': 1.4.8 @@ -33298,6 +33313,18 @@ snapshots: '@microsoft/api-extractor': 7.55.1(@types/node@22.16.5) typescript: 5.8.2 + rsbuild-plugin-dts@0.10.6(@microsoft/api-extractor@7.55.1(@types/node@22.19.1))(@rsbuild/core@1.4.8)(typescript@5.8.2): + dependencies: + '@ast-grep/napi': 0.37.0 + '@rsbuild/core': 1.4.8 + magic-string: 0.30.21 + picocolors: 1.1.1 + tinyglobby: 0.2.17 + tsconfig-paths: 4.2.0 + optionalDependencies: + '@microsoft/api-extractor': 7.55.1(@types/node@22.19.1) + typescript: 5.8.2 + rsbuild-plugin-dts@0.10.6(@microsoft/api-extractor@7.55.1(@types/node@24.10.13))(@rsbuild/core@1.4.8)(typescript@5.8.2): dependencies: '@ast-grep/napi': 0.37.0 @@ -34719,6 +34746,27 @@ snapshots: esbuild: 0.25.10 jest-util: 29.7.0 + ts-jest@29.4.11(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.1)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.8.2)))(typescript@5.8.2): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.9 + jest: 29.7.0(@types/node@22.19.1)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.8.2)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.8.2 + type-fest: 4.41.0 + typescript: 5.8.2 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.28.5 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.5) + esbuild: 0.25.10 + jest-util: 29.7.0 + ts-jest@29.4.11(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@24.10.13)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@24.10.13)(typescript@5.8.2)))(typescript@5.8.2): dependencies: bs-logger: 0.2.6