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

feat(@angular/cli): add an eject command #4680

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ matrix:
- node_js: "6"
os: linux
env: NODE_SCRIPT="tests/run_e2e.js --glob=tests/build/**"
- node_js: "6"
os: linux
env: NODE_SCRIPT="tests/run_e2e.js --eject --glob=tests/build/**"
- node_js: "6"
os: linux
env: NODE_SCRIPT="tests/run_e2e.js --ignore=**/tests/build/**"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
"@types/express": "^4.0.32",
"@types/fs-extra": "0.0.37",
"@types/glob": "^5.0.29",
"@types/jasmine": "^2.2.32",
"@types/jasmine": "~2.2.0",
"@types/lodash": "4.14.50",
"@types/mock-fs": "^3.6.30",
"@types/node": "^6.0.36",
Expand Down
1 change: 1 addition & 0 deletions packages/@angular/cli/addon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = {
return {
'build': require('../commands/build').default,
'serve': require('../commands/serve').default,
'eject': require('../commands/eject').default,
'new': require('../commands/new').default,
'generate': require('../commands/generate').default,
'destroy': require('../commands/destroy').default,
Expand Down
37 changes: 37 additions & 0 deletions packages/@angular/cli/commands/eject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { BuildOptions } from '../models/build-options';
import { Version } from '../upgrade/version';
import {baseBuildCommandOptions} from './build';

const Command = require('../ember-cli/lib/models/command');

// defaults for BuildOptions
export const baseEjectCommandOptions: any = [
Copy link
Contributor

Choose a reason for hiding this comment

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

These should be referenced from baseBuildCommandOptions in commands/build.ts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

...baseBuildCommandOptions,
{ name: 'force', 'type': Boolean }
];

export interface EjectTaskOptions extends BuildOptions {
force?: boolean;
}


const EjectCommand = Command.extend({
name: 'eject',
description: 'Ejects your app and output the proper webpack configuration and scripts.',

availableOptions: baseEjectCommandOptions,

run: function (commandOptions: EjectTaskOptions) {
const project = this.project;
const EjectTask = require('../tasks/eject').default;
const ejectTask = new EjectTask({
cliProject: project,
ui: this.ui,
});

return ejectTask.run(commandOptions);
}
});


export default EjectCommand;
25 changes: 19 additions & 6 deletions packages/@angular/cli/commands/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const Command = require('../ember-cli/lib/models/command');
import * as path from 'path';
import * as child_process from 'child_process';
import * as chalk from 'chalk';
import { CliConfig } from '../models/config';


const VersionCommand = Command.extend({
name: 'version',
Expand Down Expand Up @@ -40,6 +42,13 @@ const VersionCommand = Command.extend({

ngCliVersion = `local (v${pkg.version}, branch: ${gitBranch})`;
}
const config = CliConfig.fromProject();
if (config && config.config.project.version !== pkg.version) {
ngCliVersion += ` [${config.config.project.version}]`;
}
if (config && config.config.project.ejected) {
ngCliVersion += ' (e)';
}

if (projPkg) {
roots.forEach(root => {
Expand Down Expand Up @@ -76,12 +85,16 @@ const VersionCommand = Command.extend({
},

getVersion: function(moduleName: string): string {
const modulePkg = require(path.resolve(
this.project.root,
'node_modules',
moduleName,
'package.json'));
return modulePkg.version;
try {
const modulePkg = require(path.resolve(
this.project.root,
'node_modules',
moduleName,
'package.json'));
return modulePkg.version;
} catch (e) {
return 'error';
}
},

printVersion: function (module: string, version: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export interface BaseHrefWebpackPluginOptions {
}

export class BaseHrefWebpackPlugin {
constructor(private options: BaseHrefWebpackPluginOptions) { }
constructor(public readonly options: BaseHrefWebpackPluginOptions) { }

apply(compiler: any): void {
// Ignore if baseHref is not passed
Expand Down
5 changes: 5 additions & 0 deletions packages/@angular/cli/lib/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
},
"name": {
"type": "string"
},
"ejected": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a description

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Done.

"description": "Whether or not this project was ejected.",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
Expand Down
2 changes: 1 addition & 1 deletion packages/@angular/cli/models/webpack-configs/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { WebpackConfigOptions } from '../webpack-config';
const autoprefixer = require('autoprefixer');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');


/**
* Enumerate loaders and their dependencies from this file to let the dependency validator
Expand Down
15 changes: 11 additions & 4 deletions packages/@angular/cli/models/webpack-configs/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '../../plugins/suppress-entry-chunks-webpack-plugin';
import { extraEntryParser, getOutputHashFormat } from './utils';
import { WebpackConfigOptions } from '../webpack-config';
import { pluginArgs } from '../../tasks/eject';

const cssnano = require('cssnano');
const autoprefixer = require('autoprefixer');
Expand Down Expand Up @@ -104,17 +105,23 @@ export function getStylesConfig(wco: WebpackConfigOptions) {

// load global css as css files
if (globalStylePaths.length > 0) {
rules.push(...baseRules.map(({test, loaders}) => ({
include: globalStylePaths, test, loaders: ExtractTextPlugin.extract({
rules.push(...baseRules.map(({test, loaders}) => {
const extractTextPlugin = {
use: [
...commonLoaders,
...loaders
],
fallback: 'style-loader',
// publicPath needed as a workaround https://github.com/angular/angular-cli/issues/4035
publicPath: ''
})
})));
};
const ret: any = {
include: globalStylePaths, test, loaders: ExtractTextPlugin.extract(extractTextPlugin)
};
// Save the original options as arguments for eject.
ret[pluginArgs] = extractTextPlugin;
return ret;
}));
}

// supress empty .js files in css only entry points
Expand Down
14 changes: 9 additions & 5 deletions packages/@angular/cli/models/webpack-configs/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function _createAotPlugin(wco: WebpackConfigOptions, options: any) {
const { appConfig, projectRoot, buildOptions } = wco;

// Read the environment, and set it in the compiler host.
let hostOverrideFileSystem: any = {};
let hostReplacementPaths: any = {};
// process environment file replacement
if (appConfig.environments) {
if (!appConfig.environmentSource) {
Expand Down Expand Up @@ -58,9 +58,10 @@ function _createAotPlugin(wco: WebpackConfigOptions, options: any) {
const appRoot = path.resolve(projectRoot, appConfig.root);
const sourcePath = appConfig.environmentSource;
const envFile = appConfig.environments[buildOptions.environment];
const environmentContent = fs.readFileSync(path.join(appRoot, envFile)).toString();

hostOverrideFileSystem = { [path.join(appRoot, sourcePath)]: environmentContent };
hostReplacementPaths = {
[path.join(appRoot, sourcePath)]: path.join(appRoot, envFile)
};
}

return new AotPlugin(Object.assign({}, {
Expand All @@ -69,15 +70,18 @@ function _createAotPlugin(wco: WebpackConfigOptions, options: any) {
i18nFile: buildOptions.i18nFile,
i18nFormat: buildOptions.i18nFormat,
locale: buildOptions.locale,
hostOverrideFileSystem
hostReplacementPaths
}, options));
}


export const getNonAotConfig = function(wco: WebpackConfigOptions) {
const { projectRoot, appConfig } = wco;
let exclude = [ '**/*.spec.ts' ];
if (appConfig.test) { exclude.push(path.join(projectRoot, appConfig.root, appConfig.test)); };
if (appConfig.test) {
exclude.push(path.join(projectRoot, appConfig.root, appConfig.test));
}

return {
module: {
rules: [
Expand Down
10 changes: 10 additions & 0 deletions packages/@angular/cli/plugins/webpack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Exports the webpack plugins we use internally.

module.exports = {
BaseHrefWebpackPlugin:
require('../lib/base-href-webpack/base-href-webpack-plugin').BaseHrefWebpackPlugin,
GlobCopyWebpackPlugin: require('../plugins/glob-copy-webpack-plugin').GlobCopyWebpackPlugin,
SuppressExtractedTextChunksWebpackPlugin:
require('../plugins/suppress-entry-chunks-webpack-plugin')
.SuppressExtractedTextChunksWebpackPlugin
};
8 changes: 6 additions & 2 deletions packages/@angular/cli/tasks/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ export default Task.extend({
run: function (runTaskOptions: BuildTaskOptions) {

const project = this.cliProject;
const config = CliConfig.fromProject().config;

const outputPath = runTaskOptions.outputPath || CliConfig.fromProject().config.apps[0].outDir;
const outputPath = runTaskOptions.outputPath || config.apps[0].outDir;
if (project.root === outputPath) {
throw new SilentError ('Output path MUST not be project root directory!');
throw new SilentError('Output path MUST not be project root directory!');
}
if (config.project && config.project.ejected) {
throw new SilentError('An ejected project cannot use the build command anymore.');
}
rimraf.sync(path.resolve(project.root, outputPath));

Expand Down
8 changes: 8 additions & 0 deletions packages/@angular/cli/tasks/e2e.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import * as url from 'url';

import { E2eTaskOptions } from '../commands/e2e';
import { CliConfig } from '../models/config';
import { requireProjectModule } from '../utilities/require-project-module';

const Task = require('../ember-cli/lib/models/task');
const SilentError = require('silent-error');


export const E2eTask = Task.extend({
run: function (e2eTaskOptions: E2eTaskOptions) {
const projectConfig = CliConfig.fromProject().config;
const projectRoot = this.project.root;
const protractorLauncher = requireProjectModule(projectRoot, 'protractor/built/launcher');

if (projectConfig.project && projectConfig.project.ejected) {
throw new SilentError('An ejected project cannot use the build command anymore.');
}

return new Promise(function () {
let promise = Promise.resolve();
let additionalProtractorConfig: any = {
Expand Down