-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat(schematics): ng deploy schematic #2046
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
Changes from 16 commits
1445f28
1d5dcd2
125cc13
b36f972
524be38
2dd5362
5c23777
fdde4d7
72da1b1
a72c3f7
fc6f869
5c962cc
c547b4e
c940a82
b666254
4292cdd
3a1b108
4adc1f6
c709f04
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Deploy your application on Firebase Hosting | ||
|
||
In this guide, we'll look at how to use `@angular/fire` to automatically deploy an Angular application to Firebase hosting by using the Angular CLI. | ||
|
||
## Step 1: add `@angular/fire` to your project | ||
|
||
First, you need to add the `@angular/fire` package to your project. In your Angular CLI project run: | ||
|
||
```shell | ||
ng add @angular/fire | ||
``` | ||
|
||
*Note that the command above assumes you have global Angular CLI installed. To install Angular CLI globally run `npm i -g @angular/cli`.* | ||
|
||
The command above will trigger the `@angular/fire` `ng-add` schematics. Once they install `@angular/fire`. If you are not authenticated, the schematics will open a browser which will guide you through the authentication flow. Once you authenticate, you'll see a prompt to select a Firebase hosting project. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I ran ng-add, the "choose a project" prompt wasn't in alphabetical order. The Firebase CLI returns them in alphabetical, so that was unexpected for me. Probably not a huge deal since most people don't have tons of projects, but worth fixing if it isn't a ton of work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For convenience, we provide fuzzy search. Maybe alphabetical order will be an additional simplification. We can add this. |
||
|
||
The schematics will do the following: | ||
|
||
- Add `@angular/fire` to your list of dependencies | ||
- Create `firebase.json`, `.firebaserc` files in the root of your workspace. You can use them to configure your firebase hosting deployment. Find more about them [here](https://firebase.google.com/docs/hosting/full-config) | ||
- Update your workspace file (`angular.json`) by inserting the `deploy` builder | ||
|
||
In the end, your `angular.json` project will look like below: | ||
|
||
```json | ||
{ | ||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", | ||
"version": 1, | ||
"newProjectRoot": "projects", | ||
"projects": { | ||
"sample-app": { | ||
// ... | ||
"deploy": { | ||
"builder": "@angular/fire:deploy", | ||
"options": {} | ||
} | ||
} | ||
} | ||
// ... | ||
}, | ||
"defaultProject": "sample-app" | ||
} | ||
``` | ||
|
||
If you want to add deployment capabilities to a different project in your workspace, you can run: | ||
|
||
``` | ||
ng add @angular/fire --project=[PROJECT_NAME] | ||
``` | ||
|
||
## Step 2: deploying the project | ||
|
||
As the second step, to deploy your project run: | ||
|
||
``` | ||
ng run [PROJECT_NAME]:deploy | ||
jamesdaniels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
The command above will trigger: | ||
|
||
1. Production build of your application | ||
2. Deployment of the produced assets to the firebase hosting project you selected during `ng add` | ||
jhuleatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Step 3: customization | ||
|
||
To customize the deployment flow, you can use the configuration files you're already familiar with from `firebase-tools`. You can find more in the [firebase documentation](https://firebase.google.com/docs/hosting/full-config). |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"$schema": "@angular-devkit/architect/src/builders-schema.json", | ||
"builders": { | ||
"deploy": { | ||
"implementation": "./schematics/deploy/builder", | ||
"schema": "./schematics/deploy/schema.json", | ||
"description": "Deploy builder" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"$schema": "@angular-devkit/schematics/collection-schema.json", | ||
"schematics": { | ||
"ng-add": { | ||
"description": "Add firebase deploy schematic", | ||
"factory": "./schematics/index#ngDeploy" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { JsonObject, logging } from '@angular-devkit/core'; | ||
import { BuilderContext, BuilderRun, ScheduleOptions, Target, } from '@angular-devkit/architect/src/index2'; | ||
import { FirebaseTools, FirebaseDeployConfig } from 'schematics/interfaces'; | ||
import deploy from './actions'; | ||
|
||
|
||
let context: BuilderContext; | ||
let firebaseMock: FirebaseTools; | ||
|
||
const FIREBASE_PROJECT = 'ikachu-aa3ef'; | ||
const PROJECT = 'pirojok-project'; | ||
|
||
describe('Deploy Angular apps', () => { | ||
beforeEach(() => initMocks()); | ||
|
||
it('should check if the user is authenticated by invoking list', async () => { | ||
const spy = spyOn(firebaseMock, 'list'); | ||
const spyLogin = spyOn(firebaseMock, 'login'); | ||
await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); | ||
expect(spy).toHaveBeenCalled(); | ||
expect(spyLogin).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should invoke login if list rejects', async () => { | ||
firebaseMock.list = () => Promise.reject(); | ||
const spy = spyOn(firebaseMock, 'list').and.callThrough(); | ||
const spyLogin = spyOn(firebaseMock, 'login'); | ||
await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); | ||
expect(spy).toHaveBeenCalled(); | ||
expect(spyLogin).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should invoke the builder', async () => { | ||
const spy = spyOn(context, 'scheduleTarget').and.callThrough(); | ||
await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); | ||
expect(spy).toHaveBeenCalled(); | ||
expect(spy).toHaveBeenCalledWith({ | ||
target: 'build', | ||
configuration: 'production', | ||
project: PROJECT | ||
}); | ||
}); | ||
|
||
it('should invoke firebase.deploy', async () => { | ||
const spy = spyOn(firebaseMock, 'deploy').and.callThrough(); | ||
await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); | ||
expect(spy).toHaveBeenCalled(); | ||
expect(spy).toHaveBeenCalledWith({ | ||
cwd: 'host', only: 'hosting:' + PROJECT | ||
}); | ||
}); | ||
|
||
describe('error handling', () => { | ||
it('throws if there is no firebase project', async () => { | ||
try { | ||
await deploy(firebaseMock, context, 'host') | ||
fail(); | ||
} catch (e) { | ||
expect(e.message).toMatch(/Cannot find firebase project/); | ||
} | ||
}); | ||
|
||
it('throws if there is no target project', async () => { | ||
context.target = undefined; | ||
try { | ||
await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT) | ||
fail(); | ||
} catch (e) { | ||
expect(e.message).toMatch(/Cannot execute the build target/); | ||
} | ||
}); | ||
}); | ||
}); | ||
|
||
const initMocks = () => { | ||
firebaseMock = { | ||
login: () => Promise.resolve(), | ||
list: () => Promise.resolve([]), | ||
deploy: (_: FirebaseDeployConfig) => Promise.resolve(), | ||
use: () => Promise.resolve() | ||
}; | ||
|
||
context = { | ||
target: { | ||
configuration: 'production', | ||
project: PROJECT, | ||
target: 'foo' | ||
}, | ||
builder: { | ||
builderName: 'mock', | ||
description: 'mock', | ||
optionSchema: false | ||
}, | ||
currentDirectory: 'cwd', | ||
id: 1, | ||
logger: new logging.NullLogger() as any, | ||
workspaceRoot: 'cwd', | ||
getTargetOptions: (_: Target) => Promise.resolve({}), | ||
reportProgress: (_: number, __?: number, ___?: string) => { | ||
}, | ||
reportStatus: (_: string) => {}, | ||
reportRunning: () => {}, | ||
scheduleBuilder: (_: string, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun), | ||
scheduleTarget: (_: Target, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun) | ||
}; | ||
}; |
Uh oh!
There was an error while loading. Please reload this page.