Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat): closure compiler for minification #525

Closed
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ export interface TsdxOptions {
writeMeta?: boolean;
// Only transpile, do not type check (makes compilation faster)
transpileOnly?: boolean;
// EXPERIMENTAL: Use closure compiler to minify production bundle instead of terser
closureCompiler?: boolean;
}
```

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"templates"
],
"dependencies": {
"@ampproject/rollup-plugin-closure-compiler": "^0.22.2",
"@babel/core": "^7.4.4",
"@babel/helper-module-imports": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.4.4",
Expand Down
27 changes: 15 additions & 12 deletions src/createRollupConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { safeVariableName, safePackageName, external } from './utils';
import { paths } from './constants';
import { RollupOptions } from 'rollup';
import { terser } from 'rollup-plugin-terser';
import closureCompiler from '@ampproject/rollup-plugin-closure-compiler';
import { DEFAULT_EXTENSIONS } from '@babel/core';
// import babel from 'rollup-plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
Expand Down Expand Up @@ -194,18 +195,20 @@ export async function createRollupConfig(
// printInfo: false,
// }),
shouldMinify &&
terser({
sourcemap: true,
output: { comments: false },
compress: {
keep_infinity: true,
pure_getters: true,
passes: 10,
},
ecma: 5,
toplevel: opts.format === 'cjs',
warnings: true,
}),
(opts.closureCompiler
? closureCompiler()
: terser({
sourcemap: true,
output: { comments: false },
compress: {
keep_infinity: true,
pure_getters: true,
passes: 10,
},
ecma: 5,
toplevel: opts.format === 'cjs',
warnings: true,
})),
],
};
}
2 changes: 2 additions & 0 deletions src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ declare module '@babel/core' {
}

// Rollup plugins
declare module '@ampproject/rollup-plugin-closure-compiler';
declare module '@jaredpalmer/rollup-plugin-preserve-shebang';
ambroseus marked this conversation as resolved.
Show resolved Hide resolved
declare module 'rollup-plugin-babel';
declare module 'rollup-plugin-size-snapshot';
declare module 'rollup-plugin-terser';
Expand Down
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,11 @@ prog
.example('build --tsconfig ./tsconfig.foo.json')
.option('--transpileOnly', 'Skip type checking')
.example('build --transpileOnly')
.option(
'--closureCompiler',
'EXPERIMENTAL: Use closure compiler to minify production bundle instead of terser'
)
.example('build --closureCompiler')
.option(
'--extractErrors',
'Extract errors to ./errors/codes.json and provide a url for decoding.'
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export interface TsdxOptions extends SharedOpts {
writeMeta?: boolean;
// Only transpile, do not type check (makes compilation faster)
transpileOnly?: boolean;
// EXPERIMENTAL: Use closure compiler to minify production bundle instead of terser
closureCompiler?: boolean;
}

export interface PackageJson {
Expand Down
7 changes: 7 additions & 0 deletions test/integration/fixtures/build-withClosure/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"scripts": {
"build": "tsdx build"
},
"name": "build-withclosure",
"license": "MIT"
}
11 changes: 11 additions & 0 deletions test/integration/fixtures/build-withClosure/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const split = (str: string) => str.split('');

const sum = (a: number, b: number) => {
return a + b;
};

const bar = split('bar');

// this line gets minified differently with
// Terser vs. Closure vs. Closure ADVANCED_OPTIMIZATIONS
export const signature = `${split('bar').join('')} ${sum(bar.length, -3)}`;
28 changes: 28 additions & 0 deletions test/integration/fixtures/build-withClosure/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"module": "ESNext",
"lib": ["dom", "esnext"],
"declaration": true,
"sourceMap": true,
"rootDir": "./src",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"*": ["src/*", "node_modules/*"]
},
"jsx": "react",
"esModuleInterop": true
},
"include": ["src", "types"],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const closureCompiler = require('@ampproject/rollup-plugin-closure-compiler');

const closureCompilerPlugin = closureCompiler({
compilation_level: 'ADVANCED_OPTIMIZATIONS',
});

module.exports = {
rollup(config) {
config.plugins = config.plugins.map(plugin => {
// override closure compiler plugin's default config
if (plugin && plugin.name === closureCompilerPlugin.name) {
return closureCompilerPlugin;
}
return plugin;
});

return config;
},
};
76 changes: 76 additions & 0 deletions test/integration/tsdx-build-withClosure.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as shell from 'shelljs';
import * as util from '../utils/fixture';
import { grep } from '../utils/shell';

shell.config.silent = false;

const testDir = 'integration';
const fixtureName = 'build-withClosure';
const stageName = `stage-integration-${fixtureName}`;

describe('integration :: tsdx build :: --closureCompiler', () => {
beforeAll(() => {
util.teardownStage(stageName);
});
beforeEach(() => {
util.setupStageWithFixture(testDir, stageName, fixtureName);
});

it('should minify bundle with default options', () => {
let output = shell.exec('node ../dist/index.js build --closureCompiler');
expect(output.code).toBe(0);

expect(shell.test('-f', 'dist/index.js')).toBeTruthy();
expect(shell.test('-f', 'dist/index.d.ts')).toBeTruthy();
expect(
shell.test('-f', 'dist/build-withclosure.cjs.development.js')
).toBeTruthy();
expect(
shell.test('-f', 'dist/build-withclosure.cjs.production.min.js')
).toBeTruthy();
expect(shell.test('-f', 'dist/build-withclosure.esm.js')).toBeTruthy();

const lib = require(`../../${stageName}/dist`);
expect(lib.signature).toBe('bar 0');

// with SIMPLE optimization level minified bundle should contain
// simplePattern 'exports.signature=signature'
expect(
grep(/exports\.signature=signature/, [
'dist/build-withclosure.cjs.production.min.js',
])
).toBeTruthy();
});

it('should minify bundle with advanced options', () => {
shell.mv('-f', 'tsdx.config.closure-advanced.js', 'tsdx.config.js');

const output = shell.exec('node ../dist/index.js build --closureCompiler');
expect(output.code).toBe(0);

expect(shell.test('-f', 'dist/index.js')).toBeTruthy();
expect(shell.test('-f', 'dist/index.d.ts')).toBeTruthy();
expect(
shell.test('-f', 'dist/build-withclosure.cjs.development.js')
).toBeTruthy();
expect(
shell.test('-f', 'dist/build-withclosure.cjs.production.min.js')
).toBeTruthy();
expect(shell.test('-f', 'dist/build-withclosure.esm.js')).toBeTruthy();

const lib = require(`../../${stageName}/dist`);
expect(lib.signature).toBe('bar 0');

// with ADVANCED optimization level minified bundle should contain
// advancedPattern 'exports.a="bar 0"'
expect(
grep(/exports\.a="bar 0"/, [
ambroseus marked this conversation as resolved.
Show resolved Hide resolved
'dist/build-withclosure.cjs.production.min.js',
])
).toBeTruthy();
});

afterEach(() => {
util.teardownStage(stageName);
});
});
Loading