Skip to content

Commit 0e83b8f

Browse files
filipesilvaTheLarkInn
authored andcommitted
feat(build): add mobile app build (#2)
1 parent d52fb7f commit 0e83b8f

File tree

12 files changed

+151
-47
lines changed

12 files changed

+151
-47
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,44 @@
1+
import 'angular2-universal-polyfills';
12
import { provide } from '@angular/core';
23
import { APP_BASE_HREF } from '@angular/common';
34
import { APP_SHELL_BUILD_PROVIDERS } from '@angular/app-shell';
4-
import { AppComponent } from './app/';
5-
import {
6-
REQUEST_URL,
7-
ORIGIN_URL
5+
import {
6+
REQUEST_URL,
7+
ORIGIN_URL,
8+
Bootloader,
9+
BootloaderConfig,
10+
AppConfig
811
} from 'angular2-universal';
12+
import { AppComponent } from './app/';
913

10-
export const options = {
11-
directives: [
12-
// The component that will become the main App Shell
13-
AppComponent
14-
],
14+
const bootloaderConfig: BootloaderConfig = {
1515
platformProviders: [
1616
APP_SHELL_BUILD_PROVIDERS,
1717
provide(ORIGIN_URL, {
18-
useValue: ''
19-
})
18+
useValue: 'http://localhost:4200' // full urls are needed for node xhr
19+
}),
20+
provide(APP_BASE_HREF, { useValue: '/' }),
21+
],
22+
async: true,
23+
preboot: false
24+
}
25+
26+
const appConfig: AppConfig = {
27+
directives: [
28+
// The component that will become the main App Shell
29+
AppComponent
2030
],
2131
providers: [
2232
// What URL should Angular be treating the app as if navigating
23-
provide(APP_BASE_HREF, {useValue: '/'}),
24-
provide(REQUEST_URL, {useValue: '/'})
25-
],
26-
async: false,
27-
preboot: false
28-
};
33+
provide(REQUEST_URL, { useValue: '/' })
34+
]
35+
}
36+
37+
export function getBootloader() : Bootloader {
38+
return new Bootloader(bootloaderConfig);
39+
}
2940

41+
export function serialize(bootloader: Bootloader, template: string) : string {
42+
appConfig.template = template;
43+
return bootloader.serializeApplication(appConfig);
44+
}

addon/ng2/blueprints/mobile/files/__path__/system-import.js

-2
This file was deleted.

addon/ng2/blueprints/ng2/files/__path__/index.html

