Skip to content

Commit d63b0cd

Browse files
villesauMikaAK
authored andcommitted
Implement upload ordering (#104)
* prioritize uploads * add readme * test priority order * fetch the object and use metadata to compare last-modified time * revert fetching logic back as it was not used after all
1 parent 8381696 commit d63b0cd

File tree

5 files changed

+105
-58
lines changed

5 files changed

+105
-58
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ var config = {
212212
- `cdnizerOptions`: options to pass to [cdnizer](https://www.npmjs.com/package/cdnizer)
213213
- `basePathTransform`: transform the base path to add a folder name. Can return a promise or a string
214214
- `progress`: Enable progress bar (defaults true)
215+
- `priority`: priority order to your files as regex array. The ones not matched by regex are uploaded first. This rule becomes useful when avoiding s3 eventual consistency issues
215216

216217
### Contributing
217218
All contributions are welcome. Please make a pull request and make sure things still pass after running `npm run test`

src/s3_plugin.js

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ module.exports = class S3Plugin {
4141
s3Options = {},
4242
cdnizerOptions = {},
4343
s3UploadOptions = {},
44-
cloudfrontInvalidateOptions = {}
44+
cloudfrontInvalidateOptions = {},
45+
priority
4546
} = options
4647

4748
this.uploadOptions = s3UploadOptions
@@ -59,6 +60,7 @@ module.exports = class S3Plugin {
5960
include,
6061
exclude,
6162
basePath,
63+
priority,
6264
htmlFiles: typeof htmlFiles === 'string' ? [htmlFiles] : htmlFiles,
6365
progress: _.isBoolean(progress) ? progress : true
6466
}
@@ -240,16 +242,46 @@ module.exports = class S3Plugin {
240242
})
241243
}
242244

245+
prioritizeFiles(files) {
246+
const remainingFiles = [...files]
247+
const prioritizedFiles = this.options.priority
248+
.map(reg => _.remove(remainingFiles, (file) => reg.test(file.name)))
249+
250+
251+
return [remainingFiles, ...prioritizedFiles]
252+
}
253+
254+
uploadPriorityChunk(priorityChunk) {
255+
const uploadFiles = priorityChunk.map(file => this.uploadFile(file.name, file.path))
256+
257+
258+
return Promise.all(uploadFiles.map(({promise}) => promise))
259+
}
260+
261+
uploadInPriorityOrder(files) {
262+
const priorityChunks = this.prioritizeFiles(files)
263+
const uploadFunctions = priorityChunks
264+
.map(priorityChunk =>
265+
() => this.uploadPriorityChunk(priorityChunk))
266+
267+
268+
return uploadFunctions.reduce((promise, uploadFn) => promise.then(uploadFn), Promise.resolve())
269+
}
270+
243271
uploadFiles(files = []) {
244272
return this.transformBasePath()
245273
.then(() => {
246-
var uploadFiles = files.map(file => this.uploadFile(file.name, file.path))
274+
if (this.options.priority) {
275+
return this.uploadInPriorityOrder(files)
276+
} else {
277+
const uploadFiles = files.map(file => this.uploadFile(file.name, file.path))
247278

248-
if (this.options.progress) {
249-
this.setupProgressBar(uploadFiles)
250-
}
279+
if (this.options.progress) {
280+
this.setupProgressBar(uploadFiles)
281+
}
251282

252-
return Promise.all(uploadFiles.map(({promise}) => promise))
283+
return Promise.all(uploadFiles.map(({promise}) => promise))
284+
}
253285
})
254286
}
255287

test/upload_test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,31 @@ describe('S3 Webpack Upload', function() {
8686
.then(() => testHelpers.fetch(`${testHelpers.S3_URL}${BASE_PATH}/${randomFile.fileName}`))
8787
.then(fileBody => assert.match(fileBody, testHelpers.S3_ERROR_REGEX, 'random file exists'))
8888
})
89+
90+
describe('with priority', function() {
91+
it('uploads build to s3 in priority order', function() {
92+
testHelpers.createOutputPath()
93+
const s3Config = {priority: [/css/]}
94+
const config = testHelpers.createWebpackConfig({s3Config})
95+
96+
return testHelpers.runWebpackConfig({config})
97+
.then(testForErrorsOrGetFileNames)
98+
.then((files) => {
99+
const isCss = file => file.endsWith('css')
100+
const isJs = file => file.endsWith('js')
101+
const cssFileName = files.find(isCss)
102+
const jsFilename = files.find(isJs)
103+
104+
return Promise.all([
105+
testHelpers.getS3Object(cssFileName),
106+
testHelpers.getS3Object(jsFilename)
107+
])
108+
})
109+
.then(([cssObject, jsObject]) => {
110+
assert.isTrue(cssObject.LastModified.getTime() >= jsObject.LastModified.getTime())
111+
})
112+
})
113+
})
89114
})
90115

