├── .babelrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── package.json ├── rollup.config.js ├── src ├── index.js └── logger.js └── test ├── fixtures ├── es6getter.js ├── export-number.js ├── plain-file.js ├── sourcemap.js └── unminified.js └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["add-module-exports"] 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .babelrc 2 | .travis.yml 3 | .gitginore 4 | rollup.config.js 5 | test 6 | coverage -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.2" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Camel Aissani 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rollup-plugin-closure-compiler-js 2 | 3 | [![license](https://img.shields.io/npm/l/rollup-plugin-closure-compiler-js.svg)](https://github.com/camelaissani/rollup-plugin-closure-compiler-js/blob/master/LICENSE) 4 | [![Build Status](https://travis-ci.org/camelaissani/rollup-plugin-closure-compiler-js.svg)](https://travis-ci.org/camelaissani/rollup-plugin-closure-compiler-js) 5 | [![dependencies Status](https://david-dm.org/camelaissani/rollup-plugin-closure-compiler-js/status.svg)](https://david-dm.org/camelaissani/rollup-plugin-closure-compiler-js) 6 | [![devDependencies Status](https://david-dm.org/camelaissani/rollup-plugin-closure-compiler-js/dev-status.svg)](https://david-dm.org/camelaissani/rollup-plugin-closure-compiler-js?type=dev) 7 | 8 | 9 | [![latest version](https://img.shields.io/npm/v/rollup-plugin-closure-compiler-js.svg)](https://www.npmjs.com/package/rollup-plugin-closure-compiler-js) 10 | [![npm](https://img.shields.io/npm/dm/rollup-plugin-closure-compiler-js.svg)](https://www.npmjs.com/package/rollup-plugin-closure-compiler-js) 11 | 12 | [Rollup](https://github.com/rollup/rollup) plugin for optimizing JavaScript with google-closure-compiler-js. 13 | 14 | ## Install 15 | 16 | ```sh 17 | npm i rollup-plugin-closure-compiler-js -D 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```js 23 | import { rollup } from 'rollup'; 24 | import closure from 'rollup-plugin-closure-compiler-js'; 25 | 26 | rollup({ 27 | entry: 'main.js', 28 | plugins: [ 29 | closure() 30 | ] 31 | }); 32 | ``` 33 | 34 | See [closure-compiler-js documentation](https://github.com/google/closure-compiler-js#flags) for more information about options. 35 | 36 | # License 37 | 38 | MIT © 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-plugin-closure-compiler-js", 3 | "version": "1.0.6", 4 | "description": "Rollup plugin to invoke google-closure-compiler-js.", 5 | "main": "dist/rollup-plugin-closure-compiler-js.js", 6 | "jsnext:main": "dist/rollup-plugin-closure-compiler-js.es.js", 7 | "scripts": { 8 | "build": "rollup -c", 9 | "pretest": "npm run build", 10 | "test": "mocha test/*.js --compilers js:babel-core/register" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/camelaissani/rollup-plugin-closure-compiler-js.git" 15 | }, 16 | "keywords": [ 17 | "rollup", 18 | "rollup-plugin", 19 | "closure-compiler", 20 | "closure-compiler-js" 21 | ], 22 | "author": "Camel Aissani ", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/camelaissani/rollup-plugin-closure-compiler-js/issues" 26 | }, 27 | "homepage": "https://github.com/camelaissani/rollup-plugin-closure-compiler-js#readme", 28 | "dependencies": { 29 | "google-closure-compiler-js": ">20170000" 30 | }, 31 | "devDependencies": { 32 | "babel-core": "^6.26.0", 33 | "babel-plugin-add-module-exports": "^0.2.1", 34 | "babel-preset-es2015": "^6.24.1", 35 | "babelrc-rollup": "^3.0.0", 36 | "mocha": "^3.5.3", 37 | "rollup": "^0.35.11", 38 | "rollup-plugin-babel": "^2.6.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import babelrc from 'babelrc-rollup'; 3 | 4 | var pkg = require('./package.json'); 5 | 6 | export default { 7 | entry: 'src/index.js', 8 | plugins: [babel(babelrc({ 9 | addExternalHelpersPlugin: false 10 | }))], 11 | targets: [ 12 | { 13 | format: 'cjs', 14 | dest: pkg['main'] 15 | }, 16 | { 17 | format: 'es', 18 | dest: pkg['jsnext:main'] 19 | } 20 | ] 21 | }; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import {compile} from 'google-closure-compiler-js'; 2 | import logger from './logger'; 3 | 4 | export default function closure(flags = {}) { 5 | return { 6 | name: 'closure-compiler-js', 7 | transformBundle(code) { 8 | flags = Object.assign({ 9 | createSourceMap: true, 10 | processCommonJsModules: true 11 | }, flags); 12 | flags.jsCode = [{ 13 | src: code 14 | }]; 15 | const output = compile(flags); 16 | if (logger(flags, output)) { 17 | throw new Error(`compilation error, ${output.errors.length} error${output.errors.length===0 || output.errors.length>1?'s':''}`); 18 | } 19 | return {code: output.compiledCode, map: output.sourceMap}; 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The Closure Compiler Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @fileoverview Logger for Closure Compiler output. 19 | */ 20 | 21 | 'use strict'; 22 | 23 | const ESC = '\u001B'; 24 | const COLOR_END = ESC + '[0m'; 25 | const COLOR_RED = ESC + '[91m'; 26 | const COLOR_GREEN = ESC + '[92m'; 27 | const COLOR_YELLOW = ESC + '[93m'; 28 | 29 | /** 30 | * @param {string} line to generate prefix for 31 | * @param {number} charNo to generate prefix at 32 | * @return {string} prefix for showing a caret 33 | */ 34 | function caretPrefix(line, charNo) { 35 | return line.substr(0, charNo).replace(/[^\t]/g, ' '); 36 | } 37 | 38 | 39 | /** 40 | * @param {!Object} options 41 | * @param {!Object} output 42 | * @param {function(string)} logger 43 | * @return {boolean} Whether this output should fail a compilation. 44 | */ 45 | export default function(options, output, logger) { 46 | logger = logger || console.warn; 47 | // TODO(samthor): If this file has a sourceMap, then follow it back out of the rabbit hole. 48 | function fileFor(file) { 49 | if (!file) { return null; } 50 | 51 | // Filenames are the same across source and externs, so prefer source files. 52 | for (const files of [options.jsCode, options.externs]) { 53 | if (!files) { continue; } 54 | 55 | for (const cand of files) { 56 | if (cand.path == file) { 57 | return cand; 58 | } 59 | } 60 | } 61 | 62 | return null; 63 | } 64 | 65 | function writemsg(color, msg) { 66 | if (!msg.file && msg.lineNo < 0) { 67 | logger(msg.type); 68 | } else { 69 | logger(`${msg.file}:${msg.lineNo} (${msg.type})`) 70 | } 71 | logger(msg.description); 72 | 73 | const file = fileFor(msg.file); 74 | if (file) { 75 | const lines = file.src.split('\n'); // TODO(samthor): cache this for logger? 76 | const line = lines[msg.lineNo - 1] || ''; 77 | logger(color + line + COLOR_END); 78 | logger(COLOR_GREEN + caretPrefix(line, msg.charNo) + '^' + COLOR_END); 79 | } 80 | logger(''); 81 | } 82 | 83 | output.warnings.forEach(writemsg.bind(null, COLOR_YELLOW)); 84 | output.errors.forEach(writemsg.bind(null, COLOR_RED)); 85 | 86 | return output.errors.length > 0; 87 | }; -------------------------------------------------------------------------------- /test/fixtures/es6getter.js: -------------------------------------------------------------------------------- 1 | export class Route { 2 | constructor(uriPart) { 3 | this.uriPart = uriPart; 4 | } 5 | 6 | get uri() { 7 | return this.uriPart; 8 | } 9 | } 10 | 11 | export class Router {}; -------------------------------------------------------------------------------- /test/fixtures/export-number.js: -------------------------------------------------------------------------------- 1 | export default 5; -------------------------------------------------------------------------------- /test/fixtures/plain-file.js: -------------------------------------------------------------------------------- 1 | const foo = 'bar'; 2 | const t = 1 + 2; 3 | console.log(foo); 4 | console.log(t); -------------------------------------------------------------------------------- /test/fixtures/sourcemap.js: -------------------------------------------------------------------------------- 1 | import result from './export-number.js'; 2 | 3 | class A { 4 | constructor() { 5 | console.log('e'); 6 | } 7 | } 8 | 9 | const b = new A(); 10 | 11 | console.log(result); -------------------------------------------------------------------------------- /test/fixtures/unminified.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var a = 5; 3 | 4 | if (a < 3) { 5 | console.log(4); 6 | } -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import { rollup } from 'rollup'; 3 | import { compile } from 'google-closure-compiler-js'; 4 | import { readFileSync } from 'fs'; 5 | import closure from '../dist/rollup-plugin-closure-compiler-js.es'; 6 | 7 | process.chdir('test'); 8 | 9 | describe('rollup-plugin-closure-compiler-js', function() { 10 | // because closure-compiler takes time 11 | this.timeout(0); 12 | 13 | it('should compile', () => { 14 | return rollup({ 15 | entry: 'fixtures/unminified.js', 16 | plugins: [ closure() ] 17 | }).then(bundle => { 18 | const { code, map } = bundle.generate({ 19 | format: 'cjs' 20 | }); 21 | const jsFile = readFileSync('fixtures/unminified.js', 'utf-8'); 22 | const { compiledCode } = compile({jsCode: [{src: jsFile}]}); 23 | assert.equal(code, compiledCode+'\n'); 24 | }); 25 | }); 26 | 27 | it('should compile via closure-compiler options', () => { 28 | return rollup({ 29 | entry: 'fixtures/plain-file.js', 30 | plugins: [ closure({ 31 | compilationLevel: 'WHITESPACE_ONLY' 32 | })] 33 | }).then(bundle => { 34 | const { code } = bundle.generate({ 35 | format: 'cjs' 36 | }); 37 | assert.equal(code, 'var foo="bar";var t=1+2;console.log(foo);console.log(t);\n'); 38 | }); 39 | }); 40 | 41 | it('should compile with sourcemaps', () => { 42 | return rollup({ 43 | entry: 'fixtures/sourcemap.js', 44 | plugins: [ closure() ], 45 | }).then(bundle => { 46 | const { map } = bundle.generate({ 47 | format: 'cjs', 48 | sourceMap: true 49 | }); 50 | 51 | assert.ok(map, 'has a source map'); 52 | assert.equal(map.version, 3, 'source map has expected version'); 53 | assert.ok(Array.isArray(map.sources), 'source map has sources array'); 54 | assert.equal(map.sources.length, 2, 'source map has two sources'); 55 | assert.ok(Array.isArray(map.names), 'source maps has names array'); 56 | assert.ok(map.mappings, 'source map has mappings'); 57 | }); 58 | }); 59 | 60 | it('bug with e6getter', () => { 61 | return rollup({ 62 | entry: 'fixtures/es6getter.js', 63 | plugins: [ closure() ] 64 | }).then(bundle => { 65 | const { code, map } = bundle.generate({ 66 | format: 'cjs', 67 | sourceMap: true 68 | }); 69 | assert(code); 70 | assert(map); 71 | }); 72 | }); 73 | }); --------------------------------------------------------------------------------