feat(build): update angular-cli.json (#1633)

This commit is contained in:
Filipe Silva 2016-08-19 20:39:09 +01:00 committed by GitHub
parent 3b226be22f
commit 3dcd49bc62
30 changed files with 274 additions and 186 deletions

View File

@ -37,13 +37,14 @@ The generated project has dependencies that require **Node 4 or greater**.
* [Generating a Route](#generating-a-route)
* [Creating a Build](#creating-a-build)
* [Build Targets and Environment Files](#build-targets-and-environment-files)
* [Bundling](#bundling)
* [Adding extra files to the build](#adding-extra-files-to-the-build)
* [Running Unit Tests](#running-unit-tests)
* [Running End-to-End Tests](#running-end-to-end-tests)
* [Deploying the App via GitHub Pages](#deploying-the-app-via-github-pages)
* [Linting and formatting code](#linting-and-formatting-code)
* [Support for offline applications](#support-for-offline-applications)
* [Commands autocompletion](#commands-autocompletion)
* [Global styles](#global-styles)
* [CSS preprocessor integration](#css-preprocessor-integration)
* [3rd Party Library Installation](#3rd-party-library-installation)
* [Updating angular-cli](#updating-angular-cli)
@ -126,8 +127,8 @@ A build can specify both a build target (`development` or `production`) and an
environment file to be used with that build. By default, the development build
target is used.
At build time, `src/app/environments/environment.ts` will be replaced by
`src/app/environments/environment.{NAME}.ts` where `NAME` is the argument
At build time, `src/environments/environment.ts` will be replaced by
`src/environments/environment.NAME.ts` where `NAME` is the argument
provided to the `--environment` flag.
These options also apply to the serve command. If you do not pass a value for `environment`,
@ -145,14 +146,15 @@ ng build --dev
ng build
```
You can also add your own env files other than `dev` and `prod` by creating a
`src/app/environments/environment.{NAME}.ts` and use them by using the `--env=NAME`
flag on the build/serve commands.
You can also add your own env files other than `dev` and `prod` by doing the following:
- create a `src/environments/environment.NAME.ts`
- add `{ NAME: 'src/environments/environment.NAME.ts' }` to the the `apps[0].environments` object in `angular-cli.json`
- use them by using the `--env=NAME` flag on the build/serve commands.
### Bundling
Builds created with the `-prod` flag via `ng build -prod` or `ng serve -prod` bundle
all dependencies into a single file, and make use of tree-shaking techniques.
All builds make use of bundling, and using the `--prod` flag in `ng build --prod`
or `ng serve --prod` will also make use of uglifying and tree-shaking functionality.
### Running unit tests
@ -240,6 +242,13 @@ ng completion >> ~/.bash_profile
source ~/.bash_profile
```
### Global styles
The `styles.css` file allows users to add global styles and supports
[CSS imports](https://developer.mozilla.org/en/docs/Web/CSS/@import).
If the project is created with the `--style=sass` option, this will be a `.sass`
file instead, and the same applies to `scss/less/styl`.
### CSS Preprocessor integration

View File

@ -25,9 +25,9 @@ module.exports = {
var defaultPrefix = '';
if (this.project.ngConfig &&
this.project.ngConfig.defaults &&
this.project.ngConfig.defaults.prefix) {
defaultPrefix = this.project.ngConfig.defaults.prefix + '-';
this.project.ngConfig.apps[0] &&
this.project.ngConfig.apps[0].prefix) {
defaultPrefix = this.project.ngConfig.apps[0].prefix + '-';
}
var prefix = this.options.prefix ? defaultPrefix : '';
this.selector = stringUtils.dasherize(prefix + parsedPath.name);
@ -97,7 +97,7 @@ module.exports = {
dir = dirParts.join(path.sep);
}
}
var srcDir = this.project.ngConfig.defaults.sourceDir;
var srcDir = this.project.ngConfig.apps[0].root;
this.appDir = dir.substr(dir.indexOf(srcDir) + srcDir.length);
this.generatePath = dir;
return dir;

View File

@ -1,3 +1,2 @@
export * from './environments/environment';
export * from './app.component';
export * from './app.module';

View File

@ -1,6 +1,9 @@
import "./polyfills.ts";
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule, environment } from './app/';
import { environment } from './environments/environment';
import { AppModule } from './app/';
if (environment.production) {
enableProdMode();

View File

@ -1,4 +1,5 @@
// Prefer CoreJS over the polyfills above
// This file includes polyfills needed by Angular 2 and is loaded before
// the app. You can add your own extra polyfills to this file.
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';

View File

@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View File

@ -1,10 +1,5 @@
import 'core-js/es6';
import 'core-js/es7/reflect';
import "./polyfills.ts";
// Typescript emit helpers polyfill
import 'ts-helpers';
import 'zone.js/dist/zone';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';

View File

@ -5,9 +5,21 @@
},
"apps": [
{
"main": "<%= sourceDir %>/main.ts",
"tsconfig": "<%= sourceDir %>/tsconfig.json",
"mobile": <%= isMobile %>
"root": "<%= sourceDir %>",
"outDir": "dist",
"assets": "assets",
"index": "index.html",
"main": "main.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "<%= prefix %>",
"mobile": <%= isMobile %>,
"styles": "styles.<%= styleExt %>",
"environments": {
"source": "environments/environment.ts",
"prod": "environments/environment.prod.ts",
"dev": "environments/environment.dev.ts"
}
}
],
"addons": [],
@ -23,8 +35,6 @@
}
},
"defaults": {
"prefix": "<%= prefix %>",
"sourceDir": "<%= sourceDir %>",
"styleExt": "<%= styleExt %>",
"prefixInterfaces": false,
"lazyRoutePrefix": "+"

View File

@ -6,8 +6,9 @@ import * as chalk from 'chalk';
import * as fs from 'fs';
import * as fse from 'fs-extra';
import * as path from 'path';
import * as BuildTask from 'ember-cli/lib/tasks/build';
import * as WebpackBuild from '../tasks/build-webpack';
import * as CreateGithubRepo from '../tasks/create-github-repo';
import { CliConfig } from '../models/config';
const fsReadFile = Promise.denodeify(fs.readFile);
const fsWriteFile = Promise.denodeify(fs.writeFile);
@ -27,10 +28,15 @@ module.exports = Command.extend({
default: 'new gh-pages version',
description: 'The commit message to include with the build, must be wrapped in quotes.'
}, {
name: 'environment',
name: 'target',
type: String,
default: 'production',
description: 'The Angular environment to create a build for'
aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }]
}, {
name: 'environment',
type: String,
default: '',
aliases: ['e']
}, {
name: 'user-page',
type: Boolean,
@ -59,8 +65,20 @@ module.exports = Command.extend({
var execOptions = {
cwd: root
};
if (options.environment === ''){
if (options.target === 'development') {
options.environment = 'dev';
}
if (options.target === 'production') {
options.environment = 'prod';
}
}
var projectName = this.project.pkg.name;
const outDir = CliConfig.fromProject().apps[0].outDir;
let ghPagesBranch = 'gh-pages';
let destinationBranch = options.userPage ? 'master' : ghPagesBranch;
let initialBranch;
@ -68,15 +86,19 @@ module.exports = Command.extend({
// declared here so that tests can stub exec
const execPromise = Promise.denodeify(exec);
var buildTask = new BuildTask({
var buildTask = new WebpackBuild({
ui: this.ui,
analytics: this.analytics,
project: this.project
cliProject: this.project,
target: options.target,
environment: options.environment,
outputPath: outDir
});
var buildOptions = {
target: options.target,
environment: options.environment,
outputPath: 'dist/'
outputPath: outDir
};
var createGithubRepoTask = new CreateGithubRepo({
@ -155,13 +177,13 @@ module.exports = Command.extend({
}
function copyFiles() {
return fsReadDir('dist')
return fsReadDir(outDir)
.then((files) => Promise.all(files.map((file) => {
if (file === '.gitignore'){
// don't overwrite the .gitignore file
return Promise.resolve();
}
return fsCopy(path.join('dist', file), path.join('.', file))
return fsCopy(path.join(outDir, file), path.join('.', file))
})));
}

View File

@ -46,7 +46,6 @@ module.exports = Command.extend({
{ name: 'live-reload-live-css', type: Boolean, default: true, description: 'Whether to live reload CSS (default true)' },
{ name: 'target', type: String, default: 'development', aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }] },
{ name: 'environment', type: String, default: '', aliases: ['e'] },
{ name: 'output-path', type: 'Path', default: 'dist/', aliases: ['op', 'out'] },
{ name: 'ssl', type: Boolean, default: false },
{ name: 'ssl-key', type: String, default: 'ssl/server.key' },
{ name: 'ssl-cert', type: String, default: 'ssl/server.crt' }

View File

@ -1,5 +1,6 @@
import * as fs from 'fs';
import * as path from 'path';
import * as chalk from 'chalk';
const schemaPath = path.resolve(process.env.CLI_ROOT, 'lib/config/schema.json');
const schema = require(schemaPath);
@ -166,6 +167,24 @@ export class CliConfig {
public static fromProject(): any {
const configPath = CliConfig._configFilePath();
return configPath ? require(configPath) : {};
if (!configPath) {
return {};
}
let config = require(configPath);
if (config.defaults.sourceDir || config.defaults.prefix) {
config.apps[0].root = config.apps[0].root || config.defaults.sourceDir;
config.apps[0].prefix = config.apps[0].prefix || config.defaults.prefix;
console.error(chalk.yellow(
'The "defaults.prefix" and "defaults.sourceDir" properties of angular-cli.json '
+ 'are deprecated in favor of "apps[0].root" and "apps[0].prefix".\n'
+ 'Please update in order to avoid errors in future versions of angular-cli.'
));
}
return config;
}
}

View File

@ -6,25 +6,25 @@ import * as atl from 'awesome-typescript-loader';
import {findLazyModules} from './find-lazy-modules';
export function getWebpackCommonConfig(projectRoot: string, environment: string, appConfig: any) {
export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, outputDir: string) {
const sourceRoot = path.resolve(projectRoot, sourceDir);
const outputPath = path.resolve(projectRoot, outputDir);
const lazyModules = findLazyModules(path.resolve(projectRoot, sourceDir));
const appRoot = path.resolve(projectRoot, appConfig.root);
const appMain = path.resolve(appRoot, appConfig.main);
const styles = path.resolve(appRoot, appConfig.styles);
const lazyModules = findLazyModules(appRoot);
return {
devtool: 'source-map',
resolve: {
extensions: ['', '.ts', '.js'],
root: sourceRoot
root: appRoot
},
context: path.resolve(__dirname, './'),
entry: {
main: [path.join(sourceRoot, 'main.ts')],
polyfills: path.join(sourceRoot, 'polyfills.ts')
main: [appMain, styles]
},
output: {
path: outputPath,
path: path.resolve(projectRoot, appConfig.outDir),
filename: '[name].bundle.js'
},
module: {
@ -45,7 +45,7 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, o
loader: 'awesome-typescript-loader',
query: {
useForkChecker: true,
tsconfig: path.resolve(sourceRoot, 'tsconfig.json')
tsconfig: path.resolve(appRoot, appConfig.tsconfig)
}
}, {
loader: 'angular2-template-loader'
@ -53,25 +53,43 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, o
],
exclude: [/\.(spec|e2e)\.ts$/]
},
{ test: /\.json$/, loader: 'json-loader'},
{ test: /\.css$/, loaders: ['raw-loader', 'postcss-loader'] },
{ test: /\.styl$/, loaders: ['raw-loader', 'postcss-loader', 'stylus-loader'] },
{ test: /\.less$/, loaders: ['raw-loader', 'postcss-loader', 'less-loader'] },
{ test: /\.scss$|\.sass$/, loaders: ['raw-loader', 'postcss-loader', 'sass-loader'] },
{ test: /\.(jpg|png)$/, loader: 'url-loader?limit=128000'},
{ test: /\.html$/, loader: 'raw-loader' }
// in main, load css as raw text
       { exclude: styles, test: /\.css$/, loaders: ['raw-loader', 'postcss-loader'] },
       { exclude: styles, test: /\.styl$/, loaders: ['raw-loader', 'postcss-loader', 'stylus-loader'] },
       { exclude: styles, test: /\.less$/, loaders: ['raw-loader', 'postcss-loader', 'less-loader'] },
       { exclude: styles, test: /\.scss$|\.sass$/, loaders: ['raw-loader', 'postcss-loader', 'sass-loader'] },
// outside of main, load it via style-loader
       { include: styles, test: /\.css$/, loaders: ['style-loader', 'css-loader', 'postcss-loader'] },
       { include: styles, test: /\.styl$/, loaders: ['style-loader', 'css-loader', 'postcss-loader', 'stylus-loader'] },
       { include: styles, test: /\.less$/, loaders: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'] },
       { include: styles, test: /\.scss$|\.sass$/, loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] },
       { test: /\.json$/, loader: 'json-loader' },
       { test: /\.(jpg|png)$/, loader: 'url-loader?limit=10000' },
       { test: /\.html$/, loader: 'raw-loader' },
{ test: /\.(woff|ttf|svg)$/, loader: 'url?limit=10000' },
{ test: /\.woff2$/, loader: 'url?limit=10000&mimetype=font/woff2' },
{ test: /\.eot$/, loader: 'file' }
]
},
plugins: [
new webpack.ContextReplacementPlugin(/.*/, sourceRoot, lazyModules),
new webpack.ContextReplacementPlugin(/.*/, appRoot, lazyModules),
new atl.ForkCheckerPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(sourceRoot, 'index.html'),
template: path.resolve(appRoot, appConfig.index),
chunksSortMode: 'dependency'
}),
new webpack.optimize.CommonsChunkPlugin({
name: ['polyfills']
}),
new webpack.NormalModuleReplacementPlugin(
// This plugin is responsible for swapping the environment files.
// Since it takes a RegExp as first parameter, we need to escape the path.
// See https://webpack.github.io/docs/list-of-plugins.html#normalmodulereplacementplugin
new RegExp(path.resolve(appRoot, appConfig.environments.source)
.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")),
path.resolve(appRoot, appConfig.environments[environment])
),
new webpack.optimize.CommonsChunkPlugin({
minChunks: Infinity,
name: 'inline',
@ -79,10 +97,10 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, o
sourceMapFilename: 'inline.map'
}),
new CopyWebpackPlugin([{
context: path.resolve(projectRoot, './public'),
context: path.resolve(appRoot, appConfig.assets),
from: '**/*',
to: outputPath
}]),
to: path.resolve(projectRoot, appConfig.outDir, appConfig.assets)
}])
],
node: {
fs: 'empty',

View File

@ -1,12 +1,10 @@
import { CliConfig } from './config';
const path = require('path')
export const getWebpackDevConfigPartial = function(projectRoot: string, sourceDir: string, outputDir: string) {
export const getWebpackDevConfigPartial = function(projectRoot: string, appConfig: any) {
return {
devtool: 'source-map',
output: {
path: path.resolve(projectRoot, outputDir),
path: path.resolve(projectRoot, appConfig.outDir),
filename: '[name].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].chunk.js'
@ -14,7 +12,7 @@ export const getWebpackDevConfigPartial = function(projectRoot: string, sourceDi
tslint: {
emitErrors: false,
failOnHint: false,
resourcePath: path.resolve(projectRoot, `./${sourceDir}`)
resourcePath: path.resolve(projectRoot, appConfig.root)
},
node: {
fs: 'empty',

View File

@ -3,26 +3,26 @@ import * as path from 'path';
import * as OfflinePlugin from 'offline-plugin';
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
import { PrerenderWebpackPlugin } from '../utilities/prerender-webpack-plugin.ts';
import { CliConfig } from './config';
export const getWebpackMobileConfigPartial = function (projectRoot: string, sourceDir: string, outputDir: string) {
let outputPath: string = path.resolve(projectRoot, outputDir);
export const getWebpackMobileConfigPartial = function (projectRoot: string, appConfig: any) {
// Hardcoded files and paths here should be part of appConfig when
// reworking the mobile app functionality
return {
plugins: [
new CopyWebpackPlugin([
{from: path.resolve(projectRoot, `./${sourceDir}/icons`), to: path.resolve(outputPath, './icons')},
{from: path.resolve(projectRoot, `./${sourceDir}/manifest.webapp`), to: outputPath}
{from: path.resolve(projectRoot, appConfig.root, 'icons'), to: path.resolve(projectRoot, appConfig.outDir, 'icons')},
{from: path.resolve(projectRoot, appConfig.root, 'manifest.webapp'), to: path.resolve(projectRoot, appConfig.outDir)}
]),
new PrerenderWebpackPlugin({
templatePath: 'index.html',
configPath: path.resolve(projectRoot, `./${sourceDir}/main-app-shell.ts`),
appPath: path.resolve(projectRoot, `./${sourceDir}`)
configPath: path.resolve(projectRoot, appConfig.root, 'main-app-shell.ts'),
appPath: path.resolve(projectRoot, appConfig.root)
})
]
}
};
export const getWebpackMobileProdConfigPartial = function (projectRoot: string, sourceDir: string) {
export const getWebpackMobileProdConfigPartial = function (projectRoot: string, appConfig: any) {
return {
entry: {
'sw-install': path.resolve(__dirname, '../utilities/sw-install.js')

View File

@ -3,15 +3,13 @@ import * as webpackMerge from 'webpack-merge'; // used to merge webpack configs
import * as WebpackMd5Hash from 'webpack-md5-hash';
import * as CompressionPlugin from 'compression-webpack-plugin';
import * as webpack from 'webpack';
import { CliConfig } from './config';
export const getWebpackProdConfigPartial = function(projectRoot: string, sourceDir: string, outputDir: string) {
export const getWebpackProdConfigPartial = function(projectRoot: string, appConfig: any) {
return {
debug: false,
devtool: 'source-map',
output: {
path: path.resolve(projectRoot, outputDir),
path: path.resolve(projectRoot, appConfig.outDir),
filename: '[name].[chunkhash].bundle.js',
sourceMapFilename: '[name].[chunkhash].bundle.map',
chunkFilename: '[id].[chunkhash].chunk.js'
@ -37,7 +35,7 @@ export const getWebpackProdConfigPartial = function(projectRoot: string, sourceD
tslint: {
emitErrors: true,
failOnHint: true,
resourcePath: path.resolve(projectRoot, `./${sourceDir}`)
resourcePath: path.resolve(projectRoot, appConfig.root)
},
htmlLoader: {
minimize: true,

View File

@ -3,16 +3,19 @@
const path = require('path');
const webpack = require('webpack');
const getWebpackTestConfig = function(projectRoot, sourceDir) {
const getWebpackTestConfig = function(projectRoot, appConfig) {
const appRoot = path.resolve(projectRoot, appConfig.root);
return {
devtool: 'inline-source-map',
context: path.resolve(__dirname, './'),
resolve: {
extensions: ['', '.ts', '.js'],
root: path.resolve(projectRoot, `./${sourceDir}`)
root: appRoot
},
entry: {
test: path.resolve(projectRoot, `./${sourceDir}/test.ts`)
test: path.resolve(appRoot, appConfig.test)
},
output: {
path: './dist.test',
@ -43,7 +46,7 @@ const getWebpackTestConfig = function(projectRoot, sourceDir) {
{
loader: 'awesome-typescript-loader',
query: {
tsconfig: path.resolve(projectRoot, `./${sourceDir}/tsconfig.json`),
tsconfig: path.resolve(appRoot, appConfig.tsconfig),
module: 'commonjs',
target: 'es5',
useForkChecker: true
@ -61,7 +64,7 @@ const getWebpackTestConfig = function(projectRoot, sourceDir) {
{ test: /\.less$/, loaders: ['raw-loader', 'postcss-loader', 'less-loader'] },
{ test: /\.scss$|\.sass$/, loaders: ['raw-loader', 'postcss-loader', 'sass-loader'] },
{ test: /\.(jpg|png)$/, loader: 'url-loader?limit=128000' },
{ test: /\.html$/, loader: 'raw-loader', exclude: [path.resolve(projectRoot, `./${sourceDir}/index.html`)] }
{ test: /\.html$/, loader: 'raw-loader', exclude: [path.resolve(appRoot, appConfig.index)] }
],
postLoaders: [
{
@ -83,7 +86,7 @@ const getWebpackTestConfig = function(projectRoot, sourceDir) {
tslint: {
emitErrors: false,
failOnHint: false,
resourcePath: `./${sourceDir}`
resourcePath: `./${appConfig.root}`
},
node: {
fs: 'empty',

View File

@ -2,7 +2,6 @@ import * as path from 'path';
import * as fs from 'fs';
import * as webpackMerge from 'webpack-merge';
import { CliConfig } from './config';
import { NgCliEnvironmentPlugin } from '../utilities/environment-plugin';
import {
getWebpackCommonConfig,
getWebpackDevConfigPartial,
@ -18,33 +17,26 @@ export class NgCliWebpackConfig {
private webpackDevConfigPartial: any;
private webpackProdConfigPartial: any;
private webpackBaseConfig: any;
private webpackMaterialConfig: any;
private webpackMaterialE2EConfig: any;
private webpackMobileConfigPartial: any;
private webpackMobileProdConfigPartial: any;
constructor(public ngCliProject: any, public target: string, public environment: string, outputDir: string) {
const sourceDir = CliConfig.fromProject().defaults.sourceDir;
constructor(public ngCliProject: any, public target: string, public environment: string, outputDir?: string) {
const appConfig = CliConfig.fromProject().apps[0];
const environmentPath = `./${sourceDir}/app/environments/environment.${environment}.ts`;
appConfig.outDir = outputDir || appConfig.outDir;
this.webpackBaseConfig = getWebpackCommonConfig(this.ngCliProject.root, sourceDir, outputDir);
this.webpackDevConfigPartial = getWebpackDevConfigPartial(this.ngCliProject.root, sourceDir, outputDir);
this.webpackProdConfigPartial = getWebpackProdConfigPartial(this.ngCliProject.root, sourceDir, outputDir);
this.webpackBaseConfig = getWebpackCommonConfig(this.ngCliProject.root, environment, appConfig);
this.webpackDevConfigPartial = getWebpackDevConfigPartial(this.ngCliProject.root, appConfig);
this.webpackProdConfigPartial = getWebpackProdConfigPartial(this.ngCliProject.root, appConfig);
if (CliConfig.fromProject().apps[0].mobile){
this.webpackMobileConfigPartial = getWebpackMobileConfigPartial(this.ngCliProject.root, sourceDir, outputDir);
this.webpackMobileProdConfigPartial = getWebpackMobileProdConfigPartial(this.ngCliProject.root, sourceDir);
this.webpackMobileConfigPartial = getWebpackMobileConfigPartial(this.ngCliProject.root, appConfig);
this.webpackMobileProdConfigPartial = getWebpackMobileProdConfigPartial(this.ngCliProject.root, appConfig);
this.webpackBaseConfig = webpackMerge(this.webpackBaseConfig, this.webpackMobileConfigPartial);
this.webpackProdConfigPartial = webpackMerge(this.webpackProdConfigPartial, this.webpackMobileProdConfigPartial);
}
this.generateConfig();
this.config.plugins.unshift(new NgCliEnvironmentPlugin({
path: path.resolve(this.ngCliProject.root, `./${sourceDir}/app/environments/`),
src: 'environment.ts',
dest: `environment.${this.environment}.ts`
}));
}
generateConfig(): void {

View File

@ -17,7 +17,7 @@ module.exports = Task.extend({
let lastHash = null;
let webpackCompiler: any;
var config: NgCliWebpackConfig = new NgCliWebpackConfig(this.project, commandOptions.target, commandOptions.environment, commandOptions.outputPath).config;
var config: NgCliWebpackConfig = new NgCliWebpackConfig(this.project, commandOptions.target, commandOptions.environment).config;
// This allows for live reload of page when changes are made to repo.
// https://webpack.github.io/docs/webpack-dev-server.html#inline-mode
@ -41,7 +41,7 @@ module.exports = Task.extend({
}
const webpackDevServerConfiguration: IWebpackDevServerConfigurationOptions = {
contentBase: config.output.path,
contentBase: path.resolve(this.project.root, `./${CliConfig.fromProject().apps[0].root}`),
historyApiFallback: true,
stats: webpackDevServerOutputOptions,
inline: true,

View File

@ -4,7 +4,7 @@ var fs = require('fs');
module.exports = function dynamicPathParser(project, entityName) {
var projectRoot = project.root;
var sourceDir = project.ngConfig.defaults.sourceDir;
var sourceDir = project.ngConfig.apps[0].root;
var appRoot = path.join(sourceDir, 'app');
var cwd = process.env.PWD;

View File

@ -1,60 +0,0 @@
import * as fs from 'fs';
import * as path from 'path';
interface WebpackPlugin {
apply(compiler: any): void;
}
interface EnvOptions {
path: string;
src: string;
dest: string;
}
export class NgCliEnvironmentPlugin implements WebpackPlugin {
config: EnvOptions;
constructor(public config: EnvOptions) {}
isEnvFile(file: string): boolean {
return file === path.resolve(this.config.path, this.config.src);
}
replaceFile(file: string): any {
return path.resolve(this.config.path, this.config.dest);
}
updateResult(result: any): any {
['request', 'userRequest', 'resource']
.filter((key) => { return result[key]; })
.forEach((key) => {
result[key] = this.replaceFile(result[key]);
});
return result;
}
apply(compiler: any): void {
compiler.plugin('normal-module-factory', (normalModuleFactory: any) => {
normalModuleFactory.plugin('after-resolve', (result, callback) => {
var _resource = result['resource'];
if (!this.isEnvFile(_resource)) {
return callback(null, result);
}
var envFile = this.replaceFile(_resource);
fs.stat(envFile, (err, stats) => {
if (err || !stats.isFile()) {
const destPath = path.resolve(this.config.path, this.config.dest);
const errorText = (!err && stats.isFile()) ? 'is not a file.' : 'does not exist.';
throw new Error(`${destPath} ${errorText}`);
}
// mutate result
var newResult = this.updateResult(result);
return callback(null, newResult);
});
});
});
}
}

View File

@ -22,9 +22,62 @@
"items": {
"type": "object",
"properties": {
"main": "string",
"tsconfig": "string",
"mobile": "boolean"
"root": {
"type": "string"
},
"outDir": {
"type": "string"
},
"assets": {
"type": "string"
},
"index": {
"type": "string"
},
"main": {
"type": "string"
},
"test": {
"type": "string"
},
"tsconfig": {
"type": "string"
},
"prefix": {
"type": "string"
},
"mobile": {
"type": "boolean"
},
"additionalEntries": {
"description": "Additional files to be included in the build.",
"type": "array",
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"input": {
"type": "string"
},
"output": {
"type": "string"
}
},
"additionalProperties": false
}
]
},
"additionalProperties": false
},
"environments": {
"description": "Name and corresponding file for environment config.",
"type": "object",
"additionalProperties": true
}
},
"additionalProperties": false
},
@ -81,12 +134,6 @@
"defaults": {
"type": "object",
"properties": {
"prefix": {
"type": "string"
},
"sourceDir": {
"type": "string"
},
"styleExt": {
"type": "string"
},

View File

@ -87,7 +87,6 @@
"stylus": "^0.54.5",
"stylus-loader": "^2.1.0",
"symlink-or-copy": "^1.0.3",
"ts-helpers": "^1.1.1",
"ts-loader": "^0.8.2",
"tslint": "^3.11.0",
"tslint-loader": "^2.1.4",

View File

@ -5,10 +5,11 @@ const init = (config) => {
// load Angular CLI config
if (!config.angularCliConfig) throw new Error('Missing \'angularCliConfig\' entry in Karma config');
const angularCliConfig = require(path.join(config.basePath, config.angularCliConfig))
const angularCliConfig = require(path.join(config.basePath, config.angularCliConfig));
const appConfig = angularCliConfig.apps[0];
// add webpack config
config.webpack = getWebpackTestConfig(config.basePath, angularCliConfig.defaults.sourceDir);
config.webpack = getWebpackTestConfig(config.basePath, appConfig);
config.webpackMiddleware = {
noInfo: true, // Hide webpack output because its noisy.
stats: { // Also prevent chunk and module display output, cleaner look. Only emit errors.

View File

@ -11,14 +11,14 @@ describe('dynamic path parser', () => {
var project;
var entityName = 'temp-name';
var rootName = path.parse(process.cwd()).root + 'project';
var sourceDir = 'src';
var root = 'src';
beforeEach(() => {
project = {
root: rootName,
ngConfig: {
defaults: {
sourceDir: sourceDir
}
apps: [{
root: root
}]
}
};
var mockFolder = {};

View File

@ -109,7 +109,7 @@ describe('Basic end-to-end Workflow', function () {
var mainBundlePath = path.join(process.cwd(), 'dist', 'main.bundle.js');
var mainBundleContent = fs.readFileSync(mainBundlePath, { encoding: 'utf8' });
expect(mainBundleContent).to.include('production: true');
expect(mainBundleContent.includes('production: true')).to.be.equal(true);
});
it('Build fails on invalid build target', function (done) {
@ -310,11 +310,11 @@ describe('Basic end-to-end Workflow', function () {
expect(existsSync(lcovReport)).to.be.equal(true);
});
it('moves all files that live inside `public` into `dist`', function () {
it('moves all files that live inside `assets` into `dist`', function () {
this.timeout(420000);
const tmpFile = path.join(process.cwd(), 'public', 'test.abc');
const tmpFileLocation = path.join(process.cwd(), 'dist', 'test.abc');
const tmpFile = path.join(process.cwd(), 'src', 'assets', 'test.abc');
const tmpFileLocation = path.join(process.cwd(), 'dist', 'assets', 'test.abc');
fs.writeFileSync(tmpFile, 'hello world');
sh.exec(`${ngBin} build`);
@ -486,6 +486,40 @@ describe('Basic end-to-end Workflow', function () {
expect(indexHtml).to.include('main.bundle.js');
});
it('styles.css is added to main bundle', function() {
this.timeout(420000);
let stylesPath = path.join(process.cwd(), 'src', 'styles.css');
let testStyle = 'body { background-color: blue; }';
fs.writeFileSync(stylesPath, testStyle, 'utf8');
sh.exec(`${ngBin} build`);
var mainBundlePath = path.join(process.cwd(), 'dist', 'main.bundle.js');
var mainBundleContent = fs.readFileSync(mainBundlePath, { encoding: 'utf8' });
expect(mainBundleContent.includes(testStyle)).to.be.equal(true);
});
it('styles.css supports css imports', function() {
this.timeout(420000);
let importedStylePath = path.join(process.cwd(), 'src', 'imported-styles.css');
let testStyle = 'body { background-color: blue; }';
fs.writeFileSync(importedStylePath, testStyle, 'utf8');
let stylesPath = path.join(process.cwd(), 'src', 'style.css');
let importStyle = '@import \'./imported-style.css\';';
fs.writeFileSync(stylesPath, importStyle, 'utf8');
sh.exec(`${ngBin} build`);
var mainBundlePath = path.join(process.cwd(), 'dist', 'main.bundle.js');
var mainBundleContent = fs.readFileSync(mainBundlePath, { encoding: 'utf8' });
expect(mainBundleContent.includes(testStyle)).to.be.equal(true);
});
it('Serve and run e2e tests on dev environment', function () {
this.timeout(240000);