import { join } from 'path'; import { transformSync } from '@babel/core'; import compiledBabelPlugin from '@compiled/babel-plugin'; import { format } from 'prettier'; import stripRuntimeBabelPlugin from '../index'; const testStyleSheetPath = '@compiled/webpack-loader/css-loader!@compiled/webpack-loader/css-loader/compiled-css.css'; const regexToFindRequireStatements = /(require\('@compiled\/webpack-loader\/css-loader!@compiled\/webpack-loader\/css-loader\/compiled-css\.css\?style=.*;)/g; const testSSR = true; const transform = ( code: string, opts: { modules?: boolean; styleSheetPath?: string; compiledRequireExclude?: boolean; development?: boolean; processJsxDev?: boolean; runtime: 'automatic' | 'classic'; } ): string => { const { modules, styleSheetPath, compiledRequireExclude, development, processJsxDev, runtime } = opts; const filename = join(__dirname, 'app.tsx'); const initialFileResult = transformSync(code, { babelrc: false, configFile: false, filename, plugins: [[compiledBabelPlugin, { optimizeCss: false, collisionResistantHash: true }]], presets: [ ['@babel/preset-env', { targets: { esmodules: true }, modules: modules ?? 'auto' }], '@babel/preset-typescript', ['@babel/preset-react', { development, runtime, useBuiltIns: true }], ], }); if (!initialFileResult || !initialFileResult.code) { throw new Error(`Missing initial fileResult: ${initialFileResult}`); } const fileResult = transformSync(initialFileResult.code, { babelrc: false, configFile: false, filename, plugins: [[stripRuntimeBabelPlugin, { styleSheetPath, compiledRequireExclude, processJsxDev }]], }); if (!fileResult || !fileResult.code) { throw new Error(`Missing fileResult: ${fileResult}`); } return format(fileResult.code, { parser: 'babel', singleQuote: true, }); }; // This test suite is designed to test transpiled code, which is often found in third-party node_modules dependencies describe('babel-plugin-strip-runtime using transpiled code', () => { const code = ` import '@compiled/react'; const Component = () => (
hello world
); `; describe('with the automatic runtime', () => { const runtime = 'automatic'; it('adds require statement for every found style', () => { const actual = transform(code, { styleSheetPath: testStyleSheetPath, runtime }); expect(actual.match(regexToFindRequireStatements)).toEqual([ `require('${testStyleSheetPath}?style=._4ya3eErjyG%7Bfont-size%3A12px%7D');`, `require('${testStyleSheetPath}?style=._1UtDYzynoA%7Bcolor%3Ablue%7D');`, ]); }); it('does not add require statement in a node environment', () => { const actual = transform(code, { styleSheetPath: testStyleSheetPath, compiledRequireExclude: testSSR, runtime, }); expect(actual.match(regexToFindRequireStatements)).toEqual(null); }); it('strips the css prop runtime when using transformed modules', () => { const actual = transform(code, { runtime: 'automatic' }); expect(actual.split('var Component = ')[1]).toMatchInlineSnapshot(` "() => /*#__PURE__*/ (0, _jsxRuntime.jsx)('div', { className: (0, _runtime.ax)(['_4ya3eErjyG _1UtDYzynoA']), children: 'hello world', }); " `); }); it('strips the css prop runtime when using untransformed modules', () => { const actual = transform(code, { modules: false, runtime }); expect(actual).toMatchInlineSnapshot(` "/* app.tsx generated by @compiled/babel-plugin v0.0.0 */ import * as React from 'react'; import { ax, ix } from '@compiled/react/runtime'; import { jsxs as _jsxs, jsx as _jsx } from 'react/jsx-runtime'; var Component = () => /*#__PURE__*/ _jsx('div', { className: ax(['_4ya3eErjyG _1UtDYzynoA']), children: 'hello world', }); " `); }); it('leaves development transform handling disabled by default', () => { const actual = transform(code, { development: true, runtime, styleSheetPath: testStyleSheetPath, }); expect(actual).toContain('jsxDEV'); expect(actual.match(regexToFindRequireStatements)).toBeNull(); }); it('extracts styles and strips the css prop runtime when development handling is enabled', () => { const actual = transform(code, { development: true, processJsxDev: true, runtime, styleSheetPath: testStyleSheetPath, }); expect(actual).not.toContain('CS'); expect(actual).not.toContain('CC'); expect(actual).toContain('jsxDEV'); expect(actual.match(regexToFindRequireStatements)).toEqual([ `require('${testStyleSheetPath}?style=._4ya3eErjyG%7Bfont-size%3A12px%7D');`, `require('${testStyleSheetPath}?style=._1UtDYzynoA%7Bcolor%3Ablue%7D');`, ]); }); }); describe('with the classic runtime', () => { const runtime = 'classic'; it('adds require statement for every found style', () => { const actual = transform(code, { styleSheetPath: testStyleSheetPath, runtime }); expect(actual.match(regexToFindRequireStatements)).toEqual([ `require('${testStyleSheetPath}?style=._4ya3eErjyG%7Bfont-size%3A12px%7D');`, `require('${testStyleSheetPath}?style=._1UtDYzynoA%7Bcolor%3Ablue%7D');`, ]); }); it('does not add require statement in a node environment', () => { const actual = transform(code, { styleSheetPath: testStyleSheetPath, compiledRequireExclude: testSSR, runtime, }); expect(actual.match(regexToFindRequireStatements)).toEqual(null); }); it('strips the css prop runtime when using transformed modules', () => { const actual = transform(code, { runtime }); expect(actual.split('var Component = ')[1]).toMatchInlineSnapshot(` "() => /*#__PURE__*/ React.createElement( 'div', { className: (0, _runtime.ax)(['_4ya3eErjyG _1UtDYzynoA']), }, 'hello world' ); " `); }); it('strips the css prop runtime when using untransformed modules', () => { const actual = transform(code, { modules: false, runtime }); expect(actual).toMatchInlineSnapshot(` "/* app.tsx generated by @compiled/babel-plugin v0.0.0 */ import * as React from 'react'; import { ax, ix } from '@compiled/react/runtime'; var Component = () => /*#__PURE__*/ React.createElement( 'div', { className: ax(['_4ya3eErjyG _1UtDYzynoA']), }, 'hello world' ); " `); }); }); });