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

Uglify terser copy #256

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/metro-minify-terser/.npmignore
@@ -0,0 +1,5 @@
**/__mocks__/**
**/__tests__/**
build
src.real
yarn.lock
73 changes: 73 additions & 0 deletions packages/metro-minify-terser/__tests__/minify-test.js
@@ -0,0 +1,73 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @emails oncall+js_foundation
*/
'use strict';

import type {BabelSourceMap} from '@babel/core';

jest.mock('terser', () => ({
minify: jest.fn(code => {
return {
code: code.replace(/(^|\W)\s+/g, '$1'),
map: {},
};
}),
}));

const minify = require('..');
const {objectContaining} = jasmine;

function getFakeMap(): BabelSourceMap {
return {
version: 3,
sources: ['?'],
mappings: '',
names: [],
};
}

describe('Minification:', () => {
const filename = '/arbitrary/file.js';
const code = 'arbitrary(code)';
let map: BabelSourceMap;
let terser;

beforeEach(() => {
terser = require('terser');
terser.minify.mockClear();
terser.minify.mockReturnValue({code: '', map: '{}'});
map = getFakeMap();
});

it('passes file name, code, and source map to `terser`', () => {
minify(code, map, filename);
expect(terser.minify).toBeCalledWith(
code,
objectContaining({
sourceMap: {
content: map,
includeSources: false,
},
}),
);
});

it('returns the code provided by terser', () => {
terser.minify.mockReturnValue({code, map: '{}'});
const result = minify('', getFakeMap(), '');
expect(result.code).toBe(code);
});

it('parses the source map object provided by terser and sets the sources property', () => {
terser.minify.mockReturnValue({map: JSON.stringify(map), code: ''});
const result = minify('', getFakeMap(), filename);
expect(result.map).toEqual({...map, sources: [filename]});
});
});
19 changes: 19 additions & 0 deletions packages/metro-minify-terser/package.json
@@ -0,0 +1,19 @@
{
"name": "metro-minify-terser",
"version": "0.45.3",
"description": "🚇 Alternative minifier for Metro",
"main": "src/index.js",
"repository": {
"type": "git",
"url": "git@github.com:facebook/metro.git"
},
"scripts": {
"prepare-release": "test -d build && rm -rf src.real && mv src src.real && mv build src",
"cleanup-release": "test ! -e build && mv src build && mv src.real src"
},
"license": "MIT",
"dependencies": {
"terser": "^3.1.9"
},
"devDependencies": {}
}
15 changes: 15 additions & 0 deletions packages/metro-minify-terser/src/index.js
@@ -0,0 +1,15 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/

'use strict';

const minifier = require('./minifier');

module.exports = minifier;
74 changes: 74 additions & 0 deletions packages/metro-minify-terser/src/minifier.js
@@ -0,0 +1,74 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/

'use strict';

const terser = require('terser');

import type {
MetroMinifier,
MetroMinifierResult,
MinifyOptions,
} from 'metro/src/shared/types.flow.js';
import type {BabelSourceMap} from '@babel/core';

function minifier(
code: string,
sourceMap: ?BabelSourceMap,
filename: string,
options?: MinifyOptions = {},
): MetroMinifierResult {
const result = minify(code, sourceMap, options);
const map: BabelSourceMap = JSON.parse(result.map);

map.sources = [filename];

return {code: result.code, map};
}

function minify(
inputCode: string,
inputMap: ?BabelSourceMap,
options: MinifyOptions,
) {
const result = terser.minify(inputCode, {
mangle: {
toplevel: false,
reserved: options.reserved,
},
output: {
ascii_only: true,
quote_style: 3,
wrap_iife: true,
},
sourceMap: {
content: inputMap,
includeSources: false,
},
toplevel: false,
compress: {
// reduce_funcs inlines single-use function, which cause perf regressions.
reduce_funcs: false,
},
});

if (result.error) {
throw result.error;
}

return {
code: result.code,
map: result.map,
};
}

const metroMinifier: MetroMinifier = minifier;

module.exports = metroMinifier;
20 changes: 3 additions & 17 deletions packages/metro-minify-uglify/__tests__/minify-test.js
Expand Up @@ -47,7 +47,7 @@ describe('Minification:', () => {
});

