Skip to content

Commit 26f5d98

Browse files
committed
feat: implement --base-href argument
Implement --base-href argument for build and serve commands Closes angular#1064
1 parent 67e70a0 commit 26f5d98

9 files changed

+72
-15
lines changed

addon/ng2/commands/build.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface BuildOptions {
99
watch?: boolean;
1010
watcher?: string;
1111
supressSizes: boolean;
12+
baseHref?: string;
1213
}
1314

1415
module.exports = Command.extend({
@@ -22,7 +23,8 @@ module.exports = Command.extend({
2223
{ name: 'output-path', type: 'Path', default: 'dist/', aliases: ['o'] },
2324
{ name: 'watch', type: Boolean, default: false, aliases: ['w'] },
2425
{ name: 'watcher', type: String },
25-
{ name: 'suppress-sizes', type: Boolean, default: false }
26+
{ name: 'suppress-sizes', type: Boolean, default: false },
27+
{ name: 'base-href', type: String, default: null },
2628
],
2729

2830
run: function (commandOptions: BuildOptions) {
@@ -32,7 +34,7 @@ module.exports = Command.extend({
3234
}
3335
if (commandOptions.target === 'production') {
3436
commandOptions.environment = 'prod';
35-
}
37+
}
3638
}
3739

3840
var project = this.project;
@@ -43,14 +45,16 @@ module.exports = Command.extend({
4345
ui: ui,
4446
outputPath: commandOptions.outputPath,
4547
target: commandOptions.target,
46-
environment: commandOptions.environment
48+
environment: commandOptions.environment,
49+
baseHref: commandOptions.baseHref
4750
}) :
4851
new WebpackBuild({
4952
cliProject: project,
5053
ui: ui,
5154
outputPath: commandOptions.outputPath,
5255
target: commandOptions.target,
5356
environment: commandOptions.environment,
57+
baseHref: commandOptions.baseHref
5458
});
5559

5660
return buildTask.run(commandOptions);

addon/ng2/commands/serve.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface ServeTaskOptions {
2828
ssl?: boolean;
2929
sslKey?: string;
3030
sslCert?: string;
31+
baseHref?: string;
3132
}
3233

3334
module.exports = Command.extend({
@@ -51,7 +52,8 @@ module.exports = Command.extend({
5152
{ name: 'output-path', type: 'Path', default: 'dist/', aliases: ['op', 'out'] },
5253
{ name: 'ssl', type: Boolean, default: false },
5354
{ name: 'ssl-key', type: String, default: 'ssl/server.key' },
54-
{ name: 'ssl-cert', type: String, default: 'ssl/server.crt' }
55+
{ name: 'ssl-cert', type: String, default: 'ssl/server.crt' },
56+
{ name: 'base-href', type: String, default: null },
5557
],
5658

5759
run: function(commandOptions: ServeTaskOptions) {
@@ -85,6 +87,7 @@ module.exports = Command.extend({
8587
ui: this.ui,
8688
analytics: this.analytics,
8789
project: this.project,
90+
baseHref: commandOptions.baseHref
8891
});
8992

9093
return serve.run(commandOptions);

addon/ng2/models/webpack-build-common.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import * as HtmlWebpackPlugin from 'html-webpack-plugin';
44
import * as webpack from 'webpack';
55
import { ForkCheckerPlugin } from 'awesome-typescript-loader';
66
import { CliConfig } from './config';
7+
import { BaseHrefWebpackPlugin } from '../utilities/base-href-webpack-plugin';
78

8-
export function getWebpackCommonConfig(projectRoot: string, sourceDir: string) {
9+
export function getWebpackCommonConfig(projectRoot: string, sourceDir: string, baseHref: string) {
910
return {
1011
devtool: 'inline-source-map',
1112
resolve: {
@@ -64,6 +65,9 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string) {
6465
template: path.resolve(projectRoot, `./${sourceDir}/index.html`),
6566
chunksSortMode: 'dependency'
6667
}),
68+
new BaseHrefWebpackPlugin({
69+
baseHref: baseHref
70+
}),
6771
new webpack.optimize.CommonsChunkPlugin({
6872
name: ['polyfills']
6973
}),

addon/ng2/models/webpack-config.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ export class NgCliWebpackConfig {
2323
private webpackMobileConfigPartial: any;
2424
private webpackMobileProdConfigPartial: any;
2525

26-
constructor(public ngCliProject: any, public target: string, public environment: string) {
26+
constructor(public ngCliProject: any, public target: string, public environment: string, public baseHref: string) {
2727
const sourceDir = CliConfig.fromProject().defaults.sourceDir;
2828

2929
const environmentPath = `./${sourceDir}/app/environments/environment.${environment}.ts`;
3030

31-
this.webpackBaseConfig = getWebpackCommonConfig(this.ngCliProject.root, sourceDir);
31+
this.webpackBaseConfig = getWebpackCommonConfig(this.ngCliProject.root, sourceDir, baseHref);
3232
this.webpackDevConfigPartial = getWebpackDevConfigPartial(this.ngCliProject.root, sourceDir);
3333
this.webpackProdConfigPartial = getWebpackProdConfigPartial(this.ngCliProject.root, sourceDir);
3434

addon/ng2/tasks/build-webpack-watch.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = Task.extend({
1616

1717
rimraf.sync(path.resolve(project.root, runTaskOptions.outputPath));
1818

19-
const config = new NgCliWebpackConfig(project, runTaskOptions.target, runTaskOptions.environment).config;
19+
const config = new NgCliWebpackConfig(project, runTaskOptions.target, runTaskOptions.environment, runTaskOptions.baseHref).config;
2020
const webpackCompiler = webpack(config);
2121

2222
webpackCompiler.apply(new ProgressPlugin({

addon/ng2/tasks/build-webpack.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ let lastHash: any = null;
1111

1212
module.exports = Task.extend({
1313
// Options: String outputPath
14-
run: function(runTaskOptions: ServeTaskOptions) {
14+
run: function (runTaskOptions: ServeTaskOptions) {
1515

1616
var project = this.cliProject;
1717

1818
rimraf.sync(path.resolve(project.root, runTaskOptions.outputPath));
19-
var config = new NgCliWebpackConfig(project, runTaskOptions.target, runTaskOptions.environment).config;
19+
var config = new NgCliWebpackConfig(project, runTaskOptions.target, runTaskOptions.environment, runTaskOptions.baseHref).config;
2020
const webpackCompiler = webpack(config);
2121

2222
const ProgressPlugin = require('webpack/lib/ProgressPlugin');

addon/ng2/tasks/serve-webpack.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module.exports = Task.extend({
1515
let lastHash = null;
1616
let webpackCompiler: any;
1717

18-
var config: NgCliWebpackConfig = new NgCliWebpackConfig(this.project, commandOptions.target, commandOptions.environment).config;
18+
var config: NgCliWebpackConfig = new NgCliWebpackConfig(this.project, commandOptions.target, commandOptions.environment, commandOptions.baseHref).config;
1919
// This allows for live reload of page when changes are made to repo.
2020
// https://webpack.github.io/docs/webpack-dev-server.html#inline-mode
2121
config.entry.main.unshift(`webpack-dev-server/client?http://${commandOptions.host}:${commandOptions.port}/`);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
interface BaseHrefWebpackPluginOptions {
2+
baseHref: string;
3+
}
4+
5+
export class BaseHrefWebpackPlugin {
6+
constructor(private options: BaseHrefWebpackPluginOptions) { }
7+
8+
apply(compiler): void {
9+
// Ignore if baseHref is not passed
10+
if (!this.options.baseHref) {
11+
return;
12+
}
13+
14+
compiler.plugin('compilation', (compilation) => {
15+
compilation.plugin('html-webpack-plugin-before-html-processing', (htmlPluginData, callback) => {
16+
// Check if base tag already exists
17+
const baseTagRegex = /<base.*?>/i;
18+
const baseTagMatches = htmlPluginData.html.match(baseTagRegex);
19+
if (!baseTagMatches) {
20+
// Insert it in top of the head if not exist
21+
htmlPluginData.html = htmlPluginData.html.replace(/<head>/i, '$&' + `<base href="${this.options.baseHref}">`);
22+
} else {
23+
// Replace only href attribute if exists
24+
const modifiedBaseTag = baseTagMatches[0].replace(/href="\S+"/i, `href="${this.options.baseHref}"`);
25+
htmlPluginData.html = htmlPluginData.html.replace(baseTagRegex, modifiedBaseTag);
26+
}
27+
28+
callback(null, htmlPluginData);
29+
});
30+
});
31+
}
32+
}

tests/e2e/e2e_workflow.spec.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,20 @@ describe('Basic end-to-end Workflow', function () {
125125
});
126126
});
127127

128+
it('Supports base tag modifications via `ng build --base-href`', function() {
129+
this.timeout(420000);
130+
131+
// Check base tag before building with --base-href tag
132+
const indexHtmlBefore = fs.readFileSync(path.join(process.cwd(), 'dist/index.html'), 'utf-8');
133+
expect(indexHtmlBefore).to.match(/<base href="\/"/);
134+
135+
sh.exec(`${ngBin} build --base-href /myUrl/`);
136+
137+
// Check for base tag after build
138+
const indexHtmlAfter = fs.readFileSync(path.join(process.cwd(), 'dist/index.html'), 'utf-8');
139+
expect(indexHtmlAfter).to.match(/<base href="\/myUrl\/"/);
140+
});
141+
128142
it('Can run `ng build` in created project', function () {
129143
this.timeout(420000);
130144

@@ -338,8 +352,8 @@ describe('Basic end-to-end Workflow', function () {
338352
let lessFile = path.join(componentPath, lessFilename);
339353
let lessExample = '.outer {\n .inner { background: #fff; }\n }';
340354
let componentContents = fs.readFileSync(componentFile, 'utf8');
341-
342-
sh.mv(cssFile, lessFile);
355+
356+
sh.mv(cssFile, lessFile);
343357
fs.writeFileSync(lessFile, lessExample, 'utf8');
344358
fs.writeFileSync(componentFile, componentContents.replace(new RegExp(cssFilename, 'g'), lessFilename), 'utf8');
345359

@@ -365,8 +379,8 @@ describe('Basic end-to-end Workflow', function () {
365379
let stylusFile = path.join(componentPath, stylusFilename);
366380
let stylusExample = '.outer {\n .inner { background: #fff; }\n }';
367381
let componentContents = fs.readFileSync(componentFile, 'utf8');
368-
369-
sh.mv(cssFile, stylusFile);
382+
383+
sh.mv(cssFile, stylusFile);
370384
fs.writeFileSync(stylusFile, stylusExample, 'utf8');
371385
fs.writeFileSync(componentFile, componentContents.replace(new RegExp(cssFilename, 'g'), stylusFilename), 'utf8');
372386

0 commit comments

Comments
 (0)