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'
);
"
`);
});
});
});