Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

NG9 #28

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

NG9 #28

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"aot": true,
"outputPath": "dist/browser",
"index": "src/index.html",
"main": "src/main.ts",
Expand All @@ -29,8 +30,7 @@
"node_modules/systemjs/dist/s.js",
"node_modules/systemjs/dist/extras/named-register.js",
"node_modules/systemjs/dist/extras/amd.js"
],
"es5BrowserSupport": true
]
},
"configurations": {
"production": {
Expand All @@ -54,6 +54,10 @@
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
]
}
Expand Down Expand Up @@ -109,7 +113,7 @@
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/server",
"main": "src/main.server.ts",
"main": "server.ts",
"tsConfig": "src/tsconfig.server.json"
},
"configurations": {
Expand All @@ -120,8 +124,35 @@
"with": "src/environments/environment.prod.ts"
}
]
, "optimization": true
}
}
},
"serve-ssr": {
"builder": "@nguniversal/builders:ssr-dev-server",
"options": {
"browserTarget": "angular-plugin-architecture:build",
"serverTarget": "angular-plugin-architecture:server"
},
"configurations": {
"production": {
"browserTarget": "angular-plugin-architecture:build:production",
"serverTarget": "angular-plugin-architecture:server:production"
}
}
},
"prerender": {
"builder": "@nguniversal/builders:prerender",
"options": {
"browserTarget": "angular-plugin-architecture:build:production",
"serverTarget": "angular-plugin-architecture:server:production",
"routes": [
"/"
]
},
"configurations": {
"production": {}
}
}
}
},
Expand All @@ -142,8 +173,7 @@
"tsConfig": "projects/plugins/tsconfig.app.json",
"assets": [],
"styles": [],
"scripts": [],
"es5BrowserSupport": false
"scripts": []
},
"configurations": {
"production": {
Expand Down Expand Up @@ -181,7 +211,12 @@
"tsConfig": "projects/shared/tsconfig.lib.json",
"project": "projects/shared/ng-package.json"
}
},
, "configurations": {
"production": {
"tsConfig": "projects/shared/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
Expand All @@ -206,4 +241,4 @@
}
},
"defaultProject": "angular-plugin-architecture"
}
}
12 changes: 12 additions & 0 deletions browserslist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# You can see what browsers were selected by your queries by running:
# npx browserslist

> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.
2 changes: 1 addition & 1 deletion builders/builders.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"builders": {
"plugin": {
"class": "./plugin-builder",
"implementation": "./plugin-builder",
"schema": "./plugin-builder/schema.json",
"description": "Plugin Builder"
}
Expand Down
210 changes: 105 additions & 105 deletions builders/plugin-builder/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import {
BrowserBuilder,
NormalizedBrowserBuilderSchema
} from '@angular-devkit/build-angular';
import { Path, virtualFs } from '@angular-devkit/core';
import { BrowserBuilderOutput, executeBrowserBuilder, ExecutionTransformer } from '@angular-devkit/build-angular';
import { JsonObject } from '@angular-devkit/core';
import { createBuilder, BuilderContext } from '@angular-devkit/architect';
import * as fs from 'fs';
import * as webpack from 'webpack';
import { tap } from 'rxjs/operators';
import { Observable } from 'rxjs';

import { BuilderConfiguration, BuildEvent } from '@angular-devkit/architect';
import { tap } from 'rxjs/operators';

interface PluginBuilderSchema extends NormalizedBrowserBuilderSchema {
interface Options extends JsonObject {
/**
* A string of the form `path/to/file#exportName` that acts as a path to include to bundle
*/
Expand All @@ -25,109 +23,111 @@ interface PluginBuilderSchema extends NormalizedBrowserBuilderSchema {
*/
sharedLibs: string;
}
export default class PluginBuilder extends BrowserBuilder {
private options: PluginBuilderSchema;

private entryPointPath: string;
let entryPointPath;

function buildPlugin(options: Options,
context: BuilderContext,
transforms: {
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>,
} = {}): Observable<BrowserBuilderOutput> {
options.deleteOutputPath = false;

validateOptions(options);

const originalWebpackConfigurationFn = transforms.webpackConfiguration;
transforms.webpackConfiguration = (config: webpack.Configuration) => {
patchWebpackConfig(config, options);

return originalWebpackConfigurationFn ? originalWebpackConfigurationFn(config) : config;
};

const result = executeBrowserBuilder(options as any, context, transforms);

return result.pipe(tap(() => {
patchEntryPoint('');
}));
}

patchEntryPoint(contents: string) {
fs.writeFileSync(this.entryPointPath, contents);
function patchEntryPoint(contents: string) {
fs.writeFileSync(entryPointPath, contents);
}

function validateOptions(options: Options) {
const { pluginName, modulePath } = options;

if (!modulePath) {
throw Error('Please define modulePath!');
}

if (!pluginName) {
throw Error('Please provide pluginName!');
}
}

buildWebpackConfig(
root: Path,
projectRoot: Path,
host: virtualFs.Host<fs.Stats>,
options: PluginBuilderSchema
) {
const { pluginName, sharedLibs } = this.options;

if (!this.options.modulePath) {
throw Error('Please define modulePath!');
}

if (!pluginName) {
throw Error('Please provide pluginName!');
}

const config = super.buildWebpackConfig(root, projectRoot, host, options);

// Make sure we are producing a single bundle
delete config.entry.polyfills;
delete config.optimization.runtimeChunk;
delete config.optimization.splitChunks;
delete config.entry.styles;

config.externals = {
rxjs: 'rxjs',
'@angular/core': 'ng.core',
'@angular/common': 'ng.common',
'@angular/forms': 'ng.forms',
'@angular/router': 'ng.router',
tslib: 'tslib'
// put here other common dependencies
};

if (sharedLibs) {
config.externals = [config.externals];
const sharedLibsArr = sharedLibs.split(',');
sharedLibsArr.forEach(sharedLibName => {
const factoryRegexp = new RegExp(`${sharedLibName}.ngfactory$`);
config.externals[0][sharedLibName] = sharedLibName; // define external for code
config.externals.push((context, request, callback) => {
if (factoryRegexp.test(request)) {
return callback(null, sharedLibName); // define external for factory
}
callback();
});
function patchWebpackConfig(config: webpack.Configuration, options: Options) {
const { pluginName, sharedLibs } = options;

// Make sure we are producing a single bundle
delete config.entry.polyfills;
delete config.entry['polyfills-es5'];
delete config.optimization.runtimeChunk;
delete config.optimization.splitChunks;
delete config.entry.styles;

config.externals = {
rxjs: 'rxjs',
'@angular/core': 'ng.core',
'@angular/common': 'ng.common',
'@angular/forms': 'ng.forms',
'@angular/router': 'ng.router',
tslib: 'tslib'
// put here other common dependencies
};

if (sharedLibs) {
config.externals = [config.externals];
const sharedLibsArr = sharedLibs.split(',');
sharedLibsArr.forEach(sharedLibName => {
const factoryRegexp = new RegExp(`${sharedLibName}.ngfactory$`);
config.externals[0][sharedLibName] = sharedLibName; // define external for code

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In sharedLibsArr there is ngfactory$, how is that going to work with ivy?

config.externals.push((context, request, callback) => {
if (factoryRegexp.test(request)) {
return callback(null, sharedLibName); // define external for factory
}
callback();
});
}

const ngCompilerPluginInstance = config.plugins.find(
x => x.constructor && x.constructor.name === 'AngularCompilerPlugin'
);
if (ngCompilerPluginInstance) {
ngCompilerPluginInstance._entryModule = this.options.modulePath;
}

// preserve path to entry point
// so that we can clear use it within `run` method to clear that file
this.entryPointPath = config.entry.main[0];

const [modulePath, moduleName] = this.options.modulePath.split('#');

const factoryPath = `${
modulePath.includes('.') ? modulePath : `${modulePath}/${modulePath}`
}.ngfactory`;
const entryPointContents = `
export * from '${modulePath}';
export * from '${factoryPath}';
import { ${moduleName}NgFactory } from '${factoryPath}';
export default ${moduleName}NgFactory;
`;
this.patchEntryPoint(entryPointContents);

config.output.filename = `${pluginName}.js`;
config.output.library = pluginName;
config.output.libraryTarget = 'umd';
// workaround to support bundle on nodejs
config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`;

return config;
});
}

run(
builderConfig: BuilderConfiguration<PluginBuilderSchema>
): Observable<BuildEvent> {
this.options = builderConfig.options;
// I don't want to write it in my scripts every time so I keep it here
builderConfig.options.deleteOutputPath = false;

return super.run(builderConfig).pipe(
tap(() => {
// clear entry point so our main.ts is always empty
this.patchEntryPoint('');
})
);
const ngCompilerPluginInstance = config.plugins.find(
x => x.constructor && x.constructor.name === 'AngularCompilerPlugin'
);
if (ngCompilerPluginInstance) {
ngCompilerPluginInstance._entryModule = options.modulePath;
}

// preserve path to entry point
// so that we can clear use it within `run` method to clear that file
entryPointPath = config.entry.main[0];

const [modulePath, moduleName] = options.modulePath.split('#');

// const factoryPath = `${
// modulePath.includes('.') ? modulePath : `${modulePath}/${modulePath}`
// }.ngfactory`;
const entryPointContents = `
export * from '${modulePath}';
import { ${moduleName} } from '${modulePath}';
export default ${moduleName};
`;
patchEntryPoint(entryPointContents);

config.output.filename = `${pluginName}.js`;
config.output.library = pluginName;
config.output.libraryTarget = 'umd';
// workaround to support bundle on nodejs
config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`;
}

export default createBuilder<Options>(buildPlugin);
Loading