Import Upstream version 7.0.2+~5.0.1
This commit is contained in:
commit
2a6dbef7ee
|
@ -0,0 +1 @@
|
|||
node_modules
|
|
@ -0,0 +1,5 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "14"
|
||||
- "12"
|
||||
- "10"
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright 2018 Bogdan Chadkin <trysound@yandex.ru>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,106 @@
|
|||
# rollup-plugin-terser [![Travis Build Status][travis-img]][travis]
|
||||
|
||||
[travis-img]: https://travis-ci.org/TrySound/rollup-plugin-terser.svg
|
||||
[travis]: https://travis-ci.org/TrySound/rollup-plugin-terser
|
||||
|
||||
[Rollup](https://github.com/rollup/rollup) plugin to minify generated es bundle. Uses [terser](https://github.com/fabiosantoscode/terser) under the hood.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
yarn add rollup-plugin-terser --dev
|
||||
# Or with npm:
|
||||
npm i rollup-plugin-terser --save-dev
|
||||
```
|
||||
|
||||
_Note: this package requires rollup@0.66 and higher (including rollup@2.0.0)_
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import { rollup } from "rollup";
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
|
||||
rollup({
|
||||
input: "main.js",
|
||||
plugins: [terser()],
|
||||
});
|
||||
```
|
||||
|
||||
## Why named export?
|
||||
|
||||
1. Module is a namespace. Default export often leads to function/component per file dogma and makes code less maintainable.
|
||||
2. Interop with commonjs is broken in many cases or hard to maintain.
|
||||
3. Show me any good language with default exports. It's historical javascriptism.
|
||||
|
||||
## Options
|
||||
|
||||
> ⚠️ **Caveat:** any function used in options object cannot rely on its surrounding scope, since it is executed in an isolated context.
|
||||
|
||||
```js
|
||||
terser(options);
|
||||
```
|
||||
|
||||
`options` - [terser API options](https://github.com/fabiosantoscode/terser#minify-options)
|
||||
|
||||
Note: some terser options are set by the plugin automatically:
|
||||
|
||||
- `module: true` is set when `format` is `esm` or `es`
|
||||
- `toplevel: true` is set when `format` is `cjs`
|
||||
|
||||
`options.numWorkers: number`
|
||||
|
||||
Amount of workers to spawn. Defaults to the number of CPUs minus 1.
|
||||
|
||||
## Examples
|
||||
|
||||
### Using as output plugin
|
||||
|
||||
```js
|
||||
// rollup.config.js
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
|
||||
export default {
|
||||
input: "index.js",
|
||||
output: [
|
||||
{ file: "lib.js", format: "cjs" },
|
||||
{ file: "lib.min.js", format: "cjs", plugins: [terser()] },
|
||||
{ file: "lib.esm.js", format: "esm" },
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Comments
|
||||
|
||||
If you'd like to preserve comments (for licensing for example), then you can specify a function to do this like so:
|
||||
|
||||
```js
|
||||
terser({
|
||||
output: {
|
||||
comments: function (node, comment) {
|
||||
var text = comment.value;
|
||||
var type = comment.type;
|
||||
if (type == "comment2") {
|
||||
// multiline comment
|
||||
return /@preserve|@license|@cc_on/i.test(text);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Alternatively, you can also choose to keep all comments (e.g. if a licensing header has already been prepended by a previous rollup plugin):
|
||||
|
||||
```js
|
||||
terser({
|
||||
output: {
|
||||
comments: "all",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
See [Terser documentation](https://github.com/fabiosantoscode/terser#terser) for further reference.
|
||||
|
||||
# License
|
||||
|
||||
MIT © [Bogdan Chadkin](mailto:trysound@yandex.ru)
|
|
@ -0,0 +1,5 @@
|
|||
.DS_Store
|
||||
.nyc_output/
|
||||
coverage/
|
||||
node_modules/
|
||||
package-lock.json
|
|
@ -0,0 +1,8 @@
|
|||
.nyc_output/*
|
||||
coverage/*
|
||||
node_modules/*
|
||||
test/*
|
||||
.gitignore
|
||||
.travis.yml
|
||||
test.js
|
||||
package-lock.json
|
|
@ -0,0 +1,11 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- stable
|
||||
git:
|
||||
depth: 1
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^greenkeeper/.*$/
|
||||
after_success:
|
||||
- "npm run coveralls"
|
|
@ -0,0 +1,15 @@
|
|||
ISC License
|
||||
|
||||
Copyright (c) 2017, Andrea Giammarchi, @WebReflection
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,107 @@
|
|||
# ascjs
|
||||
|
||||
[![License: ISC](https://img.shields.io/badge/License-ISC-yellow.svg)](https://opensource.org/licenses/ISC) [![Build Status](https://travis-ci.org/WebReflection/ascjs.svg?branch=master)](https://travis-ci.org/WebReflection/ascjs) [![Coverage Status](https://coveralls.io/repos/github/WebReflection/ascjs/badge.svg?branch=master)](https://coveralls.io/github/WebReflection/ascjs?branch=master) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/WebReflection/donate) [![Greenkeeper badge](https://badges.greenkeeper.io/WebReflection/ascjs.svg)](https://greenkeeper.io/)
|
||||
|
||||
ES2015 to CommonJS import/export transformer
|
||||
|
||||
- - -
|
||||
|
||||
### Looking for a CommonJS minimalistic bundler ?
|
||||
|
||||
Fully based on _ascjs_, **[asbundle](https://github.com/WebReflection/asbundle)** is a no-brainer to create out of the box browser compatible bundles. Don't miss it out!
|
||||
|
||||
- - -
|
||||
|
||||
This module does one thing only:
|
||||
it loosely transpiles **ES2015** [import](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import)/[export](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) statements **into** valid **CommonJS** in order to fix the only part of Node that's incompatible with modern JS.
|
||||
|
||||
## How to
|
||||
|
||||
You can use _ascjs_ as binary utility or as module.
|
||||
|
||||
```sh
|
||||
npm install -g ascjs
|
||||
|
||||
# to see what you can do
|
||||
ascjs --help
|
||||
|
||||
```
|
||||
|
||||
As executable, you can use _ascjs_ to output, or save, some code content.
|
||||
```sh
|
||||
ascjs code
|
||||
ascjs --ignore=a.js,b.js sourceFile
|
||||
ascjs --no-default
|
||||
ascjs sourceFile
|
||||
ascjs sourceFile destFile
|
||||
|
||||
# folders are recursively parsed
|
||||
# destFolder is mandatory
|
||||
ascjs sourceFolder destFolder
|
||||
```
|
||||
|
||||
You can also use it via pipe operator.
|
||||
```sh
|
||||
echo code | ascjs
|
||||
cat source.js | ascjs | uglifyjs -o dest.js
|
||||
```
|
||||
|
||||
As module, you can require it and use it to convert ESM to CJS.
|
||||
```js
|
||||
const ascjs = require('ascjs');
|
||||
|
||||
ascjs('import "test";');
|
||||
// require("test");
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
* extremely lightweight, based on [babylon](https://github.com/babel/babylon) for performance and reliability, it transforms only imports/exports ignoring everything else
|
||||
* produces modern JavaScript, you are in charge of extra transformations if needed
|
||||
* indentation, spaces, semi or no-semi are preserved: beautiful source code remains beautiful
|
||||
* uses same [Babel](http://babeljs.io) convention, resolving `export default ...` intent as `exports.default`
|
||||
* you can finally write `.js` code and transform it for Node only before publishing on _npm_
|
||||
* you could write `.mjs` modules and transform them into CommonJS for [Browserify](http://browserify.org) or other bundlers as target
|
||||
|
||||
### Constrains
|
||||
|
||||
* live bindings for exported values are not preserved. You need to delegate in scope eventual changes
|
||||
* dynamic `import(...)` is untouched. If you write that, let [Webpack](https://webpack.js.org) handle it for you later on
|
||||
* there is no magic whatsoever in module names resolution, what you write in ESM is what you get as CJS
|
||||
|
||||
### Flags
|
||||
|
||||
* `--ignore=...` a comma separated paths to ignore parsing
|
||||
* `--no-default` remove the `__esModule` flag and export default via `module.exports = `
|
||||
|
||||
### Example
|
||||
This module can transform the following ES2015+ code
|
||||
```js
|
||||
import func, {a, b} from './module.js';
|
||||
import * as tmp from 'other';
|
||||
|
||||
const val = 123;
|
||||
|
||||
export default function test() {
|
||||
console.log('ascjs');
|
||||
};
|
||||
|
||||
export {func, val};
|
||||
```
|
||||
into the following one:
|
||||
```js
|
||||
'use strict';
|
||||
const func = (m => m.__esModule ? m.default : m)(require('./module.js'));
|
||||
const {a, b} = require('./module.js');
|
||||
const tmp = require('other');
|
||||
|
||||
const val = 123;
|
||||
|
||||
function test() {
|
||||
console.log('ascjs');
|
||||
}
|
||||
Object.defineProperty(exports, '__esModule', {value: true}).default = test;
|
||||
|
||||
exports.func = func;
|
||||
exports.val = val;
|
||||
```
|
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const path = require('path');
|
||||
const $ascjs = require('./index.js');
|
||||
const ascjs = input => {
|
||||
const output = $ascjs(input);
|
||||
return noDefault ?
|
||||
output.replace(`${$ascjs.EXPORT}.default`, 'module.exports') :
|
||||
output;
|
||||
};
|
||||
|
||||
const argv = process.argv.slice(2);
|
||||
const files = argv.filter(arg => /^[^-]/.test(arg));
|
||||
const options = argv.filter(arg => /^-/.test(arg));
|
||||
|
||||
let noDefault = false;
|
||||
const ignore = [];
|
||||
options.forEach(arg => {
|
||||
if (/^--no-default$/.test(arg))
|
||||
noDefault = true;
|
||||
else if (/^--ignore=/.test(arg))
|
||||
ignore.push.apply(
|
||||
ignore,
|
||||
arg.slice(9).replace(/^('|")|('|")$/g, '').split(',')
|
||||
.map(file => path.resolve(__dirname, file))
|
||||
);
|
||||
});
|
||||
|
||||
const source = files[0];
|
||||
if (files.length < 1 && options.length) {
|
||||
const info = require('./package.json');
|
||||
console.log(`
|
||||
\x1B[1mascjs\x1B[0m v${info.version}
|
||||
${'-'.repeat(info.description.length)}
|
||||
${info.description}
|
||||
${'-'.repeat(info.description.length)}
|
||||
|
||||
# as executable
|
||||
ascjs code
|
||||
ascjs --ignore=a.js,b.js sourceFile
|
||||
ascjs --no-default
|
||||
ascjs sourceFile destFile
|
||||
ascjs sourceFolder destFolder # dest is required
|
||||
|
||||
# as pipe
|
||||
echo code | ascjs
|
||||
cat sourceFile | ascjs
|
||||
|
||||
${'-'.repeat(info.description.length)}
|
||||
${' '.repeat(info.description.length)
|
||||
.slice(0, -(3 + info.author.length))}by ${info.author}
|
||||
`);
|
||||
} else if (files.length) {
|
||||
const fs = require('fs');
|
||||
const dest = files[1];
|
||||
fs.stat(source, (err, stat) => {
|
||||
if (err) {
|
||||
process.stdout.write(ascjs(source));
|
||||
} else if (stat.isFile()) {
|
||||
fs.readFile(source, (err, source) => {
|
||||
if (err) throw err;
|
||||
if (dest) fs.writeFileSync(dest, ascjs(source));
|
||||
else process.stdout.write(ascjs(source));
|
||||
});
|
||||
} else if (stat.isDirectory() && dest && fs.statSync(dest).isDirectory()) {
|
||||
const cjsDest = path.resolve(process.cwd(), dest);
|
||||
process.on('exit', () => {
|
||||
const cjsPackage = path.join(cjsDest, 'package.json');
|
||||
if (!fs.existsSync(cjsPackage))
|
||||
fs.writeFileSync(cjsPackage, JSON.stringify({type: 'commonjs'}));
|
||||
});
|
||||
const mkdir = dir => {
|
||||
try{ fs.mkdirSync(dir); }
|
||||
catch(e){
|
||||
if(e.errno === 34){
|
||||
mkdir(path.dirname(dir));
|
||||
mkdir(dir);
|
||||
}
|
||||
}
|
||||
};
|
||||
(function walkThrough(source, dest) {
|
||||
fs.readdir(source, (err, files) => {
|
||||
if (err) throw err;
|
||||
files.forEach(file => {
|
||||
if (ignore.includes(path.join(source, file))) return;
|
||||
fs.stat(path.join(source, file), (err, stat) => {
|
||||
if (err) throw err;
|
||||
switch (true) {
|
||||
case stat.isDirectory():
|
||||
walkThrough(path.join(source, file), path.join(dest, file));
|
||||
break;
|
||||
case stat.isFile():
|
||||
if (/\.(?:m\.?)?js$/.test(file)) {
|
||||
fs.readFile(path.join(source, file), (err, content) => {
|
||||
if (err) throw err;
|
||||
mkdir(dest);
|
||||
fs.writeFile(
|
||||
path.join(dest, file),
|
||||
ascjs(content),
|
||||
(err) => {
|
||||
if (err) throw err;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}(
|
||||
path.resolve(process.cwd(), source),
|
||||
cjsDest
|
||||
));
|
||||
} else {
|
||||
throw new Error('not sure what to do, try ascjs --help\n');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const chunks = [];
|
||||
process.stdin.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
process.stdin.on('end', () => {
|
||||
process.stdout.write(ascjs(chunks.join('')));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
'use strict';
|
||||
const parser = require('@babel/parser');
|
||||
const defaultOptions = {
|
||||
allowAwaitOutsideFunction: true,
|
||||
sourceType: 'module',
|
||||
plugins: [
|
||||
// 'estree',
|
||||
'jsx',
|
||||
'typescript',
|
||||
'exportExtensions',
|
||||
'exportDefaultFrom',
|
||||
'exportNamespaceFrom',
|
||||
'dynamicImport',
|
||||
'importMeta',
|
||||
'asyncGenerators',
|
||||
'bigInt',
|
||||
'classProperties',
|
||||
'classPrivateProperties',
|
||||
'classPrivateMethods',
|
||||
['decorators', {decoratorsBeforeExport: true}],
|
||||
'doExpressions',
|
||||
'functionBind',
|
||||
'functionSent',
|
||||
'logicalAssignment',
|
||||
'nullishCoalescingOperator',
|
||||
'numericSeparator',
|
||||
'objectRestSpread',
|
||||
'optionalCatchBinding',
|
||||
'optionalChaining',
|
||||
'partialApplication',
|
||||
['pipelineOperator', {proposal: 'minimal'}],
|
||||
'throwExpressions',
|
||||
'topLevelAwait'
|
||||
]
|
||||
};
|
||||
|
||||
const EXPORT = `Object.defineProperty(exports, '__esModule', {value: true})`;
|
||||
const IMPORT = `(m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)`;
|
||||
const asDefault = name => name === 'default' ? `${parse.info.EXPORT}.default` : `exports.${name}`;
|
||||
const fromDefault = defaultImport => `${parse.info.IMPORT}(${defaultImport})`;
|
||||
|
||||
const slice = (code, info) => code.slice(info.start, info.end);
|
||||
const chunk = (info, esm, cjs) => ({
|
||||
start: info.start,
|
||||
end: info.end,
|
||||
esm, cjs
|
||||
});
|
||||
|
||||
const replace = {
|
||||
|
||||
ImportDeclaration(code, item) {
|
||||
const source = item.source;
|
||||
const name = withoutCDN(slice(code, source));
|
||||
const esm = slice(code, item);
|
||||
const SEPS = /\{(\s+)/.test(esm) ? RegExp.$1 : '';
|
||||
const SEPE = /(\s+)\}/.test(esm) ? RegExp.$1 : '';
|
||||
const SEP = /(,\s+)[^{]/.test(esm) ? RegExp.$1 : ', ';
|
||||
const EOL = /;$/.test(esm) ? ';' : '';
|
||||
const imported = [];
|
||||
const specifiers = [];
|
||||
let defaultImport = `require(${name})`;
|
||||
if (item.specifiers.length) {
|
||||
item.specifiers.forEach(specifier => {
|
||||
switch(specifier.type) {
|
||||
case 'ImportDefaultSpecifier':
|
||||
imported.push(
|
||||
`const ${specifier.local.name} = ${fromDefault(defaultImport)}${EOL}`
|
||||
);
|
||||
break;
|
||||
case 'ImportNamespaceSpecifier':
|
||||
imported.push(
|
||||
`const ${specifier.local.name} = ${defaultImport}${EOL}`
|
||||
);
|
||||
break;
|
||||
case 'ImportSpecifier':
|
||||
specifiers.push(
|
||||
specifier.local.name === specifier.imported.name ?
|
||||
specifier.local.name :
|
||||
`${specifier.imported.name}: ${specifier.local.name}`
|
||||
);
|
||||
break;
|
||||
}
|
||||
});
|
||||
if (specifiers.length) {
|
||||
imported.push(
|
||||
`const {${SEPS}${specifiers.join(SEP)}${SEPE}} = ${defaultImport}${EOL}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
imported.push(`${defaultImport}${EOL}`);
|
||||
}
|
||||
return chunk(item, esm, imported.join('\n'));
|
||||
},
|
||||
|
||||
ExportAllDeclaration(code, item) {
|
||||
const source = item.source;
|
||||
const esm = slice(code, item);
|
||||
const cjs = `(m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))\n(require(${
|
||||
withoutCDN(slice(code, source))
|
||||
}));`;
|
||||
return chunk(item, esm, cjs);
|
||||
},
|
||||
|
||||
ExportDefaultDeclaration(code, item) {
|
||||
const declaration = item.declaration;
|
||||
const esm = slice(code, item);
|
||||
let cjs;
|
||||
switch (declaration.type) {
|
||||
case 'AssignmentExpression':
|
||||
case 'FunctionDeclaration':
|
||||
if (declaration.id) {
|
||||
cjs = `${esm.replace(/^export\s+default\s+/, '')}\n${parse.info.EXPORT}.default = ${declaration.id.name}`;
|
||||
} else {
|
||||
cjs = esm.replace(/^export\s+default\s+/, `${parse.info.EXPORT}.default = `);
|
||||
}
|
||||
break;
|
||||
case 'Identifier':
|
||||
case 'ObjectExpression':
|
||||
default:
|
||||
cjs = esm.replace(/^export\s+default\s+/, `${parse.info.EXPORT}.default = `);
|
||||
break;
|
||||
}
|
||||
return chunk(item, esm, cjs);
|
||||
},
|
||||
|
||||
ExportNamedDeclaration(code, item) {
|
||||
const declaration = item.declaration;
|
||||
const source = item.source;
|
||||
const esm = slice(code, item);
|
||||
const EOL = /;$/.test(esm) ? ';\n' : '\n';
|
||||
let cjs = source ? '(m => {\n' : '';
|
||||
item.specifiers.forEach(specifier => {
|
||||
cjs += `${
|
||||
source ? ' ' : ''
|
||||
}${asDefault(specifier.exported.name)} = ${
|
||||
source ? 'm.' : ''
|
||||
}${specifier.local.name}${EOL}`;
|
||||
});
|
||||
if (declaration) {
|
||||
cjs += esm.replace(/^export\s+/, '') + '\n';
|
||||
(declaration.declarations || [declaration]).forEach(specifier => {
|
||||
cjs += `${asDefault(specifier.id.name)} = ${specifier.id.name}${EOL}`;
|
||||
});
|
||||
}
|
||||
if (source) cjs += `})(require(${
|
||||
withoutCDN(slice(code, source))
|
||||
}));\n`;
|
||||
return chunk(item, esm, cjs.trim());
|
||||
}
|
||||
};
|
||||
|
||||
const parse = (code, options) => {
|
||||
if (!options) options = {};
|
||||
const parserOptions = Object.assign(
|
||||
{},
|
||||
defaultOptions,
|
||||
options
|
||||
);
|
||||
parse.info = {
|
||||
EXPORT: options.EXPORT || EXPORT,
|
||||
IMPORT: options.IMPORT || IMPORT
|
||||
};
|
||||
delete options.EXPORT;
|
||||
delete options.IMPORT;
|
||||
code = code.toString();
|
||||
const out = [];
|
||||
const chunks = [];
|
||||
const parsed = parser.parse(code, parserOptions);
|
||||
parsed.program.body.forEach(item => {
|
||||
if (replace.hasOwnProperty(item.type)) {
|
||||
chunks.push(replace[item.type](code, item));
|
||||
}
|
||||
});
|
||||
const length = chunks.length;
|
||||
let c = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
out.push(
|
||||
code.slice(c, chunks[i].start),
|
||||
chunks[i].cjs
|
||||
);
|
||||
c = chunks[i].end;
|
||||
}
|
||||
out.push(length ? code.slice(c) : code);
|
||||
let result = out.join('').replace(
|
||||
/\bimport\.meta\b/g,
|
||||
"({url: require('url').pathToFileURL(__filename).href})"
|
||||
);
|
||||
return /^(?:#!|['"]use strict['"])/.test(result.trim()) ?
|
||||
result :
|
||||
("'use strict';\n" + result);
|
||||
};
|
||||
|
||||
const withoutCDN = name =>
|
||||
/^(['"`])https?:\/\/(?:unpkg\.com)\/([^@/]+)\S*?\1$/.test(name) ?
|
||||
`${RegExp.$1}${RegExp.$2}${RegExp.$1}` : name;
|
||||
|
||||
parse.EXPORT = EXPORT;
|
||||
parse.IMPORT = IMPORT;
|
||||
module.exports = parse;
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "ascjs",
|
||||
"version": "5.0.1",
|
||||
"description": "ES2015 to CommonJS import/export transformer",
|
||||
"bin": "bin.js",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"coveralls": "nyc report --reporter=text-lcov | coveralls",
|
||||
"test": "nyc node test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/WebReflection/ascjs.git"
|
||||
},
|
||||
"keywords": [
|
||||
"cjs",
|
||||
"esm",
|
||||
"transpile",
|
||||
"convert",
|
||||
"safe",
|
||||
"module"
|
||||
],
|
||||
"author": "Andrea Giammarchi",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/WebReflection/ascjs/issues"
|
||||
},
|
||||
"homepage": "https://github.com/WebReflection/ascjs#readme",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.12.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^3.1.0",
|
||||
"nyc": "^15.1.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
const ascjs = require('./index.js');
|
||||
|
||||
const bold = text => `\x1B[1m${text}\x1B[0m`;
|
||||
|
||||
const tests = [
|
||||
{
|
||||
esm: 'console.log(import.meta.url);',
|
||||
cjs: `console.log(({url: require('url').pathToFileURL(__filename).href}).url);`
|
||||
},
|
||||
// nothing to do
|
||||
{
|
||||
esm: '',
|
||||
cjs: ''
|
||||
},
|
||||
// exports
|
||||
{
|
||||
esm: `const name1 = 1, name2 = 2, nameN = 3; export { name1, name2, nameN }`,
|
||||
cjs: `const name1 = 1, name2 = 2, nameN = 3; exports.name1 = name1\nexports.name2 = name2\nexports.nameN = nameN`
|
||||
},
|
||||
{
|
||||
esm: `export { name1, name2, nameN } from "module"`,
|
||||
cjs: `(m => {\n exports.name1 = m.name1\n exports.name2 = m.name2\n exports.nameN = m.nameN\n})(require("module"));`
|
||||
},
|
||||
{
|
||||
esm: `const name0 = 0, name1 = 1; export { name0, name1 as default };`,
|
||||
cjs: `const name0 = 0, name1 = 1; exports.name0 = name0;\nObject.defineProperty(exports, '__esModule', {value: true}).default = name1;`
|
||||
},
|
||||
{
|
||||
esm: `export { name0, name1 as default } from "shenanigans"`,
|
||||
cjs: `(m => {\n exports.name0 = m.name0\n Object.defineProperty(exports, '__esModule', {value: true}).default = m.name1\n})(require("shenanigans"));`
|
||||
},
|
||||
{
|
||||
esm: `const variable1 = 1, variable2 = 2, nameN = 3; export { variable1 as name1, variable2 as name2, nameN };`,
|
||||
cjs: `const variable1 = 1, variable2 = 2, nameN = 3; exports.name1 = variable1;\nexports.name2 = variable2;\nexports.nameN = nameN;`
|
||||
},
|
||||
{
|
||||
esm: `export let name1 = 1, name2 = function () {}, nameN = 'N';`,
|
||||
cjs: `let name1 = 1, name2 = function () {}, nameN = 'N';\nexports.name1 = name1;\nexports.name2 = name2;\nexports.nameN = nameN;`
|
||||
},
|
||||
{
|
||||
esm: `export default function () {};`,
|
||||
cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = function () {};`
|
||||
},
|
||||
{
|
||||
esm: `export default function named() {};`,
|
||||
cjs: `function named() {}\nObject.defineProperty(exports, '__esModule', {value: true}).default = named;`
|
||||
},
|
||||
{
|
||||
esm: `export default sideEffect = true;`,
|
||||
cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = sideEffect = true;`
|
||||
},
|
||||
{
|
||||
esm: `export const identifier = 123;`,
|
||||
cjs: `const identifier = 123;\nexports.identifier = identifier;`
|
||||
},
|
||||
{
|
||||
esm: `const identifier = 123;\nexport {identifier};`,
|
||||
cjs: `const identifier = 123;\nexports.identifier = identifier;`
|
||||
},
|
||||
{
|
||||
esm: `const identifier = 123;\nexport default identifier;`,
|
||||
cjs: `const identifier = 123;\nObject.defineProperty(exports, '__esModule', {value: true}).default = identifier;`
|
||||
},
|
||||
{
|
||||
esm: `export * from "foo";`,
|
||||
cjs: `(m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))\n(require("foo"));`
|
||||
},
|
||||
// imports
|
||||
{
|
||||
esm: `import * as name from "module-name";`,
|
||||
cjs: `const name = require("module-name");`
|
||||
},
|
||||
{
|
||||
esm: `import { name } from "module-name";`,
|
||||
cjs: `const { name } = require("module-name");`
|
||||
},
|
||||
{
|
||||
esm: `import {name} from "module-name"`,
|
||||
cjs: `const {name} = require("module-name")`
|
||||
},
|
||||
{
|
||||
esm: `import { name as alias } from "module-name";`,
|
||||
cjs: `const { name: alias } = require("module-name");`
|
||||
},
|
||||
{
|
||||
esm: `import { export1 , export2 } from "module-name";`,
|
||||
cjs: `const { export1, export2 } = require("module-name");`
|
||||
},
|
||||
{
|
||||
esm: `import { export1 , export2 as alias2 } from "module-name";`,
|
||||
cjs: `const { export1, export2: alias2 } = require("module-name");`
|
||||
},
|
||||
{
|
||||
esm: `import defaultExport, { otherExport } from "module-name"`,
|
||||
cjs: `const defaultExport = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("module-name"))\nconst { otherExport } = require("module-name")`
|
||||
},
|
||||
{
|
||||
esm: `import defaultExport, * as name from "module-name";`,
|
||||
cjs: `const defaultExport = (m => /* c8 ignore start */ m.__esModule ? m.default : m /* c8 ignore stop */)(require("module-name"));\nconst name = require("module-name");`
|
||||
},
|
||||
{
|
||||
esm: `import "foo";`,
|
||||
cjs: `require("foo");`
|
||||
},
|
||||
{
|
||||
esm: `import 'foo';`,
|
||||
cjs: `require('foo');`
|
||||
},
|
||||
{
|
||||
esm: `import "foo"`,
|
||||
cjs: `require("foo")`
|
||||
},
|
||||
{
|
||||
esm: `export function test() {}`,
|
||||
cjs: `function test() {}\nexports.test = test`
|
||||
},
|
||||
{
|
||||
esm: `export default function () {}`,
|
||||
cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = function () {}`
|
||||
},
|
||||
{
|
||||
esm: `export default function test() {};`,
|
||||
cjs: `function test() {}\nObject.defineProperty(exports, '__esModule', {value: true}).default = test;`
|
||||
},
|
||||
{
|
||||
esm: `import "https://unpkg.com/hyperhtml@latest/min.js"`,
|
||||
cjs: `require("hyperhtml")`
|
||||
},
|
||||
{
|
||||
esm: `export default {a: 1, b: 2};`,
|
||||
cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = {a: 1, b: 2};`
|
||||
},
|
||||
{
|
||||
esm: `export default [1, 2, 3]`,
|
||||
cjs: `Object.defineProperty(exports, '__esModule', {value: true}).default = [1, 2, 3]`
|
||||
},
|
||||
{
|
||||
esm: `'use strict';\nmodule.exports = 123;`,
|
||||
cjs: `module.exports = 123;`
|
||||
}
|
||||
];
|
||||
|
||||
console.log(`${bold('ascjs')} v${require('./package.json').version} - ${tests.length} tests\n`);
|
||||
|
||||
tests.forEach(code => {
|
||||
console.assert(
|
||||
("'use strict';\n" + code.cjs) === ascjs(code.esm),
|
||||
`\n${bold('Source')}\n${code.esm}\n${bold('Expected')}\n${code.cjs}\n${bold('Received')}\n${ascjs(code.esm)}\n`
|
||||
);
|
||||
});
|
||||
|
||||
console.log(
|
||||
ascjs(
|
||||
'import I from "test";\nexport default function E() {}',
|
||||
{IMPORT: 'require.I', EXPORT: 'require.E(exports)'}
|
||||
) ===
|
||||
`'use strict';\nconst I = require.I(require("test"));\nfunction E() {}\nrequire.E(exports).default = E`,
|
||||
'both import and export can be overwritten'
|
||||
);
|
|
@ -0,0 +1,2 @@
|
|||
'use strict';
|
||||
module.exports = 123;
|
|
@ -0,0 +1 @@
|
|||
export default 123;
|
|
@ -0,0 +1 @@
|
|||
{"type":"commonjs"}
|
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
const func = (m => m.__esModule ? m.default : m)(require('./module.js'));
|
||||
const {a, b} = require('./module.js');
|
||||
const tmp = require('other');
|
||||
|
||||
console.log(({url: require('url').pathToFileURL(__filename).href}).url);
|
||||
|
||||
const val = 123;
|
||||
|
||||
function test() {
|
||||
console.log('ascjs');
|
||||
}
|
||||
Object.defineProperty(exports, '__esModule', {value: true}).default = test;
|
||||
|
||||
exports.func = func;
|
||||
exports.val = val;
|
|
@ -0,0 +1,12 @@
|
|||
import func, {a, b} from './module.js';
|
||||
import * as tmp from 'other';
|
||||
|
||||
console.log(import.meta.url);
|
||||
|
||||
const val = 123;
|
||||
|
||||
export default function test() {
|
||||
console.log('ascjs');
|
||||
};
|
||||
|
||||
export {func, val};
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "rollup-plugin-terser",
|
||||
"version": "7.0.2",
|
||||
"description": "Rollup plugin to minify generated es bundle",
|
||||
"type": "commonjs",
|
||||
"main": "rollup-plugin-terser.js",
|
||||
"types": "rollup-plugin-terser.d.ts",
|
||||
"exports": {
|
||||
"require": "./rollup-plugin-terser.js",
|
||||
"import": "./rollup-plugin-terser.mjs"
|
||||
},
|
||||
"files": [
|
||||
"rollup-plugin-terser.js",
|
||||
"rollup-plugin-terser.mjs",
|
||||
"rollup-plugin-terser.d.ts",
|
||||
"transform.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"prepublish": "yarn test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/TrySound/rollup-plugin-terser.git"
|
||||
},
|
||||
"keywords": [
|
||||
"rollup",
|
||||
"rollup-plugin",
|
||||
"terser",
|
||||
"minify"
|
||||
],
|
||||
"author": "Bogdan Chadkin <trysound@yandex.ru>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"jest-worker": "^26.2.1",
|
||||
"serialize-javascript": "^4.0.0",
|
||||
"terser": "^5.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.1",
|
||||
"jest": "^26.2.2",
|
||||
"prettier": "^2.0.5",
|
||||
"rollup": "^2.23.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { Plugin } from "rollup";
|
||||
import { MinifyOptions } from "terser";
|
||||
|
||||
export interface Options extends Omit<MinifyOptions, "sourceMap"> {
|
||||
/**
|
||||
* Amount of workers to spawn. Defaults to the number of CPUs minus 1.
|
||||
*/
|
||||
numWorkers?: number;
|
||||
}
|
||||
|
||||
export declare function terser(options?: Options): Plugin;
|
|
@ -0,0 +1,102 @@
|
|||
const { codeFrameColumns } = require("@babel/code-frame");
|
||||
const Worker = require("jest-worker").default;
|
||||
const serialize = require("serialize-javascript");
|
||||
|
||||
function terser(userOptions = {}) {
|
||||
if (userOptions.sourceMap != null) {
|
||||
throw Error(
|
||||
"sourceMap option is removed. Now it is inferred from rollup options."
|
||||
);
|
||||
}
|
||||
if (userOptions.sourcemap != null) {
|
||||
throw Error(
|
||||
"sourcemap option is removed. Now it is inferred from rollup options."
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
name: "terser",
|
||||
|
||||
async renderChunk(code, chunk, outputOptions) {
|
||||
if (!this.worker) {
|
||||
this.worker = new Worker(require.resolve("./transform.js"), {
|
||||
numWorkers: userOptions.numWorkers,
|
||||
});
|
||||
this.numOfBundles = 0;
|
||||
}
|
||||
|
||||
this.numOfBundles++;
|
||||
|
||||
const defaultOptions = {
|
||||
sourceMap:
|
||||
outputOptions.sourcemap === true ||
|
||||
typeof outputOptions.sourcemap === "string",
|
||||
};
|
||||
if (outputOptions.format === "es" || outputOptions.format === "esm") {
|
||||
defaultOptions.module = true;
|
||||
}
|
||||
if (outputOptions.format === "cjs") {
|
||||
defaultOptions.toplevel = true;
|
||||
}
|
||||
|
||||
const normalizedOptions = { ...defaultOptions, ...userOptions };
|
||||
|
||||
// remove plugin specific options
|
||||
for (let key of ["numWorkers"]) {
|
||||
if (normalizedOptions.hasOwnProperty(key)) {
|
||||
delete normalizedOptions[key];
|
||||
}
|
||||
}
|
||||
|
||||
const serializedOptions = serialize(normalizedOptions);
|
||||
|
||||
try {
|
||||
const result = await this.worker.transform(code, serializedOptions);
|
||||
|
||||
if (result.nameCache) {
|
||||
let { vars, props } = userOptions.nameCache;
|
||||
|
||||
// only assign nameCache.vars if it was provided, and if terser produced values:
|
||||
if (vars) {
|
||||
const newVars =
|
||||
result.nameCache.vars && result.nameCache.vars.props;
|
||||
if (newVars) {
|
||||
vars.props = vars.props || {};
|
||||
Object.assign(vars.props, newVars);
|
||||
}
|
||||
}
|
||||
|
||||
// support populating an empty nameCache object:
|
||||
if (!props) {
|
||||
props = userOptions.nameCache.props = {};
|
||||
}
|
||||
|
||||
// merge updated props into original nameCache object:
|
||||
const newProps =
|
||||
result.nameCache.props && result.nameCache.props.props;
|
||||
if (newProps) {
|
||||
props.props = props.props || {};
|
||||
Object.assign(props.props, newProps);
|
||||
}
|
||||
}
|
||||
|
||||
return result.result;
|
||||
} catch (error) {
|
||||
const { message, line, col: column } = error;
|
||||
console.error(
|
||||
codeFrameColumns(code, { start: { line, column } }, { message })
|
||||
);
|
||||
throw error;
|
||||
} finally {
|
||||
this.numOfBundles--;
|
||||
|
||||
if (this.numOfBundles === 0) {
|
||||
this.worker.end();
|
||||
this.worker = 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
exports.terser = terser;
|
|
@ -0,0 +1,3 @@
|
|||
import terserModule from "./rollup-plugin-terser.js";
|
||||
|
||||
export const terser = terserModule.terser;
|
|
@ -0,0 +1,38 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`works with code splitting 1`] = `
|
||||
Object {
|
||||
"chunk-1.js": Object {
|
||||
"code": "console.log(\\"chunk-1\\");
|
||||
",
|
||||
"dynamicImports": Array [],
|
||||
"exports": Array [],
|
||||
"fileName": "chunk-1.js",
|
||||
"implicitlyLoadedBefore": Array [],
|
||||
"imports": Array [],
|
||||
"isDynamicEntry": false,
|
||||
"isEntry": true,
|
||||
"isImplicitEntry": false,
|
||||
"map": null,
|
||||
"name": "chunk-1",
|
||||
"referencedFiles": Array [],
|
||||
"type": "chunk",
|
||||
},
|
||||
"chunk-2.js": Object {
|
||||
"code": "console.log(\\"chunk-2\\");
|
||||
",
|
||||
"dynamicImports": Array [],
|
||||
"exports": Array [],
|
||||
"fileName": "chunk-2.js",
|
||||
"implicitlyLoadedBefore": Array [],
|
||||
"imports": Array [],
|
||||
"isDynamicEntry": false,
|
||||
"isEntry": true,
|
||||
"isImplicitEntry": false,
|
||||
"map": null,
|
||||
"name": "chunk-2",
|
||||
"referencedFiles": Array [],
|
||||
"type": "chunk",
|
||||
},
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,2 @@
|
|||
var chunk1 = 'chunk-1';
|
||||
console.log(chunk1)
|
|
@ -0,0 +1,2 @@
|
|||
var chunk2 = 'chunk-2';
|
||||
console.log(chunk2)
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
window.a = 5;
|
||||
|
||||
/* @preserve this comment */
|
||||
|
||||
/* delete this comment */
|
||||
|
||||
// and this one too
|
||||
|
||||
if (window.a < 3) {
|
||||
console.log(4);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export default 5;
|
|
@ -0,0 +1 @@
|
|||
var a = 1;
|
|
@ -0,0 +1,4 @@
|
|||
"use strict";
|
||||
|
||||
const foo = 'bar';
|
||||
console.log(foo);
|
|
@ -0,0 +1,9 @@
|
|||
function recurse(count) {
|
||||
if (count > 0) return recurse(count - 1);
|
||||
return count;
|
||||
}
|
||||
const obj = {
|
||||
foo: 1,
|
||||
_priv: 2
|
||||
};
|
||||
console.log(obj, recurse(10));
|
|
@ -0,0 +1,5 @@
|
|||
const obj = {
|
||||
foo: 1,
|
||||
_priv: 2
|
||||
};
|
||||
console.log(obj);
|
|
@ -0,0 +1,3 @@
|
|||
import result from './export-number.js';
|
||||
|
||||
console.log(result);
|
|
@ -0,0 +1,6 @@
|
|||
"use strict";
|
||||
window.a = 5;
|
||||
|
||||
if (window.a < 3) {
|
||||
console.log(4);
|
||||
}
|
|
@ -0,0 +1,473 @@
|
|||
const { rollup } = require("rollup");
|
||||
const { terser } = require("../");
|
||||
|
||||
test("minify", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/unminified.js",
|
||||
plugins: [terser()],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual(
|
||||
'"use strict";window.a=5,window.a<3&&console.log(4);\n'
|
||||
);
|
||||
expect(output.map).toBeFalsy();
|
||||
});
|
||||
|
||||
test("minify via terser options", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/empty.js",
|
||||
plugins: [terser({ output: { comments: "all" } })],
|
||||
});
|
||||
const result = await bundle.generate({
|
||||
banner: "/* package name */",
|
||||
format: "cjs",
|
||||
});
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual('/* package name */\n"use strict";\n');
|
||||
expect(output.map).toBeFalsy();
|
||||
});
|
||||
|
||||
test("minify multiple outputs", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/unminified.js",
|
||||
plugins: [terser()],
|
||||
});
|
||||
|
||||
const [bundle1, bundle2] = await Promise.all([
|
||||
bundle.generate({ format: "cjs" }),
|
||||
bundle.generate({ format: "es" }),
|
||||
]);
|
||||
const [output1] = bundle1.output;
|
||||
const [output2] = bundle2.output;
|
||||
|
||||
expect(output1.code).toEqual(
|
||||
'"use strict";window.a=5,window.a<3&&console.log(4);\n'
|
||||
);
|
||||
expect(output2.code).toEqual("window.a=5,window.a<3&&console.log(4);\n");
|
||||
});
|
||||
|
||||
test("minify esm module", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/plain-file.js",
|
||||
plugins: [terser()],
|
||||
});
|
||||
const result = await bundle.generate({ format: "esm" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual('console.log("bar");\n');
|
||||
});
|
||||
|
||||
test("minify esm module with disabled module option", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/plain-file.js",
|
||||
plugins: [terser({ module: false })],
|
||||
});
|
||||
const result = await bundle.generate({ format: "esm" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual('const foo="bar";console.log(foo);\n');
|
||||
});
|
||||
|
||||
test("minify cjs module", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/plain-file.js",
|
||||
plugins: [terser()],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual('"use strict";console.log("bar");\n');
|
||||
});
|
||||
|
||||
test("minify cjs module with disabled toplevel option", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/plain-file.js",
|
||||
plugins: [terser({ toplevel: false })],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual(
|
||||
'"use strict";const foo="bar";console.log(foo);\n'
|
||||
);
|
||||
});
|
||||
|
||||
test("minify with sourcemaps", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/sourcemap.js",
|
||||
plugins: [terser()],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs", sourcemap: true });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.map).toMatchInlineSnapshot(`
|
||||
SourceMap {
|
||||
"file": "sourcemap.js",
|
||||
"mappings": "aAEAA,QAAQC,ICFO",
|
||||
"names": Array [
|
||||
"console",
|
||||
"log",
|
||||
],
|
||||
"sources": Array [
|
||||
"test/fixtures/sourcemap.js",
|
||||
"test/fixtures/export-number.js",
|
||||
],
|
||||
"sourcesContent": Array [
|
||||
"import result from './export-number.js';
|
||||
|
||||
console.log(result);
|
||||
",
|
||||
"export default 5;
|
||||
",
|
||||
],
|
||||
"version": 3,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('work with sourcemap: "inline"', async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/sourcemap.js",
|
||||
plugins: [terser()],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs", sourcemap: "inline" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.map).toMatchInlineSnapshot(`
|
||||
SourceMap {
|
||||
"file": "sourcemap.js",
|
||||
"mappings": "aAEAA,QAAQC,ICFO",
|
||||
"names": Array [
|
||||
"console",
|
||||
"log",
|
||||
],
|
||||
"sources": Array [
|
||||
"test/fixtures/sourcemap.js",
|
||||
"test/fixtures/export-number.js",
|
||||
],
|
||||
"sourcesContent": Array [
|
||||
"import result from './export-number.js';
|
||||
|
||||
console.log(result);
|
||||
",
|
||||
"export default 5;
|
||||
",
|
||||
],
|
||||
"version": 3,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("does not allow to pass sourcemap option", async () => {
|
||||
try {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/sourcemap.js",
|
||||
plugins: [terser({ sourcemap: false })],
|
||||
});
|
||||
expect(true).toBeFalsy();
|
||||
} catch (error) {
|
||||
expect(error.toString()).toMatch(/sourcemap option is removed/);
|
||||
}
|
||||
});
|
||||
|
||||
test("does not allow to pass sourceMap option", async () => {
|
||||
try {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/sourcemap.js",
|
||||
plugins: [terser({ sourceMap: false })],
|
||||
});
|
||||
expect(true).toBeFalsy();
|
||||
} catch (error) {
|
||||
expect(error.toString()).toMatch(/sourceMap option is removed/);
|
||||
}
|
||||
});
|
||||
|
||||
test("throw error on terser fail", async () => {
|
||||
try {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/failed.js",
|
||||
plugins: [
|
||||
{
|
||||
renderChunk: () => ({ code: "var = 1" }),
|
||||
},
|
||||
terser(),
|
||||
],
|
||||
});
|
||||
await bundle.generate({ format: "esm" });
|
||||
expect(true).toBeFalsy();
|
||||
} catch (error) {
|
||||
expect(error.toString()).toMatch(/Name expected/);
|
||||
}
|
||||
});
|
||||
|
||||
test("throw error on terser fail with multiple outputs", async () => {
|
||||
try {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/failed.js",
|
||||
plugins: [
|
||||
{
|
||||
renderChunk: () => ({ code: "var = 1" }),
|
||||
},
|
||||
terser(),
|
||||
],
|
||||
});
|
||||
await Promise.all([
|
||||
bundle.generate({ format: "cjs" }),
|
||||
bundle.generate({ format: "esm" }),
|
||||
]);
|
||||
expect(true).toBeFalsy();
|
||||
} catch (error) {
|
||||
expect(error.toString()).toMatch(/Name expected/);
|
||||
}
|
||||
});
|
||||
|
||||
test("works with code splitting", async () => {
|
||||
const bundle = await rollup({
|
||||
input: ["test/fixtures/chunk-1.js", "test/fixtures/chunk-2.js"],
|
||||
plugins: [terser()],
|
||||
});
|
||||
const { output } = await bundle.generate({ format: "esm" });
|
||||
const newOutput = {};
|
||||
output.forEach((out) => {
|
||||
// TODO rewrite with object rest after node 6 dropping
|
||||
const value = Object.assign({}, out);
|
||||
delete value.modules;
|
||||
delete value.facadeModuleId;
|
||||
newOutput[out.fileName] = value;
|
||||
});
|
||||
expect(newOutput).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("allow to pass not string values to worker", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/unminified.js",
|
||||
plugins: [terser({ mangle: { properties: { regex: /^_/ } } })],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual(
|
||||
'"use strict";window.a=5,window.a<3&&console.log(4);\n'
|
||||
);
|
||||
});
|
||||
|
||||
test("allow classic function definitions passing to worker", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/commented.js",
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: { properties: { regex: /^_/ } },
|
||||
output: {
|
||||
comments: function (node, comment) {
|
||||
if (comment.type === "comment2") {
|
||||
// multiline comment
|
||||
return /@preserve|@license|@cc_on|^!/i.test(comment.value);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs", compact: true });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual(
|
||||
'"use strict";window.a=5,\n/* @preserve this comment */\nwindow.a<3&&console.log(4);'
|
||||
);
|
||||
});
|
||||
|
||||
test("allow method shorthand definitions passing to worker", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/commented.js",
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: { properties: { regex: /^_/ } },
|
||||
output: {
|
||||
comments(node, comment) {
|
||||
if (comment.type === "comment2") {
|
||||
// multiline comment
|
||||
return /@preserve|@license|@cc_on|^!/i.test(comment.value);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs", compact: true });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual(
|
||||
'"use strict";window.a=5,\n/* @preserve this comment */\nwindow.a<3&&console.log(4);'
|
||||
);
|
||||
});
|
||||
|
||||
test("allow arrow function definitions passing to worker", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/unminified.js",
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: { properties: { regex: /^_/ } },
|
||||
output: {
|
||||
comments: (node, comment) => {
|
||||
if (comment.type === "comment2") {
|
||||
// multiline comment
|
||||
return /@preserve|@license|@cc_on|^!/i.test(comment.value);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs" });
|
||||
expect(result.output).toHaveLength(1);
|
||||
const [output] = result.output;
|
||||
expect(output.code).toEqual(
|
||||
'"use strict";window.a=5,window.a<3&&console.log(4);\n'
|
||||
);
|
||||
});
|
||||
|
||||
test("allow to pass not string values to worker", async () => {
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/unminified.js",
|
||||
plugins: [terser({ mangle: { properties: { regex: /^_/ } } })],
|
||||
});
|
||||
const result = await bundle.generate({ format: "cjs" });
|
||||
expect(result.output[0].code).toEqual(
|
||||
'"use strict";window.a=5,window.a<3&&console.log(4);\n'
|
||||
);
|
||||
});
|
||||
|
||||
test("terser accepts the nameCache option", async () => {
|
||||
const nameCache = {
|
||||
props: {
|
||||
props: {
|
||||
$_priv: "custom",
|
||||
},
|
||||
},
|
||||
};
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/properties.js",
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: {
|
||||
properties: {
|
||||
regex: /^_/,
|
||||
},
|
||||
},
|
||||
nameCache,
|
||||
}),
|
||||
],
|
||||
});
|
||||
const result = await bundle.generate({ format: "es" });
|
||||
expect(result.output[0].code.trim()).toEqual(
|
||||
`console.log({foo:1,custom:2});`
|
||||
);
|
||||
});
|
||||
|
||||
test("terser updates the nameCache object", async () => {
|
||||
const nameCache = {
|
||||
props: {
|
||||
props: {
|
||||
$_priv: "f",
|
||||
},
|
||||
},
|
||||
};
|
||||
const props = nameCache.props;
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/properties.js",
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: {
|
||||
properties: {
|
||||
regex: /./,
|
||||
},
|
||||
},
|
||||
nameCache,
|
||||
}),
|
||||
],
|
||||
});
|
||||
const result = await bundle.generate({ format: "es" });
|
||||
expect(result.output[0].code.trim()).toEqual(`console.log({o:1,f:2});`);
|
||||
expect(nameCache.props).toBe(props);
|
||||
expect(nameCache).toEqual({
|
||||
props: {
|
||||
props: {
|
||||
$_priv: "f",
|
||||
$foo: "o",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("omits populates an empty nameCache object", async () => {
|
||||
const nameCache = {};
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/properties-and-locals.js",
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: {
|
||||
properties: {
|
||||
regex: /./,
|
||||
},
|
||||
},
|
||||
nameCache,
|
||||
}),
|
||||
],
|
||||
});
|
||||
const result = await bundle.generate({ format: "es" });
|
||||
expect(result.output[0].code.trim()).toEqual(
|
||||
`console.log({o:1,i:2},function o(n){return n>0?o(n-1):n}(10));`
|
||||
);
|
||||
expect(nameCache).toEqual({
|
||||
props: {
|
||||
props: {
|
||||
$_priv: "i",
|
||||
$foo: "o",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Note: nameCache.vars never gets populated, but this is a Terser issue.
|
||||
// Here we're just testing that an empty vars object doesn't get added to nameCache if it wasn't there previously.
|
||||
test("terser preserve vars in nameCache when provided", async () => {
|
||||
const nameCache = {
|
||||
vars: {
|
||||
props: {},
|
||||
},
|
||||
};
|
||||
const bundle = await rollup({
|
||||
input: "test/fixtures/properties-and-locals.js",
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: {
|
||||
properties: {
|
||||
regex: /./,
|
||||
},
|
||||
},
|
||||
nameCache,
|
||||
}),
|
||||
],
|
||||
});
|
||||
const result = await bundle.generate({ format: "es" });
|
||||
expect(result.output[0].code.trim()).toEqual(
|
||||
`console.log({o:1,i:2},function o(n){return n>0?o(n-1):n}(10));`
|
||||
);
|
||||
expect(nameCache).toEqual({
|
||||
props: {
|
||||
props: {
|
||||
$_priv: "i",
|
||||
$foo: "o",
|
||||
},
|
||||
},
|
||||
vars: {
|
||||
props: {},
|
||||
},
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
const { minify } = require("terser");
|
||||
|
||||
const transform = (code, optionsString) => {
|
||||
const options = eval(`(${optionsString})`);
|
||||
return minify(code, options).then(result => ({ result, nameCache: options.nameCache }));
|
||||
};
|
||||
|
||||
exports.transform = transform;
|
Loading…
Reference in New Issue