+12-23
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,21 @@
1010
<meta name="apple-mobile-web-app-capable" content="yes">
1111
<meta name="theme-color" content="#000000">
1212
<link rel="manifest" href="/manifest.webapp">
13-
{{#each mobile.icons}}
14-
<link rel="{{rel}}" {{#if sizes}}sizes="{{sizes}}" {{/if}}href="{{href}}">
15-
{{/each}}
16-
{{#if environment.production}}
17-
<script type="text/javascript">
18-
if ('serviceWorker' in navigator) {
19-
navigator.serviceWorker.register('/worker.js').catch(function(err) {
20-
console.log('Error installing service worker: ', err);
21-
});
22-
}
23-
</script>
24-
{{/if}}
13+
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
14+
<link rel="apple-touch-icon" sizes="57x57" href="/icons/apple-touch-icon-57x57.png">
15+
<link rel="apple-touch-icon" sizes="60x60" href="/icons/apple-touch-icon-60x60.png">
16+
<link rel="apple-touch-icon" sizes="72x72" href="/icons/apple-touch-icon-72x72.png">
17+
<link rel="apple-touch-icon" sizes="76x76" href="/icons/apple-touch-icon-76x76.png">
18+
<link rel="apple-touch-icon" sizes="114x114" href="/icons/apple-touch-icon-114x114.png">
19+
<link rel="apple-touch-icon" sizes="120x120" href="/icons/apple-touch-icon-120x120.png">
20+
<link rel="apple-touch-icon" sizes="144x144" href="/icons/apple-touch-icon-144x144.png">
21+
<link rel="apple-touch-icon" sizes="152x152" href="/icons/apple-touch-icon-152x152.png">
22+
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon-180x180.png">
23+
<link rel="apple-touch-startup-image" href="/icons/apple-touch-icon-180x180.png">
2524
<% } %>
25+
2626
</head>
2727
<body>
2828
<<%= prefix %>-root>Loading...</<%= prefix %>-root>
29-
30-
<% if (isMobile) { %>
31-
{{#if environment.production}}
32-
<script src="/app-concat.js" async></script>
33-
{{else}}
34-
35-
{{/if}}
36-
<% } else { %>
37-
38-
39-
<% } %>
4029
</body>
4130
</html>

addon/ng2/blueprints/ng2/files/__path__/typings.d.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@
44
// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html
55

66
/// <reference path="<%= refToTypings %>/typings/browser.d.ts" />
7-
<% if(!isMobile) { %>declare var module: { id: string };<% } %>
7+
<% if(!isMobile) { %>
8+
declare var module: { id: string };
89
declare var require: any;
10+
<% } %>
11+

addon/ng2/blueprints/ng2/files/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@
3131
"@angular/platform-server": "2.0.0-rc.3",
3232
"@angular/service-worker": "0.2.0",
3333
"@angular/app-shell": "0.0.0",
34-
"angular2-universal":"0.101.5",
34+
"angular2-universal":"0.104.4",
3535
"angular2-universal-polyfills": "0.4.1",
36-
"preboot": "^2.0.10",<% } %>
36+
"preboot": "2.1.2",
37+
"parse5": "1.5.1",<% } %>
3738
"angular-cli": "^<%= version %>",
3839
"codelyzer": "0.0.20",
3940
"ember-cli-inject-live-reload": "1.4.0",

addon/ng2/blueprints/ng2/files/typings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
"selenium-webdriver": "registry:dt/selenium-webdriver#2.44.0+20160317120654"
66
},
77
"ambientDependencies": {
8-
<% if (isMobile) {%>"node": "registry:dt/node#4.0.0+20160509154515" <% } %>
8+
<% if (isMobile) {%>"node": "registry:dt/node#6.0.0+20160621231320" <% } %>
99
}
1010
}

addon/ng2/models/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './webpack-build-common';
22
export * from './webpack-build-test';
33
export * from './webpack-build-production';
44
export * from './webpack-build-development';
5+
export * from './webpack-build-mobile';
56
export * from './webpack-build-utils';
67
export {getWebpackMaterialConfig, getWebpackMaterialE2EConfig} from './webpack-build-material2.ts';
78

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as webpack from 'webpack';
2+
import * as path from 'path';
3+
import * as SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin';
4+
import * as OfflinePlugin from 'offline-plugin';
5+
import { PrerenderWebpackPlugin } from '../utilities/prerender-webpack-plugin.ts'
6+
7+
export const getWebpackMobileConfigPartial = function (projectRoot: string) {
8+
return {
9+
plugins: [
10+
new PrerenderWebpackPlugin({
11+
templatePath: 'index.html',
12+
configPath: path.resolve(projectRoot, './src/main-app-shell.ts'),
13+
appPath: path.resolve(projectRoot, './src')
14+
})
15+
]
16+
}
17+
};
18+
19+
export const getWebpackMobileProdConfigPartial = function (projectRoot: string) {
20+
return {
21+
plugins: [
22+
new OfflinePlugin(),
23+
new SingleEntryPlugin(__dirname, path.join(__dirname, '../utilities/sw-install.js'), 'sw-install'),
24+
]
25+
}
26+
};

addon/ng2/models/webpack-config.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { CliConfig } from './config';
12
import {
23
getWebpackCommonConfig,
34
getWebpackDevConfigPartial,
45
getWebpackProdConfigPartial,
56
getWebpackMaterialConfig,
6-
getWebpackMaterialE2EConfig
7+
getWebpackMaterialE2EConfig,
8+
getWebpackMobileConfigPartial,
9+
getWebpackMobileProdConfigPartial
710
} from './';
811

912
const webpackMerge = require('webpack-merge');
@@ -18,13 +21,23 @@ export class NgCliWebpackConfig {
1821
private webpackBaseConfig: any;
1922
private webpackMaterialConfig: any;
2023
private webpackMaterialE2EConfig: any;
24+
private webpackMobileConfigPartial: any;
25+
private webpackMobileProdConfigPartial: any;
2126

2227
constructor(public ngCliProject: any, public environment: string) {
2328
this.webpackBaseConfig = getWebpackCommonConfig(this.ngCliProject.root);
2429
this.webpackMaterialConfig = getWebpackMaterialConfig(this.ngCliProject.root);
2530
this.webpackMaterialE2EConfig = getWebpackMaterialE2EConfig(this.ngCliProject.root);
2631
this.webpackDevConfigPartial = getWebpackDevConfigPartial(this.ngCliProject.root);
2732
this.webpackProdConfigPartial = getWebpackProdConfigPartial(this.ngCliProject.root);
33+
this.webpackMobileConfigPartial = getWebpackMobileConfigPartial(this.ngCliProject.root);
34+
this.webpackMobileProdConfigPartial = getWebpackMobileProdConfigPartial(this.ngCliProject.root);
35+
36+
if (CliConfig.fromProject().apps[0].mobile){
37+
this.webpackDevConfigPartial = webpackMerge(this.webpackDevConfigPartial, this.webpackMobileConfigPartial);
38+
this.webpackProdConfigPartial = webpackMerge(this.webpackProdConfigPartial, this.webpackMobileProdConfigPartial);
39+
}
40+
2841
this.generateConfig();
2942
}
3043

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// replace with the real thing when PR is merged
2+
// https://github.com/angular/universal/pull/464
3+
4+
interface IWebpackPrerender {
5+
templatePath: string;
6+
configPath: string;
7+
appPath: string;
8+
}
9+
10+
export class PrerenderWebpackPlugin {
11+
12+
private bootloader: any;
13+
private cachedTemplate: string
14+
15+
constructor(private options: IWebpackPrerender) {
16+
// maintain your platform instance
17+
this.bootloader = require(this.options.configPath).getBootloader();
18+
}
19+
20+
apply(compiler) {
21+
compiler.plugin('emit', (compilation, callback) => {
22+
if (compilation.assets.hasOwnProperty(this.options.templatePath)) {
23+
// we need to cache the template file to be able to re-serialize it
24+
// even when it is not being emitted
25+
this.cachedTemplate = compilation.assets[this.options.templatePath].source();
26+
}
27+
28+
if (this.cachedTemplate) {
29+
this.decacheAppFiles();
30+
require(this.options.configPath).serialize(this.bootloader, this.cachedTemplate)
31+
.then((html) => {
32+
compilation.assets[this.options.templatePath] = {
33+
source: () => html,
34+
size: () => html.length
35+
};
36+
callback();
37+
});
38+
} else {
39+
callback();
40+
}
41+
});
42+
}
43+
44+
decacheAppFiles() {
45+
// delete all app files from cache, but keep libs
46+
// this is needed so that the config file can reimport up to date
47+
// versions of the app files
48+
delete require.cache[this.options.configPath];
49+
Object.keys(require.cache)
50+
.filter(key => key.startsWith(this.options.appPath))
51+
.forEach(function (key) {
52+
// console.log('===', key);
53+
delete require.cache[key];
54+
});
55+
}
56+
}

addon/ng2/utilities/sw-install.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require('offline-plugin/runtime').install();

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"less-loader": "^2.2.3",
7171
"lodash": "^4.11.1",
7272
"node-sass": "^3.7.0",
73+
"offline-plugin": "^3.4.1",
7374
"opn": "4.0.1",
7475
"parse5": "^2.1.5",
7576
"phantomjs-polyfill": "0.0.2",

0 commit comments

Comments
 (0)