mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-15 18:13:38 +08:00
feat(build): update angular-cli.json (#1633)
This commit is contained in:
parent
3b226be22f
commit
3dcd49bc62
25
README.md
25
README.md
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -1,3 +1,2 @@
|
||||
export * from './environments/environment';
|
||||
export * from './app.component';
|
||||
export * from './app.module';
|
||||
|
@ -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();
|
||||
|
@ -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';
|
||||
|
@ -0,0 +1 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
@ -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';
|
||||
|
@ -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": "+"
|
||||
|
@ -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);
|
||||
@ -26,11 +27,16 @@ module.exports = Command.extend({
|
||||
type: String,
|
||||
default: 'new gh-pages version',
|
||||
description: 'The commit message to include with the build, must be wrapped in quotes.'
|
||||
}, {
|
||||
}, {
|
||||
name: 'target',
|
||||
type: String,
|
||||
default: 'production',
|
||||
aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }]
|
||||
}, {
|
||||
name: 'environment',
|
||||
type: String,
|
||||
default: 'production',
|
||||
description: 'The Angular environment to create a build for'
|
||||
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))
|
||||
})));
|
||||
}
|
||||
|
||||
|
@ -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' }
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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')
|
||||
entry: {
|
||||
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',
|
||||
|
@ -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',
|
||||
|
@ -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')
|
||||
|
@ -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,
|
||||
|
@ -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',
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -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"
|
||||
},
|
||||
@ -101,4 +148,4 @@
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
@ -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",
|
||||
|
@ -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.
|
||||
|
@ -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 = {};
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user