├── .gitignore ├── test ├── mochats │ ├── index.ts │ ├── component.html │ ├── example-component.html │ ├── component.ts │ └── component.spec.ts ├── mochajs │ ├── index.js │ ├── component.html │ ├── style.scss │ ├── example-component.html │ ├── component.js │ ├── example-component.js │ ├── example-component.original.js │ └── component.spec.js ├── karma │ ├── example-component.html │ ├── test-user.component.html │ ├── test.component.html │ ├── test-user.component.ts │ ├── test.component.ts │ ├── index.ts │ └── test.component.spec.ts └── hello │ ├── hello.ts │ └── test.ts ├── .editorconfig ├── tsconfig.json ├── rollup.config.js ├── .travis.yml ├── LICENSE ├── package.json ├── README.md ├── karma.conf.js └── src └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .vscode 4 | -------------------------------------------------------------------------------- /test/mochats/index.ts: -------------------------------------------------------------------------------- 1 | import './component.spec'; 2 | -------------------------------------------------------------------------------- /test/mochajs/index.js: -------------------------------------------------------------------------------- 1 | require('./component.spec.js'); 2 | -------------------------------------------------------------------------------- /test/mochajs/component.html: -------------------------------------------------------------------------------- 1 | component.html content loaded 2 | -------------------------------------------------------------------------------- /test/mochats/component.html: -------------------------------------------------------------------------------- 1 | component.html content loaded 2 | -------------------------------------------------------------------------------- /test/karma/example-component.html: -------------------------------------------------------------------------------- 1 | example-component.html content loaded 2 | -------------------------------------------------------------------------------- /test/mochats/example-component.html: -------------------------------------------------------------------------------- 1 | example-component.html content loaded 2 | -------------------------------------------------------------------------------- /test/karma/test-user.component.html: -------------------------------------------------------------------------------- 1 | test-user.component.html content loaded 2 | -------------------------------------------------------------------------------- /test/karma/test.component.html: -------------------------------------------------------------------------------- 1 | test.component.html loaded 2 | 3 | -------------------------------------------------------------------------------- /test/mochajs/style.scss: -------------------------------------------------------------------------------- 1 | $test: 150px; 2 | .test { 3 | width: $test; 4 | font-family: fantasy; 5 | } 6 | -------------------------------------------------------------------------------- /test/hello/hello.ts: -------------------------------------------------------------------------------- 1 | export function hello() { 2 | return 'Hello World!'; 3 | } 4 | 5 | export default hello; 6 | -------------------------------------------------------------------------------- /test/mochajs/example-component.html: -------------------------------------------------------------------------------- 1 | blaah 2 |

3 | example-component ! 4 |

