Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The generated project has dependencies that require **Node 4.x.x and NPM 3.x.x**
* [Generating a Route](#generating-a-route)
* [Creating a Build](#creating-a-build)
* [Build Targets and Environment Files](#build-targets-and-environment-files)
* [Base tag handling in index.html](#base-tag-handling-in-indexhtml)
* [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)
Expand Down Expand Up @@ -152,6 +153,16 @@ You can also add your own env files other than `dev` and `prod` by doing the fol
- 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.

### Base tag handling in index.html

When building you can modify base tag (`<base href="/">`) in your index.html with `--base-href your-url` option.

```bash
# Sets base tag href to /myUrl/ in your index.html
ng build --base-href /myUrl/
ng build --bh /myUrl/
```

### Bundling

All builds make use of bundling, and using the `--prod` flag in `ng build --prod`
Expand Down
6 changes: 4 additions & 2 deletions addon/ng2/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import * as Command from 'ember-cli/lib/models/command';
import * as WebpackBuild from '../tasks/build-webpack';
import * as WebpackBuildWatch from '../tasks/build-webpack-watch';

interface BuildOptions {
export interface BuildOptions {
target?: string;
environment?: string;
outputPath?: string;
watch?: boolean;
watcher?: string;
supressSizes: boolean;
baseHref?: string;
}

module.exports = Command.extend({
Expand All @@ -27,7 +28,8 @@ module.exports = Command.extend({
{ name: 'output-path', type: 'Path', default: 'dist/', aliases: ['o'] },
{ name: 'watch', type: Boolean, default: false, aliases: ['w'] },
{ name: 'watcher', type: String },
{ name: 'suppress-sizes', type: Boolean, default: false }
{ name: 'suppress-sizes', type: Boolean, default: false },
{ name: 'base-href', type: String, default: null, aliases: ['bh'] },
],

run: function (commandOptions: BuildOptions) {
Expand Down
46 changes: 32 additions & 14 deletions addon/ng2/commands/github-pages-deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ import * as CreateGithubRepo from '../tasks/create-github-repo';
import { CliConfig } from '../models/config';
import { oneLine } from 'common-tags';

const fsReadFile = Promise.denodeify(fs.readFile);
const fsWriteFile = Promise.denodeify(fs.writeFile);
const fsReadDir = Promise.denodeify(fs.readdir);
const fsCopy = Promise.denodeify(fse.copy);

interface GithubPagesDeployOptions {
message?: string;
target?: string;
environment?: string;
userPage?: boolean;
skipBuild?: boolean;
ghToken?: string;
ghUsername?: string;
baseHref?: string;
}

module.exports = Command.extend({
name: 'github-pages:deploy',
aliases: ['gh-pages:deploy'],
Expand Down Expand Up @@ -61,9 +70,14 @@ module.exports = Command.extend({
type: String,
default: '',
description: 'Github username'
}, {
name: 'base-href',
type: String,
default: null,
aliases: ['bh']
}],

run: function(options, rawArgs) {
run: function(options: GithubPagesDeployOptions, rawArgs) {
const ui = this.ui;
const root = this.project.root;
const execOptions = {
Expand Down Expand Up @@ -99,10 +113,19 @@ module.exports = Command.extend({
outputPath: outDir
});

/**
* BaseHref tag setting logic:
* First, use --base-href flag value if provided.
* Else if --user-page is true, then keep baseHref default as declared in index.html.
* Otherwise auto-replace with `/${projectName}/`.
*/
const baseHref = options.baseHref || (options.userPage ? null : `/${projectName}/`);

const buildOptions = {
target: options.target,
environment: options.environment,
outputPath: outDir
outputPath: outDir,
baseHref: baseHref,
};

const createGithubRepoTask = new CreateGithubRepo({
Expand All @@ -123,7 +146,7 @@ module.exports = Command.extend({
.then(createGitHubRepoIfNeeded)
.then(checkoutGhPages)
.then(copyFiles)
.then(updateBaseHref)
.then(createNotFoundPage)
.then(addAndCommit)
.then(returnStartingBranch)
.then(pushToGitRepo)
Expand Down Expand Up @@ -191,15 +214,10 @@ module.exports = Command.extend({
})));
}

function updateBaseHref() {
if (options.userPage) { return Promise.resolve(); }
let indexHtml = path.join(root, 'index.html');
return fsReadFile(indexHtml, 'utf8')
.then((data) => data.replace(/<base href="\/">/g, `<base href="/${projectName}/">`))
.then((data) => {
fsWriteFile(indexHtml, data, 'utf8');
fsWriteFile(path.join(root, '404.html'), data, 'utf8');
});
function createNotFoundPage() {
const indexHtml = path.join(root, 'index.html');
const notFoundPage = path.join(root, '404.html');
return fsCopy(indexHtml, notFoundPage);
}

function addAndCommit() {
Expand Down
11 changes: 10 additions & 1 deletion addon/ng2/models/webpack-build-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ import * as webpack from 'webpack';
import * as atl from 'awesome-typescript-loader';

import { findLazyModules } from './find-lazy-modules';
import { BaseHrefWebpackPlugin } from '../utilities/base-href-webpack-plugin';

export function getWebpackCommonConfig(projectRoot: string, environment: string, appConfig: any) {
export function getWebpackCommonConfig(
projectRoot: string,
environment: string,
appConfig: any,
baseHref: string
) {

const appRoot = path.resolve(projectRoot, appConfig.root);
const appMain = path.resolve(appRoot, appConfig.main);
Expand Down Expand Up @@ -118,6 +124,9 @@ export function getWebpackCommonConfig(projectRoot: string, environment: string,
template: path.resolve(appRoot, appConfig.index),
chunksSortMode: 'dependency'
}),
new BaseHrefWebpackPlugin({
baseHref: baseHref
}),
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.
Expand Down
10 changes: 8 additions & 2 deletions addon/ng2/models/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ export class NgCliWebpackConfig {
public ngCliProject: any,
public target: string,
public environment: string,
outputDir?: string
outputDir?: string,
baseHref?: string
) {
const config: CliConfig = CliConfig.fromProject();
const appConfig = config.config.apps[0];

appConfig.outDir = outputDir || appConfig.outDir;

this.baseConfig = getWebpackCommonConfig(this.ngCliProject.root, environment, appConfig);
this.baseConfig = getWebpackCommonConfig(
this.ngCliProject.root,
environment,
appConfig,
baseHref
);
this.devConfigPartial = getWebpackDevConfigPartial(this.ngCliProject.root, appConfig);
this.prodConfigPartial = getWebpackProdConfigPartial(this.ngCliProject.root, appConfig);

Expand Down
7 changes: 4 additions & 3 deletions addon/ng2/tasks/build-webpack-watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import * as webpack from 'webpack';
import * as ProgressPlugin from 'webpack/lib/ProgressPlugin';
import { NgCliWebpackConfig } from '../models/webpack-config';
import { webpackOutputOptions } from '../models/';
import { ServeTaskOptions } from '../commands/serve';
import { BuildOptions } from '../commands/build';

let lastHash: any = null;

module.exports = Task.extend({
run: function(runTaskOptions: ServeTaskOptions) {
run: function(runTaskOptions: BuildOptions) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Strange, that nobody has noticed yet that build-webpack and build-webpack-watch tasks uses the options interface from serve command. 😕

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like one of those things that slipped :/


const project = this.cliProject;

Expand All @@ -20,7 +20,8 @@ module.exports = Task.extend({
project,
runTaskOptions.target,
runTaskOptions.environment,
runTaskOptions.outputPath
runTaskOptions.outputPath,
runTaskOptions.baseHref
).config;
const webpackCompiler = webpack(config);

Expand Down
7 changes: 4 additions & 3 deletions addon/ng2/tasks/build-webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as rimraf from 'rimraf';
import * as path from 'path';
import * as Task from 'ember-cli/lib/models/task';
import * as webpack from 'webpack';
import { ServeTaskOptions } from '../commands/serve';
import { BuildOptions } from '../commands/build';
import { NgCliWebpackConfig } from '../models/webpack-config';
import { webpackOutputOptions } from '../models/';

Expand All @@ -11,7 +11,7 @@ let lastHash: any = null;

module.exports = Task.extend({
// Options: String outputPath
run: function(runTaskOptions: ServeTaskOptions) {
run: function (runTaskOptions: BuildOptions) {

const project = this.cliProject;

Expand All @@ -20,7 +20,8 @@ module.exports = Task.extend({
project,
runTaskOptions.target,
runTaskOptions.environment,
runTaskOptions.outputPath
runTaskOptions.outputPath,
runTaskOptions.baseHref
).config;

const webpackCompiler = webpack(config);
Expand Down
39 changes: 39 additions & 0 deletions addon/ng2/utilities/base-href-webpack-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
interface BaseHrefWebpackPluginOptions {
baseHref: string;
}

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

apply(compiler): void {
// Ignore if baseHref is not passed
if (!this.options.baseHref) {
return;
}

compiler.plugin('compilation', (compilation) => {
compilation.plugin(
'html-webpack-plugin-before-html-processing',
(htmlPluginData, callback) => {
// Check if base tag already exists
const baseTagRegex = /<base.*?>/i;
const baseTagMatches = htmlPluginData.html.match(baseTagRegex);
if (!baseTagMatches) {
// Insert it in top of the head if not exist
htmlPluginData.html = htmlPluginData.html.replace(
/<head>/i, '$&' + `<base href="${this.options.baseHref}">`
);
} else {
// Replace only href attribute if exists
const modifiedBaseTag = baseTagMatches[0].replace(
/href="\S+"/i, `href="${this.options.baseHref}"`
);
htmlPluginData.html = htmlPluginData.html.replace(baseTagRegex, modifiedBaseTag);
}

callback(null, htmlPluginData);
}
);
});
}
}
50 changes: 50 additions & 0 deletions tests/acceptance/base-href-webpack-plugin.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*eslint-disable no-console */
'use strict';

var expect = require('chai').expect;
var BaseHrefWebpackPlugin = require('../../addon/ng2/utilities/base-href-webpack-plugin').BaseHrefWebpackPlugin;

function mockCompiler(indexHtml, callback) {
return {
plugin: function (event, compilerCallback) {
var compilation = {
plugin: function (hook, compilationCallback) {
var htmlPluginData = {
html: indexHtml
};
compilationCallback(htmlPluginData, callback);
}
};
compilerCallback(compilation);
}
};
}

describe('base href webpack plugin', function () {
it('should do nothing when baseHref is null', function () {
var plugin = new BaseHrefWebpackPlugin({ baseHref: null });

var compiler = mockCompiler('<body><head></head></body>', function (x, htmlPluginData) {
expect(htmlPluginData.html).to.equal('<body><head></head></body>');
});
plugin.apply(compiler);
});

it('should insert base tag when not exist', function () {
var plugin = new BaseHrefWebpackPlugin({ baseHref: '/' });

var compiler = mockCompiler('<body><head></head></body>', function (x, htmlPluginData) {
expect(htmlPluginData.html).to.equal('<body><head><base href="/"></head></body>');
});
plugin.apply(compiler);
});

it('should replace href attribute when base tag already exists', function () {
var plugin = new BaseHrefWebpackPlugin({ baseHref: '/myUrl/' });

var compiler = mockCompiler('<body><head><base href="/" target="_blank"></head></body>', function (x, htmlPluginData) {
expect(htmlPluginData.html).to.equal('<body><head><base href="/myUrl/" target="_blank"></head></body>');
});
plugin.apply(compiler);
});
});
Loading