Skip to content

Commit

Permalink
fix(core): remove pure markers from js module output (#2936)
Browse files Browse the repository at this point in the history
* test(webpack): check js module tree-shake
* test(rollup): check js module tree-shake
* test(esbuild): check js module tree-shake
* chore: remove unneeded pure functions markers from generated js module
  • Loading branch information
idoros authored Jan 14, 2024
1 parent 888c5c1 commit 0ff9c3f
Show file tree
Hide file tree
Showing 16 changed files with 270 additions and 5 deletions.
8 changes: 4 additions & 4 deletions packages/core/src/stylable-js-module-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ ${runtimeImport(moduleType, runtimeRequest, injectOptions)}
${header}
${varType} _namespace_ = ${JSON.stringify(namespace)};
${varType} _style_ = /*#__PURE__*/ classesRuntime.bind(null, _namespace_);
${varType} _style_ = classesRuntime.bind(null, _namespace_);
${exportKind}cssStates = /*#__PURE__*/ statesRuntime.bind(null, _namespace_);
${exportKind}style = /*#__PURE__*/ _style_;
${exportKind}st = /*#__PURE__*/ _style_;
${exportKind}cssStates = statesRuntime.bind(null, _namespace_);
${exportKind}style = _style_;
${exportKind}st = _style_;
${exportKind}namespace = _namespace_;
${exportKind}classes = ${JSON.stringify(classes)};
Expand Down
26 changes: 26 additions & 0 deletions packages/esbuild/test/e2e/tree-shake/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const { stylablePlugin } = require('@stylable/esbuild');
const { rmSync, existsSync } = require('node:fs');
const { join } = require('node:path');

module.exports.cssInJsDev = (build, options) => run('js', build, options);
module.exports.cssBundleProd = (build, options) => run('css', build, options);

function run(cssInjection, build, options) {
const outdir = cssInjection === 'css' ? 'dist-bundle' : 'dist';
const path = join(__dirname, outdir);
if (existsSync(path)) {
rmSync(path, { recursive: true, force: true });
}
return build({
...options({
entryPoints: ['./index'],
plugins: [
stylablePlugin({
mode: cssInjection === 'css' ? 'production' : 'development',
cssInjection,
}),
],
}),
outdir,
});
}
13 changes: 13 additions & 0 deletions packages/esbuild/test/e2e/tree-shake/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/dist/" />
<title>tree-shake</title>
</head>
<body>
<script type="module" src="index.js"></script>
</body>
</html>
2 changes: 2 additions & 0 deletions packages/esbuild/test/e2e/tree-shake/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { classes } from './index.st.css';
document.body.innerHTML = `<div class="${classes.bbb}">bbb used</div>`;
26 changes: 26 additions & 0 deletions packages/esbuild/test/e2e/tree-shake/index.st.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.aaa {}

.bbb {}

.ccc {
-st-states: stateX;
container-name: containerX;
}

@property --propX;

@keyframes keyframesX {
0% {
color: red;
}

100% {
color: blue;
}
}

:vars {
varX: 1px;
}

@layer layerX;
12 changes: 12 additions & 0 deletions packages/esbuild/test/e2e/tree-shake/stylable.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { createNamespaceStrategyNode } = require('@stylable/node');

module.exports = {
defaultConfig() {
return {
resolveNamespace: createNamespaceStrategyNode({
hashFragment: 'minimal',
strict: true,
}),
};
},
};
23 changes: 23 additions & 0 deletions packages/esbuild/test/e2e/tree-shake/tree-shake.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { expect } from 'chai';
import { ESBuildTestKit } from '../esbuild-testkit';

describe('Stylable ESBuild plugin - tree-shake', () => {
const tk = new ESBuildTestKit({
log: false,
launchOptions: {
headless: true,
},
});
afterEach(() => tk.dispose());

it('should not include unused js', async () => {
const { read } = await tk.build({ project: 'tree-shake', buildExport: 'cssBundleProd' });
const bundledJS = read('dist-bundle/index.js');

expect(bundledJS, 'keyframes').to.not.include('keyframesX');
expect(bundledJS, 'stVars').to.not.include('varX');
expect(bundledJS, 'vars').to.not.include('propX');
expect(bundledJS, 'layers').to.not.include('layerX');
expect(bundledJS, 'containers').to.not.include('containerX');
});
});
2 changes: 2 additions & 0 deletions packages/rollup-plugin/test/projects/tree-shake/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { classes } from './index.st.css';
document.body.innerHTML = `<div class="${classes.bbb}">bbb used</div>`;
27 changes: 27 additions & 0 deletions packages/rollup-plugin/test/projects/tree-shake/index.st.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.aaa {}

.bbb {}

.ccc {
-st-states: stateX;
container-name: containerX;
}

@property --propX;

@keyframes keyframesX {
0% {
color: red;
}

100% {
color: blue;
}
}

:vars {
varX: 1px;
}

@layer layerX;

4 changes: 4 additions & 0 deletions packages/rollup-plugin/test/projects/tree-shake/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "test-tree-shake",
"version": "0.0.0-test"
}
40 changes: 40 additions & 0 deletions packages/rollup-plugin/test/rollup-tree-shake.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { expect } from 'chai';
import { rollupRunner } from './test-kit/rollup-runner';
import { getProjectPath } from './test-kit/test-helpers';