5 | 6 | minfiy this 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/mochajs/component.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @Component({ 4 | * selector: 'component', 5 | * templateUrl: './component.html' 6 | * styleUrls: [ 7 | * './style.scss' 8 | * ] 9 | * }) 10 | */ 11 | 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /test/karma/test-user.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'test-user', 5 | templateUrl: './test-user.component.html' 6 | }) 7 | export class TestUserComponent { 8 | constructor() {} 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "module": "commonjs", 5 | "target": "es5", 6 | "noImplicitAny": false, 7 | "sourceMap": false, 8 | "removeComments": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/hello/test.ts: -------------------------------------------------------------------------------- 1 | import hello from './hello'; 2 | import { expect } from 'chai'; 3 | 4 | describe('Hello function', () => { 5 | it('should return hello world', () => { 6 | const result = hello(); 7 | expect(result).to.equal('Hello World!'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import buble from 'rollup-plugin-buble'; 2 | 3 | var external = Object.keys(require('./package.json').dependencies).concat(['colors', ,'fs', 'path', 'replace']); 4 | 5 | export default { 6 | entry: 'src/index.js', 7 | plugins: [ buble() ], 8 | external: external, 9 | targets: [ 10 | { dest: 'dist/rollup-plugin-angular.js', format: 'cjs' }, 11 | { dest: 'dist/rollup-plugin-angular.esm.js', format: 'es' } 12 | ] 13 | }; 14 | -------------------------------------------------------------------------------- /test/mochats/component.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Component } from '@angular/core'; 3 | /** 4 | * @Component({ 5 | * selector: 'example', 6 | * templateUrl: './example-component.html' 7 | * }) 8 | * export class ExampleComponent {} 9 | * @export 10 | * @class ExampleComponent 11 | * @implements {AfterViewChecked} 12 | */ 13 | @Component({ 14 | selector: 'component', 15 | templateUrl: `./component.html` 16 | }) 17 | export class TestComponent { 18 | constructor() {} 19 | } 20 | -------------------------------------------------------------------------------- /test/karma/test.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | /** 3 | * @Component({ 4 | * selector: 'example', 5 | * templateUrl: './do-not-load-this-component.html' 6 | * }) 7 | * export class ExampleComponent {} 8 | * @export 9 | * @class ExampleComponent 10 | * @implements {AfterViewChecked} 11 | */ 12 | @Component({ 13 | selector: 'test', 14 | templateUrl: `./test.component.html` 15 | }) 16 | export class TestComponent { 17 | constructor() {} 18 | } 19 | -------------------------------------------------------------------------------- /test/karma/index.ts: -------------------------------------------------------------------------------- 1 | // import 'es6-shim'; 2 | import 'reflect-metadata'; 3 | import 'core-js/es6'; 4 | import 'core-js/es7/reflect'; 5 | 6 | // Typescript emit helpers polyfill 7 | // require('ts-helpers'); 8 | 9 | import 'zone.js/dist/zone'; 10 | import 'zone.js/dist/long-stack-trace-zone'; 11 | import 'zone.js/dist/proxy'; 12 | import 'zone.js/dist/sync-test'; 13 | import 'zone.js/dist/jasmine-patch'; 14 | import 'zone.js/dist/async-test'; 15 | import 'zone.js/dist/fake-async-test'; 16 | 17 | // RxJS 18 | import 'rxjs/Rx'; 19 | 20 | import * as browser from '@angular/platform-browser-dynamic/testing'; 21 | import * as testing from '@angular/core/testing'; 22 | 23 | testing.TestBed.initTestEnvironment( 24 | browser.BrowserDynamicTestingModule, 25 | browser.platformBrowserDynamicTesting() 26 | ); 27 | Error.stackTraceLimit = Infinity; 28 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000; 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: '6' 3 | deploy: 4 | provider: npm 5 | email: felix@stkn.org 6 | api_key: 7 | secure: bU+7l8jBtPV7LAxN7NimbrSIEM+GvDU5CpVbq4T+ix3wzkYdaCaOLS60kJNoS/cB5sAAENZZRkyBLuwDJZ/u38IrVc3k2p6U/eu7i+5ErvHB6v6z4yB6yOiFqYbEloPWpvROX3KN2AQkot8TNl81HO2cTG0vHEipusXh8g/xIG/62gJvHXosDEySd7Wfmy0cDijZUD7UDbTm+INioToHvI5UdSq35JdBFblALP6eRBqE+WtW12Nql2/oDTtWblBLopFhXqptpJINAYZL3YclPRmGycfvhqN2ygjdEo6bltvdphTJU9QTua2XFrwer6dJI8bKDt4cmJUsTEbAVRMhjCWW4zGiRQx9C4GnhccH8+0mupvLdrkPEgvcwCUaHDyDAJ++UgC/b9PglrZUKP/ol6KdN2fCBmwf5zrNjygy0OYWPsiUrd1PiqDF3KkLMbOoymEUI7nNQ6oTJDu8L43GSuaysKUYUOafiPqoSFes144BZ/nlRpIiDjmdo1AhuzFDry9kuQYeHk6frEswY9aQ43NfDtzHygs35FPZ7MGtpNWbFTnp72MnJ6MdDE38zz8YparrkH/sX+JBHWVsmE5aYwuphtL4waeTqZRZq1S//dZLp7WSz2jd43h13A/h3ggkuIp4f8sw8FQtqmWZwehFnnYHw7+KR4+u2uuTrwtMaf4= 8 | on: 9 | tags: true 10 | repo: cebor/rollup-plugin-angular 11 | before_script: 12 | - "export DISPLAY=:99.0" 13 | - "sh -e /etc/init.d/xvfb start" 14 | - sleep 3 # give xvfb some time to start 15 | -------------------------------------------------------------------------------- /test/mochajs/example-component.js: -------------------------------------------------------------------------------- 1 | /** 2 | ExampleComponent.decorators = [ 3 | { type: Component, args: [{ 4 | selector: 'example-component', 5 | templateUrl: `./example-component.html`, 6 | styleUrls: [ 7 | './style.scss', 8 | './style.scss' 9 | ] 10 | },] }, 11 | ]; 12 | 13 | */ 14 | ExampleComponent.decorators = [ 15 | { type: Component, args: [{ 16 | selector: 'example-component', 17 | templateUrl: `./example-component.html`, 18 | styleUrls: [ 19 | './style.scss', 20 | './style.scss' 21 | ] 22 | },] }, 23 | ]; 24 | 25 | ExampleComponent.decorators = [ 26 | { type: Component, args: [{ 27 | selector: 'example-component', 28 | template: `blaaah`, 29 | style: [ 30 | '.test{ }', 31 | '.test_aa {}' 32 | ] 33 | },] }, 34 | ]; 35 | -------------------------------------------------------------------------------- /test/mochajs/example-component.original.js: -------------------------------------------------------------------------------- 1 | /** 2 | ExampleComponent.decorators = [ 3 | { type: Component, args: [{ 4 | selector: 'example-component', 5 | templateUrl: `./example-component.html`, 6 | styleUrls: [ 7 | './style.scss', 8 | './style.scss' 9 | ] 10 | },] }, 11 | ]; 12 | 13 | */ 14 | ExampleComponent.decorators = [ 15 | { type: Component, args: [{ 16 | selector: 'example-component', 17 | templateUrl: `./example-component.html`, 18 | styleUrls: [ 19 | './style.scss', 20 | './style.scss' 21 | ] 22 | },] }, 23 | ]; 24 | 25 | ExampleComponent.decorators = [ 26 | { type: Component, args: [{ 27 | selector: 'example-component', 28 | template: `blaaah`, 29 | style: [ 30 | '.test{ }', 31 | '.test_aa {}' 32 | ] 33 | },] }, 34 | ]; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Felix Itzenplitz 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 | -------------------------------------------------------------------------------- /test/mochats/component.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | import { rollup } from 'rollup'; 3 | import * as commonjs from 'rollup-plugin-commonjs'; 4 | import * as nodeResolve from 'rollup-plugin-node-resolve'; 5 | import * as typescript from 'rollup-plugin-typescript'; 6 | import { expect, assert } from 'chai'; 7 | import * as angular from '../../dist/rollup-plugin-angular.js'; 8 | import * as colors from 'colors'; 9 | 10 | process.chdir('test'); 11 | 12 | 13 | const bundle = () => { 14 | return rollup({ 15 | entry: 'mochats/component.ts', 16 | plugins: [ 17 | angular(), 18 | commonjs(), 19 | typescript({ 20 | typescript: require('./../../node_modules/typescript') 21 | }) 22 | ] 23 | }); 24 | } 25 | 26 | describe('rollup-plugin-angular', () => { 27 | console.info(`-------------------`); 28 | console.info(colors.blue(`start test mocha:ts`)); 29 | console.info(`-------------------`); 30 | beforeEach(() => { 31 | 32 | }); 33 | it('should not have example-component.html file content loaded from comment', () => { 34 | return bundle() 35 | .then(bundle => { 36 | return bundle 37 | .generate({ format: 'iife', moduleName: 'component' }) 38 | .then(generated => { 39 | assert.ok(generated.code); 40 | expect(generated.code.includes(`example-component.html content loaded`)).to.equal(false); 41 | return generated; 42 | }); 43 | }); 44 | }); 45 | 46 | it('should have component.html file content loaded', () => { 47 | return bundle() 48 | .then(bundle => { 49 | return bundle 50 | .generate({ format: 'iife', moduleName: 'component' }) 51 | .then(generated => { 52 | assert.ok(generated.code); 53 | expect(generated.code.includes(`component.html content loaded`)).to.equal(true); 54 | return generated; 55 | }); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/karma/test.component.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | // external 3 | import { DebugElement, NO_ERRORS_SCHEMA, ViewChild } from '@angular/core'; 4 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; 5 | import { By } from '@angular/platform-browser'; 6 | import { TestBed, async, inject, ComponentFixture } from '@angular/core/testing'; 7 | 8 | // internal 9 | import { TestComponent } from './test.component'; 10 | import { TestUserComponent } from './test-user.component'; 11 | 12 | beforeAll(() => { 13 | TestBed.resetTestEnvironment(); 14 | TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); 15 | }); 16 | 17 | describe('TestComponent', () => { 18 | 19 | let comp: TestComponent; 20 | let debugElement: DebugElement; 21 | let fixture: ComponentFixture; 22 | let nativeElement: HTMLElement; 23 | 24 | beforeEach(async(() => { 25 | TestBed.configureTestingModule({ 26 | declarations: [ 27 | TestComponent, 28 | TestUserComponent 29 | ] 30 | }).compileComponents(); 31 | })); 32 | 33 | // synchronous beforeEach 34 | beforeEach(() => { 35 | fixture = TestBed.createComponent(TestComponent); 36 | 37 | // get from fixture 38 | comp = fixture.componentInstance; 39 | nativeElement = fixture.nativeElement; 40 | debugElement = fixture.debugElement; 41 | }); 42 | 43 | it('should be defined', async(() => { 44 | expect(fixture).toBeDefined(); 45 | expect(comp).toBeTruthy(); 46 | console.info(fixture.componentRef); 47 | })); 48 | it('should have test.component.html loaded', async(() => { 49 | expect(nativeElement.textContent).toContain('test.component.html loaded'); 50 | })); 51 | it('should have test.component.html loaded', async(() => { 52 | expect(nativeElement.textContent).toContain('test-user.component.html content loaded'); 53 | })); 54 | }); 55 | -------------------------------------------------------------------------------- /test/mochajs/component.spec.js: -------------------------------------------------------------------------------- 1 | const { rollup } = require('rollup'); 2 | const assert = require('chai').assert; 3 | const expect = require('chai').expect; 4 | const angular = require('../../dist/rollup-plugin-angular.js'); 5 | const external = Object.keys(require('./../../package.json').dependencies).concat(['fs', 'path']); 6 | const colors = require('colors'); 7 | const sass = require('node-sass'); 8 | const cleanCSS = require('clean-css'); 9 | const htmlMinifier = require('html-minifier'); 10 | const cssmin = new cleanCSS(); 11 | const htmlminOpts = { 12 | caseSensitive: true, 13 | collapseWhitespace: true, 14 | removeComments: true 15 | }; 16 | 17 | process.chdir('test'); 18 | 19 | describe('rollup-plugin-angular', () => { 20 | console.info(`-------------------`); 21 | console.info(colors.blue(`start test mocha:js`)); 22 | console.info(`-------------------`); 23 | it('should not have component.html file content loaded from comment', () => { 24 | return rollup({ 25 | input: 'mochajs/component.js', 26 | external: external, 27 | plugins: [ 28 | angular({ 29 | replace: false 30 | }) 31 | ] 32 | }) 33 | .then(bundle => { 34 | return bundle 35 | .generate({ 36 | format: 'umd', 37 | name: 'component' 38 | }) 39 | .then(generated => { 40 | expect(generated.code.includes(`component.html content loaded`)).to.equal(false); 41 | assert.ok(generated.code); 42 | }); 43 | }); 44 | }); 45 | 46 | it('should have example-component.html file content loaded', () => { 47 | return rollup({ 48 | input: 'mochajs/example-component.js', 49 | external: external, 50 | plugins: [ 51 | angular({ 52 | preprocessors: { 53 | template: template => htmlMinifier.minify(template, htmlminOpts), 54 | style: scss => { 55 | const css = sass.renderSync({ data: scss }).css; 56 | return cssmin.minify(css).styles; 57 | }, 58 | } 59 | }) 60 | ] 61 | }) 62 | .then(bundle => { 63 | return bundle 64 | .generate({ 65 | format: 'umd', 66 | name: 'component' 67 | }) 68 | .then(generated => { 69 | expect(generated.code.includes(`blaah`)).to.equal(true); 70 | assert.ok(generated.code); 71 | }); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-plugin-angular", 3 | "version": "0.5.3", 4 | "description": "Angular2 template and styles inliner", 5 | "main": "dist/rollup-plugin-angular.js", 6 | "module": "dist/rollup-plugin-angular.esm.js", 7 | "scripts": { 8 | "build": "rollup -c", 9 | "prepublish": "npm run build", 10 | "test": "npm run build && npm run mocha:test && npm run karma:test", 11 | "karma:test": "./node_modules/karma/bin/karma start karma.conf.js", 12 | "mocha:js": "mocha test/mochajs/index.js --compilers js:buble/register --compilers js:babel-register; exit 0", 13 | "mocha:ts": "mocha test/mochats/index.ts --compilers ts:ts-node/register --timeout 2000; exit 0", 14 | "mocha:test": "npm run build && npm run mocha:js && npm run mocha:ts; exit 0;" 15 | }, 16 | "keywords": [ 17 | "angular2", 18 | "template", 19 | "styles", 20 | "inliner", 21 | "rollup-plugin" 22 | ], 23 | "files": [ 24 | "dist" 25 | ], 26 | "author": "Felix Itzenplitz", 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/cebor/rollup-plugin-angular.git" 30 | }, 31 | "license": "MIT", 32 | "dependencies": { 33 | "colors": "^1.1.2", 34 | "magic-string": "^0.22.4", 35 | "replace": "^0.3.0", 36 | "rollup-pluginutils": "^2.0.1" 37 | }, 38 | "devDependencies": { 39 | "@angular/common": "^4.3.5", 40 | "@angular/compiler": "^4.3.5", 41 | "@angular/core": "^4.3.5", 42 | "@angular/platform-browser": "^4.3.5", 43 | "@angular/platform-browser-dynamic": "^4.3.5", 44 | "@types/chai": "^4.0.4", 45 | "@types/jasmine": "^2.5.54", 46 | "@types/karma": "^0.13.36", 47 | "@types/mocha": "^2.2.42", 48 | "@types/node": "^8.0.24", 49 | "babel-register": "^6.26.0", 50 | "chai": "^4.1.1", 51 | "clean-css": "^4.1.7", 52 | "html-minifier": "^3.5.3", 53 | "jasmine": "^2.7.0", 54 | "jasmine-core": "^2.7.0", 55 | "karma": "^1.7.0", 56 | "karma-chrome-launcher": "^2.2.0", 57 | "karma-coverage": "^1.1.1", 58 | "karma-firefox-launcher": "^1.0.1", 59 | "karma-jasmine": "^1.1.0", 60 | "karma-rollup-preprocessor": "^4.0.4", 61 | "mocha": "^3.5.0", 62 | "node-sass": "^4.5.3", 63 | "reflect-metadata": "^0.1.10", 64 | "rollup": "^0.48.2", 65 | "rollup-plugin-buble": "^0.15.0", 66 | "rollup-plugin-commonjs": "^8.2.0", 67 | "rollup-plugin-node-resolve": "^3.0.0", 68 | "rollup-plugin-typescript": "^0.8.1", 69 | "rxjs": "^5.4.3", 70 | "ts-node": "^3.3.0", 71 | "typescript": "^2.5.1", 72 | "zone.js": "^0.8.16" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/cebor/rollup-plugin-angular.svg?branch=master)](https://travis-ci.org/cebor/rollup-plugin-angular) 2 | 3 | # rollup-plugin-angular 4 | Angular2 template and styles inliner for rollup 5 | 6 | ## Looking for new maintainer 7 | I have no time to maintain this plugin anymore. So im looking for a new Maintainer. Feel free to create an issue, when you want to maintain this plugin. 8 | 9 | ## Installation 10 | ```bash 11 | npm install --save-dev rollup-plugin-angular 12 | ``` 13 | 14 | ## Example 15 | ```javascript 16 | // rollup.config.js 17 | import angular from 'rollup-plugin-angular'; 18 | import typescript from 'rollup-plugin-typescript'; 19 | import alias from 'rollup-plugin-alias'; 20 | import nodeResolve from 'rollup-plugin-node-resolve'; 21 | 22 | export default { 23 | entry: 'src/main.ts', 24 | format: 'iife', 25 | dest: 'dist/bundle.js', 26 | plugins: [ 27 | angular(), 28 | typescript(), 29 | alias({ rxjs: __dirname + '/node_modules/rxjs-es' }), // rxjs fix (npm install rxjs-es) 30 | nodeResolve({ jsnext: true, main: true }) 31 | ] 32 | } 33 | ``` 34 | 35 | ## Template & Style preprocessing 36 | You may need to do some preprocessing on your templates & styles such as minification and/or transpilation. 37 | 38 | To do this you can pass a preprocessors object as an option, containing a style and/or template preprocessor. 39 | 40 | If you are using rollup on a source that has already been transpiled to JavaScript you will also need to set the sourcetype. 41 | 42 | ### Signature 43 | ```typescript 44 | sourcetype: 'js' //defaults to 'ts' 45 | preprocessors: { 46 | template: (source: string, path: string) => string, 47 | style: (source: string, path: string) => string, 48 | } 49 | ``` 50 | `source` - The contents of the style or template's file. 51 | 52 | `path` - The path to the loaded file. Can be useful for checking file extensions for example. 53 | 54 | returns the manipulated source as a string. 55 | 56 | ### Example 57 | The following example shows how you can use sass, clean-css (for css minification), and htmlmin. 58 | 59 | ```javascript 60 | // rollup.config.js 61 | import angular from 'rollup-plugin-angular'; 62 | import typescript from 'rollup-plugin-typescript'; 63 | import nodeResolve from 'rollup-plugin-node-resolve'; 64 | import sass from 'node-sass'; 65 | import CleanCSS from 'clean-css'; 66 | import { minify as minifyHtml } from 'html-minifier'; 67 | 68 | const cssmin = new CleanCSS(); 69 | const htmlminOpts = { 70 | caseSensitive: true, 71 | collapseWhitespace: true, 72 | removeComments: true, 73 | }; 74 | 75 | export default { 76 | input: 'src/main.ts', 77 | output: { 78 | format: 'umd', 79 | file: 'dist/bundle.js' 80 | }, 81 | plugins: [ 82 | angular({ 83 | // additional replace `templateUrl` and `stylesUrls` in every `.js` file 84 | // default: true 85 | replace: false, 86 | preprocessors: { 87 | template: template => minifyHtml(template, htmlminOpts), 88 | style: scss => { 89 | const css = sass.renderSync({ data: scss }).css; 90 | return cssmin.minify(css).styles; 91 | }, 92 | } 93 | }) 94 | typescript(), 95 | nodeResolve({ jsnext: true, main: true }) 96 | ] 97 | } 98 | ``` 99 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | 3 | const angular = require('./dist/rollup-plugin-angular.js'); 4 | const commonjs = require('rollup-plugin-commonjs'); 5 | const nodeResolve = require('rollup-plugin-node-resolve'); 6 | const typescript = require('rollup-plugin-typescript'); 7 | 8 | module.exports = function(config) { 9 | config.set({ 10 | 11 | // base path that will be used to resolve all patterns (eg. files, exclude) 12 | basePath: '', 13 | 14 | 15 | // frameworks to use 16 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 17 | frameworks: ['jasmine'], 18 | 19 | 20 | // list of files / patterns to load in the browser 21 | files: [ 22 | 'test/karma/*.ts' 23 | ], 24 | 25 | 26 | plugins: [ 27 | require('karma-coverage'), 28 | require('karma-chrome-launcher'), 29 | require('karma-firefox-launcher'), 30 | require('karma-rollup-preprocessor'), 31 | require('karma-jasmine') 32 | ], 33 | 34 | 35 | // list of files to exclude 36 | exclude: [], 37 | 38 | 39 | // preprocess matching files before serving them to the browser 40 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 41 | preprocessors: { 42 | 'test/karma/*.ts': ['rollup'] 43 | }, 44 | 45 | 46 | rollupPreprocessor: { 47 | context: 'this', 48 | // will help to prevent conflicts between different tests entries 49 | moduleName: 'examplemodule', 50 | format: 'umd', 51 | sourceMap: 'inline', 52 | // rollup settings. See Rollup documentation 53 | plugins: [ 54 | angular(), 55 | commonjs(), 56 | nodeResolve({ 57 | // use "es2015" field for ES2015 modules with ES2015 code, 58 | // if possible 59 | es2015: true, // Default: false 60 | 61 | // use "module" field for ES2015 modules with ES5 code, 62 | // if possible 63 | module: true, // Default: true 64 | 65 | // use "jsnext:main" if possible 66 | // – see https://github.com/rollup/rollup/wiki/jsnext:main 67 | jsnext: true, // Default: false 68 | 69 | // use "main" field or index.js, even if it's not an ES6 module 70 | // (needs to be converted from CommonJS to ES6 71 | // – see https://github.com/rollup/rollup-plugin-commonjs 72 | main: true, // Default: true 73 | 74 | extensions: [ '.js', '.json' ] 75 | }), 76 | typescript({ 77 | typescript: require('./node_modules/typescript') 78 | }), 79 | ], 80 | }, 81 | 82 | 83 | // test results reporter to use 84 | // possible values: 'dots', 'progress' 85 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 86 | reporters: ['progress'], 87 | 88 | 89 | // web server port 90 | port: 9876, 91 | 92 | 93 | // enable / disable colors in the output (reporters and logs) 94 | colors: true, 95 | 96 | 97 | // level of logging 98 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 99 | logLevel: config.LOG_INFO, 100 | 101 | 102 | // enable / disable watching file and executing tests whenever any file changes 103 | autoWatch: true, 104 | 105 | 106 | mime: { 107 | 'text/x-typescript': ['ts','tsx'] 108 | }, 109 | 110 | 111 | // start these browsers 112 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 113 | browsers: ['Firefox'], 114 | 115 | // Continuous Integration mode 116 | // if true, Karma captures browsers, runs the tests and exits 117 | singleRun: true, 118 | 119 | // Concurrency level 120 | // how many browser should be started simultaneous 121 | concurrency: Infinity 122 | }) 123 | } 124 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import * as colors from 'colors'; 4 | import replace from 'replace'; 5 | 6 | import MagicString from 'magic-string'; 7 | import { createFilter } from 'rollup-pluginutils'; 8 | 9 | const moduleIdRegex = /moduleId\s*:(.*)/g; 10 | const componentRegex = /@Component\(\s?{([\s\S]*)}\s?\)$|type:\s?Component,\s?args:\s?\[\s?{([\s\S]*)},\s?\]/gm; 11 | const commentRegex = /\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm; // http://www.regextester.com/?fam=96247 12 | const templateUrlRegex = /templateUrl\s*:(.*)/g; 13 | const styleUrlsRegex = /styleUrls\s*:(\s*\[[\s\S]*?\])/g; // http://www.regextester.com/?fam=98594 14 | const stringRegex = /(['"`])((?:[^\\]\\\1|.)*?)\1/g; 15 | 16 | function insertText(str, dir, preprocessor = res => res, processFilename = false, sourceType = 'ts') { 17 | let quoteChar = sourceType === 'ts' ? '`' : '"'; 18 | return str.replace(stringRegex, function (match, quote, url) { 19 | const includePath = path.join(dir, url); 20 | if (processFilename) { 21 | return quoteChar + preprocessor(includePath) + quoteChar; 22 | } 23 | const text = fs.readFileSync(includePath).toString(); 24 | return quoteChar + preprocessor(text, includePath) + quoteChar; 25 | }); 26 | } 27 | 28 | export default function angular(options = {}) { 29 | options.preprocessors = options.preprocessors || {}; // set default preprocessors to `{}` 30 | options.replace = (typeof options.replace === 'boolean') ? options.replace : true; // set default replace to `true` 31 | 32 | // ignore @angular/** modules 33 | options.exclude = options.exclude || []; 34 | if (typeof options.exclude === 'string' || options.exclude instanceof String) { 35 | options.exclude = [options.exclude]; 36 | } 37 | if (options.exclude.indexOf('node_modules/@angular/**') === -1) { 38 | options.exclude.push('node_modules/@angular/**'); 39 | } 40 | 41 | const filter = createFilter(options.include, options.exclude); 42 | 43 | return { 44 | name: 'angular', 45 | transform(source, map) { 46 | if (!filter(map)) return; 47 | // replace comments in source 48 | source = source.replace(commentRegex, ''); 49 | // use MagicString 50 | const magicString = new MagicString(source); 51 | // get dir from `map` 52 | const dir = path.parse(map).dir; 53 | // get file extension from `map` 54 | const fileExt = map.split('.').pop(); 55 | 56 | let hasReplacements = false; 57 | let match; 58 | let start, end, replacement; 59 | 60 | while ((match = componentRegex.exec(source)) !== null) { 61 | start = match.index; 62 | end = start + match[0].length; 63 | 64 | replacement = match[0] 65 | .replace(templateUrlRegex, function (match, url) { 66 | hasReplacements = true; 67 | const toReplace = 'template:' + insertText(url, dir, options.preprocessors.template, options.processFilename, options.sourcetype); 68 | if (fileExt === 'js' && options.replace === true) { 69 | /* replace templateUrl in files generated by ngc */ 70 | replace({ 71 | regex: match, 72 | replacement: toReplace, 73 | paths: [map], 74 | recursive: true, 75 | silent: true, 76 | }); 77 | console.info(`templateUrl in file ${map} has been changed from ${colors.green(match)} to ${colors.green(toReplace)}`); 78 | } 79 | return toReplace; 80 | }) 81 | .replace(styleUrlsRegex, function (match, urls) { 82 | hasReplacements = true; 83 | const toReplace = 'styles:' + insertText(urls, dir, options.preprocessors.style, options.processFilename, options.sourcetype); 84 | /* replace styles in files generated by ngc */ 85 | if (fileExt === 'js' && options.replace === true) { 86 | replace({ 87 | regex: styleUrlsRegex, 88 | replacement: toReplace, 89 | paths: [map], 90 | recursive: true, 91 | silent: true, 92 | }); 93 | console.info(`styleUrls in file ${map} has been changed from ${colors.green(match)} to ${colors.green(toReplace)}`); 94 | } 95 | return toReplace; 96 | }) 97 | .replace(moduleIdRegex, function (match, moduleId) { 98 | hasReplacements = true; 99 | return ''; 100 | }); 101 | if (hasReplacements) { 102 | magicString.overwrite(start, end, replacement); 103 | } 104 | } 105 | 106 | if (!hasReplacements) { 107 | return null; 108 | } 109 | 110 | let result = { code: magicString.toString() }; 111 | 112 | if (options.sourceMap !== false) { 113 | result.map = magicString.generateMap({ hires: true }); 114 | } 115 | return result; 116 | } 117 | }; 118 | } 119 | --------------------------------------------------------------------------------