it('passes file name, code, and source map to `uglify`', () => {
minify.withSourceMap(code, map, filename);
minify(code, map, filename);
expect(uglify.minify).toBeCalledWith(
code,
objectContaining({
Expand All @@ -59,29 +59,15 @@ describe('Minification:', () => {
);
});

it('passes code to `uglify` when minifying without source map', () => {
minify.noSourceMap(code);
expect(uglify.minify).toBeCalledWith(
code,
objectContaining({
sourceMap: {
content: undefined,
includeSources: false,
},
}),
);
});

it('returns the code provided by uglify', () => {
uglify.minify.mockReturnValue({code, map: '{}'});
const result = minify.withSourceMap('', getFakeMap(), '');
const result = minify('', getFakeMap(), '');
expect(result.code).toBe(code);
expect(minify.noSourceMap('')).toBe(code);
});

it('parses the source map object provided by uglify and sets the sources property', () => {
uglify.minify.mockReturnValue({map: JSON.stringify(map), code: ''});
const result = minify.withSourceMap('', getFakeMap(), filename);
const result = minify('', getFakeMap(), filename);
expect(result.map).toEqual({...map, sources: [filename]});
});
});
4 changes: 0 additions & 4 deletions packages/metro-minify-uglify/src/index.js
Expand Up @@ -12,8 +12,4 @@

const minifier = require('./minifier');

export type {MetroMinifier} from './types.js.flow';
export type {ResultWithMap} from './types.js.flow';
export type {ResultWithoutMap} from './types.js.flow';

module.exports = minifier;
21 changes: 5 additions & 16 deletions packages/metro-minify-uglify/src/minifier.js
Expand Up @@ -14,25 +14,17 @@ const uglify = require('uglify-es');

import type {
MetroMinifier,
ResultWithMap,
ResultWithoutMap,
MetroMinifierResult,
MinifyOptions,
} from './types.js.flow';
} from 'metro/src/shared/types.flow.js';
import type {BabelSourceMap} from '@babel/core';

function noSourceMap(
code: string,
options?: MinifyOptions = {},
): ResultWithoutMap {
return minify(code, undefined, options).code;
}

function withSourceMap(
function minifier(
code: string,
sourceMap: ?BabelSourceMap,
filename: string,
options?: MinifyOptions = {},
): ResultWithMap {
): MetroMinifierResult {
const result = minify(code, sourceMap, options);
const map: BabelSourceMap = JSON.parse(result.map);

Expand Down Expand Up @@ -77,9 +69,6 @@ function minify(
};
}

const metroMinifier: MetroMinifier = {
noSourceMap,
withSourceMap,
};
const metroMinifier: MetroMinifier = minifier;

module.exports = metroMinifier;
41 changes: 0 additions & 41 deletions packages/metro-minify-uglify/src/types.js.flow

This file was deleted.

2 changes: 1 addition & 1 deletion packages/metro/src/JSTransformer/worker.js
Expand Up @@ -323,7 +323,7 @@ async function minifyCode(
const minify = getMinifier(minifierPath);

try {
const minified = minify.withSourceMap(code, sourceMap, filename, options);
const minified = minify(code, sourceMap, filename, options);

return {
code: minified.code,
Expand Down
Expand Up @@ -12,11 +12,9 @@
jest
.mock('../constant-folding-plugin')
.mock('../inline-plugin')
.mock('../../../lib/getMinifier', () => () => ({
withSourceMap: (code, map) => ({
code: code.replace('arbitrary(code)', 'minified(code)'),
map,
}),
.mock('../../../lib/getMinifier', () => () => (code, map) => ({
code: code.replace('arbitrary(code)', 'minified(code)'),
map,
}))
.mock('metro-minify-uglify');

Expand Down
2 changes: 1 addition & 1 deletion packages/metro/src/lib/getMinifier.js
Expand Up @@ -10,7 +10,7 @@

'use strict';

import type {MetroMinifier} from 'metro-minify-uglify';
import type {MetroMinifier} from '../shared/types.flow.js';

function getMinifier(minifierPath: string): MetroMinifier {
// Note: minifierPath should be an absolute path OR a module name here!
Expand Down
17 changes: 17 additions & 0 deletions packages/metro/src/shared/types.flow.js
Expand Up @@ -9,6 +9,8 @@
*/
'use strict';

import type {BabelSourceMap} from '@babel/core';
import type {MinifyOptions} from '../JSTransformer/worker';
import type {TransformResult} from '../DeltaBundler';
import type {CustomTransformOptions} from '../JSTransformer/worker';
import type {DynamicRequiresBehavior} from '../ModuleGraph/worker/collectDependencies';
Expand Down Expand Up @@ -160,3 +162,18 @@ export type RequestOptions = {|
createModuleIdFactory?: () => (path: string) => number,
onProgress?: (transformedFileCount: number, totalFileCount: number) => void,
|};

export type {MinifyOptions};

export type MetroMinifierResult = {
code: string,
map: BabelSourceMap,
options?: MinifyOptions,
};

export type MetroMinifier = (
code: string,
inputMap?: ?BabelSourceMap,
filename: string,
options?: MinifyOptions,
) => MetroMinifierResult;