91116
describe('basePathTransform', function() {

test/upload_test_helpers.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import https from 'https'
33
import path from 'path'
44
import webpack from 'webpack'
55
import fs from 'fs'
6+
import {S3} from 'aws-sdk'
67
import HtmlWebpackPlugin from 'html-webpack-plugin'
78
import s3Opts from './s3_options'
89
import S3WebpackPlugin from '../src/s3_plugin'
@@ -130,7 +131,7 @@ export default {
130131
},
131132
plugins: [
132133
new HtmlWebpackPlugin(),
133-
new ExtractTextPlugin('styles.css'),
134+
new ExtractTextPlugin('[name]-[hash].css'),
134135
generateS3Config(s3Config)
135136
],
136137
output: {
@@ -224,5 +225,23 @@ export default {
224225

225226
getCloudfrontInvalidateOptions() {
226227
return s3Opts.cloudfrontInvalidateOptions
228+
},
229+
230+
getS3Object(key) {
231+
const s3 = new S3({
232+
accessKeyId: s3Opts.AWS_ACCESS_KEY,
233+
secretAccessKey: s3Opts.AWS_SECRET_ACCESS_KEY
234+
})
235+
236+
237+
return new Promise((resolve, reject) => {
238+
s3.getObject({Bucket: s3Opts.AWS_BUCKET, Key: key}, function(err, data) {
239+
if (!err) {
240+
resolve(data)
241+
} else {
242+
reject(err)
243+
}
244+
})
245+
})
227246
}
228247
}

yarn.lock

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,9 @@ autoprefixer@^6.3.1:
325325
postcss "^5.2.16"
326326
postcss-value-parser "^3.2.3"
327327

328-
aws-sdk@^2.221.1:
329-
version "2.296.0"
330-
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.296.0.tgz#109016088b7edc063a5e5bc36537632e02e91447"
328+
aws-sdk@^2.282.1:
329+
version "2.299.0"
330+
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.299.0.tgz#9c12f924f1e28d22899816e112dcb722c4bccf30"
331331
dependencies:
332332
buffer "4.9.1"
333333
events "1.1.1"
@@ -537,7 +537,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
537537
dependencies:
538538
babel-runtime "^6.22.0"
539539

540-
babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1:
540+
babel-plugin-transform-es2015-block-scoping@^6.23.0:
541541
version "6.26.0"
542542
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
543543
dependencies:
@@ -547,7 +547,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20
547547
babel-types "^6.26.0"
548548
lodash "^4.17.4"
549549

550-
babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1:
550+
babel-plugin-transform-es2015-classes@^6.23.0:
551551
version "6.24.1"
552552
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
553553
dependencies:
@@ -561,33 +561,33 @@ babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-cla
561561
babel-traverse "^6.24.1"
562562
babel-types "^6.24.1"
563563

564-
babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1:
564+
babel-plugin-transform-es2015-computed-properties@^6.22.0:
565565
version "6.24.1"
566566
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
567567
dependencies:
568568
babel-runtime "^6.22.0"
569569
babel-template "^6.24.1"
570570

571-
babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0:
571+
babel-plugin-transform-es2015-destructuring@^6.23.0:
572572
version "6.23.0"
573573
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
574574
dependencies:
575575
babel-runtime "^6.22.0"
576576

577-
babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1:
577+
babel-plugin-transform-es2015-duplicate-keys@^6.22.0:
578578
version "6.24.1"
579579
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e"
580580
dependencies:
581581
babel-runtime "^6.22.0"
582582
babel-types "^6.24.1"
583583

584-
babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0:
584+
babel-plugin-transform-es2015-for-of@^6.23.0:
585585
version "6.23.0"
586586
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
587587
dependencies:
588588
babel-runtime "^6.22.0"
589589

590-
babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1:
590+
babel-plugin-transform-es2015-function-name@^6.22.0:
591591
version "6.24.1"
592592
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b"
593593
dependencies:
@@ -618,30 +618,30 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e
618618
babel-template "^6.26.0"
619619
babel-types "^6.26.0"
620620

621-
babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1:
621+
babel-plugin-transform-es2015-modules-systemjs@^6.23.0:
622622
version "6.24.1"
623623
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
624624
dependencies:
625625
babel-helper-hoist-variables "^6.24.1"
626626
babel-runtime "^6.22.0"
627627
babel-template "^6.24.1"
628628

629-
babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1:
629+
babel-plugin-transform-es2015-modules-umd@^6.23.0:
630630
version "6.24.1"
631631
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
632632
dependencies:
633633
babel-plugin-transform-es2015-modules-amd "^6.24.1"
634634
babel-runtime "^6.22.0"
635635
babel-template "^6.24.1"
636636

637-
babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1:
637+
babel-plugin-transform-es2015-object-super@^6.22.0:
638638
version "6.24.1"
639639
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
640640
dependencies:
641641
babel-helper-replace-supers "^6.24.1"
642642
babel-runtime "^6.22.0"
643643

644-
babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1:
644+
babel-plugin-transform-es2015-parameters@^6.23.0:
645645
version "6.24.1"
646646
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
647647
dependencies:
@@ -652,7 +652,7 @@ babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-
652652
babel-traverse "^6.24.1"
653653
babel-types "^6.24.1"
654654

655-
babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1:
655+
babel-plugin-transform-es2015-shorthand-properties@^6.22.0:
656656
version "6.24.1"
657657
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
658658
dependencies:
@@ -665,7 +665,7 @@ babel-plugin-transform-es2015-spread@^6.22.0:
665665
dependencies:
666666
babel-runtime "^6.22.0"
667667

668-
babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1:
668+
babel-plugin-transform-es2015-sticky-regex@^6.22.0:
669669
version "6.24.1"
670670
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc"
671671
dependencies:
@@ -679,13 +679,13 @@ babel-plugin-transform-es2015-template-literals@^6.22.0:
679679
dependencies:
680680
babel-runtime "^6.22.0"
681681

682-
babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0:
682+
babel-plugin-transform-es2015-typeof-symbol@^6.23.0:
683683
version "6.23.0"
684684
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
685685
dependencies:
686686
babel-runtime "^6.22.0"
687687

688-
babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1:
688+
babel-plugin-transform-es2015-unicode-regex@^6.22.0:
689689
version "6.24.1"
690690
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9"
691691
dependencies:
@@ -701,7 +701,7 @@ babel-plugin-transform-exponentiation-operator@^6.22.0:
701701
babel-plugin-syntax-exponentiation-operator "^6.8.0"
702702
babel-runtime "^6.22.0"
703703

704-
babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1:
704+
babel-plugin-transform-regenerator@^6.22.0:
705705
version "6.26.0"
706706
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f"
707707
dependencies:
@@ -749,35 +749,6 @@ babel-preset-env@^1.6.1:
749749
invariant "^2.2.2"
750750
semver "^5.3.0"
751751

752-
babel-preset-es2015@^6.24.1:
753-
version "6.24.1"
754-
resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939"
755-
dependencies:
756-
babel-plugin-check-es2015-constants "^6.22.0"
757-
babel-plugin-transform-es2015-arrow-functions "^6.22.0"
758-
babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
759-
babel-plugin-transform-es2015-block-scoping "^6.24.1"
760-
babel-plugin-transform-es2015-classes "^6.24.1"
761-
babel-plugin-transform-es2015-computed-properties "^6.24.1"
762-
babel-plugin-transform-es2015-destructuring "^6.22.0"
763-
babel-plugin-transform-es2015-duplicate-keys "^6.24.1"
764-
babel-plugin-transform-es2015-for-of "^6.22.0"
765-
babel-plugin-transform-es2015-function-name "^6.24.1"
766-
babel-plugin-transform-es2015-literals "^6.22.0"
767-
babel-plugin-transform-es2015-modules-amd "^6.24.1"
768-
babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
769-
babel-plugin-transform-es2015-modules-systemjs "^6.24.1"
770-
babel-plugin-transform-es2015-modules-umd "^6.24.1"
771-
babel-plugin-transform-es2015-object-super "^6.24.1"
772-
babel-plugin-transform-es2015-parameters "^6.24.1"
773-
babel-plugin-transform-es2015-shorthand-properties "^6.24.1"
774-
babel-plugin-transform-es2015-spread "^6.22.0"
775-
babel-plugin-transform-es2015-sticky-regex "^6.24.1"
776-
babel-plugin-transform-es2015-template-literals "^6.22.0"
777-
babel-plugin-transform-es2015-typeof-symbol "^6.22.0"
778-
babel-plugin-transform-es2015-unicode-regex "^6.24.1"
779-
babel-plugin-transform-regenerator "^6.24.1"
780-
781752
babel-register@^6.26.0:
782753
version "6.26.0"
783754
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
@@ -2797,7 +2768,7 @@ lodash@^2.4.1:
27972768
version "2.4.2"
27982769
resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e"
27992770

2800-
lodash@^4.14.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0:
2771+
lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0:
28012772
version "4.17.10"
28022773
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
28032774

@@ -2899,7 +2870,7 @@ miller-rabin@^4.0.0:
28992870
bn.js "^4.0.0"
29002871
brorand "^1.0.1"
29012872

2902-
mime@^2.2.2:
2873+
mime@^2.3.1:
29032874
version "2.3.1"
29042875
resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369"
29052876

@@ -4765,4 +4736,3 @@ yargs@^12.0.1:
47654736
which-module "^2.0.0"
47664737
y18n "^3.2.1 || ^4.0.0"
47674738
yargs-parser "^10.1.0"
4768-

0 commit comments

Comments
 (0)