describe('StylableRollupPlugin - tree-shake', function () {
this.timeout(30000);

const project = 'tree-shake';

const runner = rollupRunner({
projectPath: getProjectPath(project),
entry: './index.js',
pluginOptions: {
stylableConfig(config) {
config.mode = 'production';
// keep namespace with no hash for test expectations
config.resolveNamespace = (namespace) => namespace;
return config;
},
includeGlobalSideEffects: true,
},
rollupOptions: {
treeshake: 'smallest',
},
});

it('should not include unused js', async () => {
const { ready, getOutputFiles } = runner;

await ready;
const outputFiles = getOutputFiles();
const bundledJS = outputFiles['index.js'];

expect(bundledJS, 'keyframes').to.not.include('keyframesX');
expect(bundledJS, 'stVars').to.not.include('varX');
expect(bundledJS, 'vars').to.not.include('propX');
expect(bundledJS, 'layers').to.not.include('layerX');
expect(bundledJS, 'containers').to.not.include('containerX');
});
});
5 changes: 4 additions & 1 deletion packages/rollup-plugin/test/test-kit/rollup-runner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import nodeResolve from '@rollup/plugin-node-resolve';
import { RollupWatcherEvent, watch } from 'rollup';
import { RollupWatchOptions, RollupWatcherEvent, watch } from 'rollup';
import { loadDirSync, runServer } from '@stylable/e2e-test-kit';
import playwright from 'playwright-core';
import { stylableRollupPlugin, StylableRollupPluginOptions } from '@stylable/rollup-plugin';
Expand All @@ -17,6 +17,7 @@ export interface RollupRunnerOptions {
nodeModulesPath?: string;
entry?: string;
pluginOptions?: StylableRollupPluginOptions;
rollupOptions?: RollupWatchOptions;
}
const rootNodeModulesFromHere = join(
dirname(require.resolve('../../../../../package.json')),
Expand All @@ -27,6 +28,7 @@ export function rollupRunner({
nodeModulesPath = rootNodeModulesFromHere,
entry = 'index.js',
pluginOptions,
rollupOptions,
}: RollupRunnerOptions) {
const {
context,
Expand Down Expand Up @@ -58,6 +60,7 @@ export function rollupRunner({
}),
html({}),
],
...(rollupOptions || {}),
});
const ready = waitForWatcherFinish(watcher);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { classes } from './index.st.css';
document.body.innerHTML = `<div class="${classes.bbb}">bbb used</div>`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.aaa {}

.bbb {}

.ccc {
-st-states: stateX;
container-name: containerX;
}

@property --propX;

@keyframes keyframesX {
0% {
color: red;
}

100% {
color: blue;
}
}

:vars {
varX: 1px;
}

@layer layerX;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { StylableWebpackPlugin } = require('@stylable/webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/** @type {import('webpack').Configuration} */
module.exports = {
mode: 'production',
context: __dirname,
devtool: 'source-map',
plugins: [
new StylableWebpackPlugin({
optimize: {
removeUnusedComponents: true,
removeComments: true,
classNameOptimizations: false,
shortNamespaces: false,
removeEmptyNodes: true,
minify: true,
},
stylableConfig(config) {
return {
...config,
resolveNamespace(namespace) {
return namespace;
},
};
},
}),
new HtmlWebpackPlugin(),
],
};
29 changes: 29 additions & 0 deletions packages/webpack-plugin/test/e2e/tree-shake.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { StylableProjectRunner } from '@stylable/e2e-test-kit';
import { expect } from 'chai';
import { dirname } from 'path';

const project = 'tree-shake';
const projectDir = dirname(
require.resolve(`@stylable/webpack-plugin/test/e2e/projects/${project}/webpack.config`)
);

describe(`(${project})`, () => {
const projectRunner = StylableProjectRunner.mochaSetup(
{
projectDir,
launchOptions: {
// headless: false,
},
},
before,
afterEach,
after
);

it('should inline classes and remove the stylesheet js module', () => {
const files = projectRunner.getProjectFiles();
expect(files['dist/main.js']).to.eql(
`(()=>{"use strict";document.body.innerHTML='<div class="index__bbb">bbb used</div>'})();\n//# sourceMappingURL=main.js.map`
);
});
});

0 comments on commit 0ff9c3f

Please sign in to comment.