@@ -19,8 +19,7 @@ const CLOUDINARY_ASSET_DIRECTORIES = [
19
19
*/
20
20
21
21
module . exports = {
22
-
23
- async onBuild ( { netlifyConfig, constants, inputs } ) {
22
+ async onPreBuild ( { netlifyConfig, constants, inputs } ) {
24
23
const host = process . env . DEPLOY_PRIME_URL || process . env . NETLIFY_HOST ;
25
24
26
25
if ( ! host ) {
@@ -37,7 +36,16 @@ module.exports = {
37
36
folder = process . env . SITE_NAME
38
37
} = inputs ;
39
38
39
+ // If we're using the fetch API, we don't need to worry about uploading any
40
+ // of the media as itw ill all be publicly accessible, so we can skip this step
41
+
42
+ if ( deliveryType === 'fetch' ) {
43
+ console . log ( 'Skipping: Delivery type set to fetch.' )
44
+ return ;
45
+ }
46
+
40
47
const cloudName = process . env . CLOUDINARY_CLOUD_NAME || inputs . cloudName ;
48
+
41
49
const apiKey = process . env . CLOUDINARY_API_KEY ;
42
50
const apiSecret = process . env . CLOUDINARY_API_SECRET ;
43
51
@@ -51,40 +59,126 @@ module.exports = {
51
59
apiSecret
52
60
} ) ;
53
61
54
- await Promise . all ( CLOUDINARY_ASSET_DIRECTORIES . map ( async ( { name : mediaName , inputKey, path : defaultPath } ) => {
55
- const mediaPath = inputs [ inputKey ] || defaultPath ;
56
- const cldAssetPath = `/${ path . join ( PUBLIC_ASSET_PATH , mediaPath ) } ` ;
57
- const cldAssetUrl = `${ host } /${ cldAssetPath } ` ;
62
+ const imagesDirectory = glob . sync ( `${ PUBLISH_DIR } /images/**/*` ) ;
63
+ const imagesFiles = imagesDirectory . filter ( file => ! ! path . extname ( file ) ) ;
58
64
59
- const assetRedirectUrl = await getCloudinaryUrl ( {
60
- deliveryType : 'fetch' ,
61
- folder,
62
- path : `${ cldAssetUrl } /:splat` ,
63
- uploadPreset
64
- } ) ;
65
+ const images = await Promise . all ( imagesFiles . map ( async image => {
66
+ const publishPath = image . replace ( PUBLISH_DIR , '' ) ;
67
+ const publishUrl = `${ host } ${ publishPath } ` ;
68
+ const cldAssetPath = `/${ path . join ( PUBLIC_ASSET_PATH , publishPath ) } ` ;
69
+ const cldAssetUrl = `${ host } ${ cldAssetPath } ` ;
65
70
66
- netlifyConfig . redirects . unshift ( {
67
- from : `${ cldAssetPath } *` ,
68
- to : `${ mediaPath } /:splat` ,
69
- status : 200 ,
70
- force : true
71
+ const cloudinary = await getCloudinaryUrl ( {
72
+ deliveryType,
73
+ folder,
74
+ path : publishPath ,
75
+ localDir : PUBLISH_DIR ,
76
+ uploadPreset,
77
+ remoteHost : host ,
71
78
} ) ;
72
79
73
- netlifyConfig . redirects . unshift ( {
74
- from : `${ mediaPath } /*` ,
75
- to : assetRedirectUrl ,
76
- status : 302 ,
77
- force : true
78
- } ) ;
80
+ return {
81
+ publishPath,
82
+ publishUrl,
83
+ ...cloudinary
84
+ }
79
85
} ) ) ;
86
+
87
+ netlifyConfig . build . environment . CLOUDINARY_ASSETS = {
88
+ images
89
+ }
90
+ } ,
91
+
92
+ async onBuild ( { netlifyConfig, constants, inputs } ) {
93
+ const host = process . env . DEPLOY_PRIME_URL || process . env . NETLIFY_HOST ;
94
+
95
+ if ( ! host ) {
96
+ console . warn ( 'Cannot determine Netlify host, not proceeding with on-page image replacement.' ) ;
97
+ console . log ( 'Note: The Netlify CLI does not currently support the ability to determine the host locally, try deploying on Netlify.' ) ;
98
+ return ;
99
+ }
100
+
101
+ const { PUBLISH_DIR } = constants ;
102
+
103
+ const {
104
+ deliveryType,
105
+ uploadPreset,
106
+ folder = process . env . SITE_NAME
107
+ } = inputs ;
108
+
109
+ const cloudName = process . env . CLOUDINARY_CLOUD_NAME || inputs . cloudName ;
110
+ const apiKey = process . env . CLOUDINARY_API_KEY ;
111
+ const apiSecret = process . env . CLOUDINARY_API_SECRET ;
112
+
113
+ if ( ! cloudName ) {
114
+ throw new Error ( 'A Cloudinary Cloud Name is required. Please set cloudName input or use the environment variable CLOUDINARY_CLOUD_NAME' ) ;
115
+ }
116
+
117
+ configureCloudinary ( {
118
+ cloudName,
119
+ apiKey,
120
+ apiSecret
121
+ } ) ;
122
+
123
+ // If the delivery type is set to upload, we need to be able to map individual assets based on their public ID,
124
+ // which would require a dynamic middle solution, but that adds more hops than we want, so add a new redirect
125
+ // for each asset uploaded
126
+
127
+ if ( deliveryType === 'upload' ) {
128
+ await Promise . all ( Object . keys ( netlifyConfig . build . environment . CLOUDINARY_ASSETS ) . flatMap ( mediaType => {
129
+ return netlifyConfig . build . environment . CLOUDINARY_ASSETS [ mediaType ] . map ( async asset => {
130
+ const { publishPath, cloudinaryUrl } = asset ;
131
+
132
+ netlifyConfig . redirects . unshift ( {
133
+ from : `${ publishPath } *` ,
134
+ to : cloudinaryUrl ,
135
+ status : 302 ,
136
+ force : true
137
+ } ) ;
138
+ } )
139
+ } ) ) ;
140
+ }
141
+
142
+ // If the delivery type is fetch, we're able to use the public URL and pass it right along "as is", so
143
+ // we can create generic redirects. The tricky thing is to avoid a redirect loop, we modify the
144
+ // path, so that we can safely allow Cloudinary to fetch the media remotely
145
+
146
+ if ( deliveryType === 'fetch' ) {
147
+ await Promise . all ( CLOUDINARY_ASSET_DIRECTORIES . map ( async ( { name : mediaName , inputKey, path : defaultPath } ) => {
148
+ const mediaPath = inputs [ inputKey ] || defaultPath ;
149
+ const cldAssetPath = `/${ path . join ( PUBLIC_ASSET_PATH , mediaPath ) } ` ;
150
+ const cldAssetUrl = `${ host } /${ cldAssetPath } ` ;
151
+
152
+ const { cloudinaryUrl : assetRedirectUrl } = await getCloudinaryUrl ( {
153
+ deliveryType : 'fetch' ,
154
+ folder,
155
+ path : `${ cldAssetUrl } /:splat` ,
156
+ uploadPreset
157
+ } ) ;
158
+
159
+ netlifyConfig . redirects . unshift ( {
160
+ from : `${ cldAssetPath } /*` ,
161
+ to : `${ mediaPath } /:splat` ,
162
+ status : 200 ,
163
+ force : true
164
+ } ) ;
165
+
166
+ netlifyConfig . redirects . unshift ( {
167
+ from : `${ mediaPath } /*` ,
168
+ to : assetRedirectUrl ,
169
+ status : 302 ,
170
+ force : true
171
+ } ) ;
172
+ } ) ) ;
173
+ }
174
+
80
175
} ,
81
176
82
177
// Post build looks through all of the output HTML and rewrites any src attributes to use a cloudinary URL
83
178
// This only solves on-page references until any JS refreshes the DOM
84
179
85
- async onPostBuild ( { constants, inputs } ) {
86
-
87
- const host = process . env . DEPLOY_PRIME_URL ;
180
+ async onPostBuild ( { netlifyConfig, constants, inputs } ) {
181
+ const host = process . env . DEPLOY_PRIME_URL || process . env . NETLIFY_HOST ;
88
182
89
183
if ( ! host ) {
90
184
console . warn ( 'Cannot determine Netlify host, not proceeding with on-page image replacement.' ) ;
@@ -121,6 +215,7 @@ module.exports = {
121
215
const sourceHtml = await fs . readFile ( page , 'utf-8' ) ;
122
216
123
217
const { html, errors } = await updateHtmlImagesToCloudinary ( sourceHtml , {
218
+ assets : netlifyConfig . build . environment . CLOUDINARY_ASSETS ,
124
219
deliveryType,
125
220
uploadPreset,
126
221
folder,
0 commit comments