@@ -2,29 +2,42 @@ const path = require('path');
22const _ = require ( 'lodash' ) ;
33const yaml = require ( 'js-yaml' ) ;
44const fs = require ( 'fs' ) ;
5+ const Mustache = require ( 'mustache' ) ;
56
67class ServerlessAWSFunctionURLCustomDomainPlugin {
78 constructor ( serverless , options ) {
89 this . serverless = serverless ;
910 this . options = options ;
1011
1112 this . hooks = {
12- 'before:package:createDeploymentArtifacts ' : this . createDeploymentArtifacts . bind ( this ) ,
13+ 'before:package:finalize ' : this . createDeploymentArtifacts . bind ( this ) ,
1314 'aws:info:displayStackOutputs' : this . printSummary . bind ( this ) ,
1415 } ;
1516 }
1617
1718 createDeploymentArtifacts ( ) {
1819 const baseResources = this . serverless . service . provider . compiledCloudFormationTemplate ;
1920
20- const filename = path . resolve ( __dirname , 'resources.yml' ) ;
21- const content = fs . readFileSync ( filename , 'utf-8' ) ;
22- const resources = yaml . load ( content , {
23- filename,
24- } ) ;
21+ var functionURLResourceName = null ;
22+ for ( var key in baseResources . Resources ) {
23+ if ( baseResources . Resources [ key ] [ 'Type' ] === "AWS::Lambda::Url" ) {
24+ functionURLResourceName = key
25+ }
26+ }
27+
28+ if ( functionURLResourceName === null ) {
29+ this . serverless . cli . consoleLog ( "no function url defined" ) ;
30+ return baseResources ;
31+ }
32+
33+ const config = this . serverless . service . custom . urlDomain ;
34+ config [ 'lambdaFunctionUrl' ] = functionURLResourceName
35+
36+ const resources = this . prepareResources ( config ) ;
2537
26- this . prepareResources ( resources ) ;
2738 const combinedResouces = _ . merge ( baseResources , resources ) ;
39+ console . log ( JSON . stringify ( combinedResouces ) ) ;
40+
2841 return combinedResouces ;
2942 }
3043
@@ -37,7 +50,7 @@ class ServerlessAWSFunctionURLCustomDomainPlugin {
3750 }
3851
3952 const { outputs } = awsInfo . gatheredData ;
40- const apiDistributionDomain = _ . find ( outputs , ( output ) => output . OutputKey === 'ApiCloudFrontDistributionDomain ' ) ;
53+ const apiDistributionDomain = _ . find ( outputs , ( output ) => output . OutputKey === 'CloudFrontDistributionDomain ' ) ;
4154
4255 if ( ! apiDistributionDomain || ! apiDistributionDomain . OutputValue ) {
4356 return ;
@@ -46,39 +59,66 @@ class ServerlessAWSFunctionURLCustomDomainPlugin {
4659 const cnameDomain = this . getConfig ( 'apiDomain' , '-' ) ;
4760
4861 this . serverless . cli . consoleLog ( 'CloudFront domain name' ) ;
49- this . serverless . cli . consoleLog ( ` ${ apiDistributionDomain . OutputValue } (CNAME: ${ cnameDomain } )` ) ;
62+ this . serverless . cli . consoleLog ( `${ apiDistributionDomain . OutputValue } (CNAME: ${ cnameDomain } )` ) ;
5063 }
5164
52- prepareResources ( resources ) {
53- const distributionConfig = resources . Resources . ApiCloudFrontDistribution . Properties . DistributionConfig ;
54- const apiRecordsConfig = resources . Resources . ApiRecordSetGroup . Properties ;
55- this . prepareDomain ( distributionConfig , apiRecordsConfig ) ;
56- this . prepareAcmCertificateArn ( distributionConfig ) ;
57- this . prepareHostedZoneName ( apiRecordsConfig ) ;
58- }
59-
60- prepareHostedZoneName ( apiRecordsConfig ) {
61- const name = this . getConfig ( 'hostedZoneName' , null ) ;
65+ prepareResources ( config ) {
6266
63- apiRecordsConfig . HostedZoneName = name ;
67+ const route53 = this . getConfig ( 'route53' , true ) ;
68+ var resources = this . getCloudfrontResources ( config ) ;
69+ if ( route53 ) {
70+ resources = _ . merge ( resources , this . getRoute53Resources ( config ) ) ;
71+ }
72+ return resources
6473 }
6574
66- prepareAcmCertificateArn ( distributionConfig ) {
67- const arn = this . getConfig ( 'certificateArn' , null ) ;
68- distributionConfig . ViewerCertificate . AcmCertificateArn = arn ;
75+ getCloudfrontResources ( config ) {
76+ const filename = path . resolve ( __dirname , 'resources.yml' ) ;
77+ const content = fs . readFileSync ( filename , 'utf-8' ) ;
78+ const resources = yaml . load ( content , {
79+ filename,
80+ } ) ;
81+ var output = Mustache . render ( JSON . stringify ( resources ) , config ) ;
82+ output = JSON . parse ( output )
83+ output [ 'Resources' ] [ 'CloudFrontDistribution' ] [ 'Properties' ] [ 'DistributionConfig' ] [ 'Aliases' ] = config [ 'domains' ]
84+ return output ;
6985 }
7086
71- prepareDomain ( distributionConfig , apiRecordsConfig ) {
72- const domain = this . getConfig ( 'apiDomain' , null ) ;
73-
74- if ( domain !== null ) {
75- const domains = Array . isArray ( domain ) ? domain : [ domain ] ;
76- distributionConfig . Aliases = domains ;
77- apiRecordsConfig . RecordSets [ 0 ] . Name = domains [ 0 ] ;
78- distributionConfig . Comment = `Api distribution for ${ domains [ 0 ] } ` ;
79- } else {
80- delete distributionConfig . Aliases ;
87+ getRoute53Resources ( config ) {
88+ const domains = this . getConfig ( 'domains' , null ) ;
89+ const hostedZoneName = this . getConfig ( 'hostedZoneName' , null ) ;
90+
91+ const template = JSON . stringify ( {
92+ "Type" : "AWS::Route53::RecordSetGroup" ,
93+ "DeletionPolicy" : "Delete" ,
94+ "DependsOn" : [
95+ "CloudFrontDistribution"
96+ ] ,
97+ "Properties" : {
98+ "HostedZoneName" : hostedZoneName ,
99+ "RecordSets" : [
100+ {
101+ "Name" : "{{{ domain }}}" ,
102+ "Type" : "A" ,
103+ "AliasTarget" : {
104+ "HostedZoneId" : "Z2FDTNDATAQYW2" ,
105+ "DNSName" : {
106+ "Fn::GetAtt" : [
107+ "CloudFrontDistribution" ,
108+ "DomainName"
109+ ]
110+ }
111+ }
112+ }
113+ ]
114+ }
115+ } )
116+ var resources = { }
117+ for ( var idx in domains ) {
118+ var output = Mustache . render ( template , { 'domain' : domains [ idx ] } ) ;
119+ resources [ `Route53Record${ idx } ` ] = JSON . parse ( output ) ;
81120 }
121+ return { 'Resources' : resources }
82122 }
83123
84124 getConfig ( field , defaultValue ) {
0 commit comments