Coder Social home page Coder Social logo

googlechromelabs / sw-toolbox Goto Github PK

View Code? Open in Web Editor NEW
3.6K 109.0 332.0 1.13 MB

[Deprecated] A collection of service worker tools for offlining runtime requests

Home Page: https://developers.google.com/web/tools/workbox/guides/migrations/migrate-from-sw

License: Apache License 2.0

JavaScript 96.85% HTML 3.08% Ruby 0.08%
javascript service-worker service-workers progressive-web-app caching offline-first

sw-toolbox's Introduction

⚠️ sw-toolbox ⚠️

sw-toolbox and sw-precache are deprecated in favor of Workbox. Please read this migration guide for information on upgrading.

About

A collection of tools for service workers

Service Worker Toolbox provides some simple helpers for use in creating your own service workers. Specifically, it provides common caching strategies for dynamic content, such as API calls, third-party resources, and large or infrequently used local resources that you don't want precached.

Service Worker Toolbox provides an expressive approach to using those strategies for runtime requests. If you're not sure what service workers are or what they are for, start with the explainer doc.

What if I need precaching as well?

Then you should go check out sw-precache before doing anything else. In addition to precaching static resources, sw-precache supports optional runtime caching through a simple, declarative configuration that incorporates Service Worker Toolbox under the hood.

Install

Service Worker Toolbox is available through Bower, npm or direct from GitHub:

bower install --save sw-toolbox

npm install --save sw-toolbox

git clone https://github.com/GoogleChrome/sw-toolbox.git

Register your service worker

From your registering page, register your service worker in the normal way. For example:

navigator.serviceWorker.register('my-service-worker.js');

As implemented in Chrome 40 or later, a service worker must exist at the root of the scope that you intend it to control, or higher. So if you want all of the pages under /myapp/ to be controlled by the worker, the worker script itself must be served from either / or /myapp/. The default scope is the containing path of the service worker script.

For even lower friction, you can instead include the Service Worker Toolbox companion script in your HTML as shown below. Be aware that this is not customizable. If you need to do anything fancier than register with a default scope, you'll need to use the standard registration.

<script src="/path/to/sw-toolbox/companion.js" data-service-worker="my-service-worker.js"></script>

Add Service Worker Toolbox to your service worker script

In your service worker you just need to use importScripts to load Service Worker Toolbox:

importScripts('bower_components/sw-toolbox/sw-toolbox.js');  // Update path to match your own setup.

Use the toolbox

To understand how to use the toolbox read the Usage and API documentation.

License

Copyright 2015-2016 Google, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

sw-toolbox's People

Contributors

addyosmani avatar cvan avatar dandv avatar davidscales avatar garbee avatar gierschv avatar jeffposnick avatar jpmedley avatar mcrayray avatar mickeywu avatar mohsen1 avatar nickiaconis avatar psimyn avatar samertm avatar shantanuraj avatar thbp avatar tusharmath avatar wibblymat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sw-toolbox's Issues

Can I serve an Offline page?

I currently have

toolbox.precache([
    '/Offline',
    '/Offline/Json'
]);

toolbox.router.get('/(.*)', toolbox.networkFirst);

How easy is it for me to serve the offline page if the requested HTML is not in the cache already?

Possible to bypass service worker for video sources?

First, thank you for this great library!

I have a use case where I want to both be able to bypass the service worker cache and also for some videos cache them. Right now I am just setting a

[sw-toolbox] Strategy: network only [http://domain.com/video/53ff58afaf3f1ca111126715.mov]

Fetch API cannot load http://domain.com/video/53ff271c1cd2ce4082931973.mov. Request header field range is not allowed by Access-Control-Allow-Headers in preflight response.

The FetchEvent for "http://domain.com/video/53ff271c1cd2ce4082931973.mov" resulted in a network error response: the promise was rejected.
(program):1 Uncaught (in promise) TypeError: Failed to fetch(…)

Is there a way to to let certain videos bypass the service worker cache based on say an url-pattern, and let others get cached?

Returning cached resource based on route without considering method

I'm using sw-toolbox through Polymer's platinum-sw-cache and iron-ajax and it's come up with a bit of strange behaviour explained below:

GET /api/resource --> 200 {"data": [{"id": 1}, {"id":2}]
POST /api/resource --> Server sends 422 {"errors": [{"description": "can't be blank"}]}, SW intercepts and returns 200 {"data": [{"id": 1}, {"id":2}] `Status Code:200 OK (from ServiceWorker)`

However, When inspecting the service worker, it shows 2 Requests:

Request Method:OPTIONS
Status Code:200 OK
Request Method:POST
Status Code:422 Unprocessable Entity

and POST https://localhost:4000/api/resource 422 (Unprocessable Entity) in the console

TBH, I don't really expect anything but GET to be cached, which may the case, but it definitely shouldn't replace my POST's 422 and body with a 200 OK and the GET body.

sw-toolbox Mock Interest?

I've created a mock for sw-toolbox to unit test my code that uses sw-toolbox.

I'm happy to donate it (or some form of it) here if this project thinks this is a good thing to do/allow.

Regardless, would be good to get technical feedback on this.

Example usage

Better example usage

Thanks again for creating this library.

New npm release

Hi guys,

Could you publish the latest changes with a NPM release? Running into errors with 'options.cache.name' with the older version.

Thanks

toolbox.precache should not cache invalid files

At the moment toolbox.precache will cache a 404 response.

My initial assumption this in unexpected default behavior (and not something I think would be desirable in any situation).

Would allowing 20x status be a better option?

The concern this raises is what is the behavior when a 404 is encountered? I would expect the service worker install to fail.

Warn if routes overwrite each other

If I have a route for :foo/:bar and another for :baz/:quux then they compile to the same regex, and one will overwrite the other.

This should cause an error or warning in the console.

Unable to match API requests

I'm trying to match API requests that use cookie and qstring CSRF parameters.
I seem to be unable to match API requests in the cache.

I've verified the responses are getting into the cache, but I'm unable to match the key with subsequent requests.

Items of note:

  1. Even though I specify { credentials: 'include' } in the Request, the Request that gets stored in the cache is { credentials: 'omit' }.
  2. No way to send { ignoreSearch: true } to cache.match options.
  3. vary: Accept-Encoding (Content-Encoding: gzip)

Example, CSRF tokens at end of url:

Key Url (Request in cache associated with response):
http://localhost:3000/_api/page;format=markdown;models=%5B%22LocalBusiness%22%2C%22SiteInfo%22%5D;pageTitle=About;resource=about;url=https%3A%2F%2Fapi.github.com%2Frepos%2Flocalnerve%2Fflux-react-example-data%2Fcontents%2Fpages%2Fabout.md?_csrf=DgDQBtRH-qbZvUXqBhAz6lsYwiE-JazMUjLs

Offline Url (Request made while offline, does not match):
http://localhost:3000/_api/page;format=markdown;models=%5B%22LocalBusiness%22%2C%22SiteInfo%22%5D;pageTitle=About;resource=about;url=https%3A%2F%2Fapi.github.com%2Frepos%2Flocalnerve%2Fflux-react-example-data%2Fcontents%2Fpages%2Fabout.md?_csrf=4Uq9fOBW-GYJRq-wjE_uaPjNW_QBlQutIp6I

I played around with my own version of sw-toolbox that added { ignoreSearch: true } in a specific case (for offline cache fallback), but did not get results.

I'm still looking for clear reason why I can't match the Request, but haven't found one just yet.
Ideas?

Use FetchEvent.waitUntil() for cache expiration logic

Right now, the logic for cache expiration (if enabled) is started asynchronously in the onfetch handler following the call to FetchEvent.respondWith().

This ensures that the controlled page gets the response without being blocked during the time it takes for the cache expiration logic to run. Unfortunately, there's the possibility that the browser will terminate the service worker before the cache expiration logic has a chance to complete.

This is not likely in the current Chrome implementation at least (which tends to keep the service worker running following a fetch event for at least a few seconds), but it would be ideal to specifically tell the service worker to stay alive while the cache expiration code runs.

w3c/ServiceWorker#584 tracks FetchEvent.waitUntil(), which looks like will make it to browsers at some point. Another related bug is w3c/ServiceWorker#679

API Feedback

Just reading through the readme and the naming of router.get, router.post, router.... generally doesn't really explain what the function is going to do when reading it on its own.

router.addGetRequestHandler <- much longer, but does explain the goal.
router.addGetHandler()

I was reading through the WSK implementation and it was my first time at reading through sw-toolbox code and was pretty quickly lost:

global.toolbox.router.get('/(.*)', global.toolbox.fastest, {
origin: /.(?:googleapis|gstatic).com$/
});

Remove custom rules from .eslintrc

In #60 we started using the Google ESLint config but I cheated and added/kept some custom rules.

I should remove the rules and fix the remaining lint errors.

Clean up the option parsing logic

There's a lot of repeated code that involves looking for the local options parameter's value and falling back to the global configuration provided by toolbox.options. I am pretty sure we can clean up some of that.

Move build artefacts out of master

The built version of the library (sw-toolbox.js and sw-toolbox.map.json) lives in the master branch, but in an ideal world we would only keep the source in the repo. It is easy for the built version to become out of sync with the source.

The only reason that we put the built version in git is because that's what Bower needs. However, we could create a separate builds branch, populate it only with the Bower version of the library, and tag new versions there instead. We can create a gulp task that automates this process for us when it is time to publish a new version.

The npm version would still come from master, but that doesn't need to be pre-built. If you are using npm then we can assume that you are going to require() the source files and do your own build.

Any concerns? @addyosmani @jeffposnick

Distribution for "helper" scripts

There are a number of novel things you can build on top of the core sw-toolbox library, e.g.:

  • Offline Google Analytics
  • An Appcache-manifest converter
  • A set of cache strategies for resources distributed on common CDNs
  • your idea here

We should come up with a standard way of distributing first-party helper scripts.

Possible approaches:

  • Creating a helpers or addons directory within the main project. This would make the helper scripts more discoverable, but versioning them sanely would be difficult.
  • Creating a new sw-toolbox-helpers repo to host them all en masse. This would be less discoverable than if they were bundled with sw-toolbox, and versioning each script independently of the others wouldn't be possible.
  • Creating a new sw-toolbox-helper-XYZ repo for each helper script. This would have similar discoverability problems but we would be able to version each helper script properly.

Thoughts? CC: @wibblymat @addyosmani

Resolve ES6-compatibility issues with current build

Against the current master and node v0.12.7, checking out the code and running npm install followed by gulp build leads to the following failure, since the underyling uglify-js library doesn't support the ES6 for...of syntax:

/usr/local/bin/node /usr/local/lib/node_modules/gulp/bin/gulp.js --color --gulpfile /Users/jeff/git/sw-toolbox/gulpfile.js build
[13:19:21] Using gulpfile ~/git/sw-toolbox/gulpfile.js
[13:19:21] Starting 'build'...
uglify-js failed on lib/router.js : Unexpected token name «of», expected punc «;» (line: 25, col: 16, pos: 785)

Error
    at new JS_Parse_Error (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:196:18)
    at js_error (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:204:11)
    at croak (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:684:41)
    at token_error (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:688:9)
    at expect_token (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:701:9)
    at expect (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:704:36)
    at regular_for (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:934:9)
    at for_ (/Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:930:16)
    at /Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:812:24
    at /Users/jeff/git/sw-toolbox/node_modules/minifyify/node_modules/uglify-js/lib/parse.js:727:24
[13:19:22] Finished 'build' after 772 ms

Process finished with exit code 0

Rethink the pathname/origin split when defining handlers

I've never taken to the ExpressJS-style routes used to define custom handlers. It might make sense for situations in which you're normally matching same-origin URLs and you care about assigning portions of the pathname to request handler parameters, but I find it clumsy for, e.g., matching any request made against a given remote origin.

How about we start accepting a RegExp object as the first parameter to the .get(), etc. registration handlers? We could still support the old syntax as well. When there's a RegExp passed in, we use it as a match against the full event.request.url to determine whether the handler applies. We could expose any embedded capture groups in the parameters passed in to the handler, too.

That would allow for, e.g.,

toolbox.router.get(/example\.com.+\.json/, function(request) {
  // handle GET request made to example.com that ends in '.json'
});

instead of the current

toolbox.router.get('/(.*).json', function(request) {
  // handle GET request made to example.com that ends in '.json'
}, {origin: /example\.com/});

Support for cache expiration

Brainstorming a bit: it would be useful if sw-toolbox had built-in support for cache expiration. It might take the form of associating LRU or oldest-first expiration policies with a specific named Cache object, along with a maximum number of entries, and then enforcing those policies via the built-in methods that store new entries. IndexedDB could be used to aid in bookkeeping.

sw-toolbox currently makes some assumptions about there only being a single named cached that your app works with globally, so relaxing some of those assumptions might be part of this work.

My ideal way of using sw-toolbox

This is just an idea, but after looking at sw-precache and sw-toolbox, I'm finding it more and more scary how heavily I end up relying on it and how removed it is from everything else I use on a day to day basis.

In an ideal world this is the sort of thing I would want to write, I know this is a broken record comment and looks over issues you have probably overcome, this feels much safer to me as a consumer of the libraries:

importScripts('/scripts/sw-toolbox.js');

var CACHE_NAME = 'appshell';
var CACHE_VERSION = '@VERSION@';

var swToolbox = new SWToolbox(CACHE_NAME, CACHE_VERSION);

// Serve from cache if available and update in the bg
swToolbox.addHandler('https://fonts.googleapis.com/*', {
  strategy: cacheFirstAndUpdate
});

// Useful for single page web apps
swToolbox.addHandlerForNavigations('/*', {}, function(request) {
  return caches.match('/app-shell');
});

// Cache these pages as they are visited
swToolbox.addHandler('/blog/*', {
  strategy: cacheOnVisit
});

// if all else fails serve from the net worker only
swToolbox.setDefaultHandler({
  strategy: networkOnly
});

self.addEventListener('install', function(event) {
  return event.waitUntil(function() {
    return swToolbox.precache([
      '@SW_PRECACHE:ASSET_LIST@'
    ]);
  });
});

self.addEventListener('activate', function(event) {
  return event.waitUntil(function() {
    return swToolbox.cleanCaches(CACHE_VERSION);
  });
});


self.addEventListener('fetch', function(event) {
  return event.waitUntil(function() {
    return swToolbox.handleRequest(event);
  });
});

toolbox.precache - Mixture of strings, promises, arrays leads to some assets not caching

Just tried the following:

self.toolbox.precache([
  '/test/data/files/text.txt',
  Promise.resolve('/test/data/files/text-1.txt'),
  [
    '/test/data/files/text-2.txt',
    Promise.resolve('/test/data/files/text-3.txt')
  ],
  [
    '/test/data/files/text-4.txt',
    Promise.resolve('/test/data/files/text-5.txt')
  ]
]);

The behavior has bad side effects and is inconsistent.

Looks like promises nested in an array will attempt to cache:

http://localhost:8888/test/browser-tests/precache/serviceworkers/[object%20Object]

In this case that would be test-3.txt and test-5.txt. This is the side effect.

Inconsistent behavior is that if nested promises aren't allowed, then it's hard to follow why text-2 and text-4 would be cached (which they are).

Flatten precache() results before passing to cache.addAll()

https://github.com/GoogleChrome/sw-toolbox/blob/79def66583319e2da08cb962ed29cc0af8a2a0c9/lib/sw-toolbox.js#L35 is currently return Promise.all(options.preCacheItems).then(cache.addAll.bind(cache));

cache.addAll() takes in a one-dimensional array of either URLs or Request objects, but Promise.all() might resolve to a multi-dimensional array if the underlying promises in options.preCacheItems each resolve to an array.

sw-toolbox should flatten the value that Promise.all() resolves with before passing it along to cache.addAll().

Question about examples.

Hi @wibblymat Thanks for sw-toolbox!

I'm trying to find examples. Can you point me to examples of applications using sw-toolbox. I apologize for not finding them.

I tried from the documentation to create an example. See https://civic-data.github.io/laws-of-planet-earth/us/ny/scripts_openlegislation/getdata1_swtoolkit.html

I only seem to be able to cache some of the data.

How do I turn on debug in the sw-toolbox.js?

It appears that globalOptions.debug and options.debug can be set to true, but I don't see how to set it.

Again I apologize for not finding it and thank you for the toolbox!

service worker support is amazing! I agree with @jakearchibald that this changes applications for the better!

Uncaught (in promise) TypeError: Request method 'POST' is unsupported

Hi, when trying to run the Polymer Starter Kit I get following TypeError

Uncaught (in promise) TypeError: Request method 'POST' is unsupported
    at TypeError (native)
    at http://localhost:3000/bower_components/sw-toolbox/sw-toolbox.js:20:430

I'm running Chrome/43.0.2357.65. Is this version of Chrome missing some features which are mandatory to use sw-toolbox?

Option to define the scope when using the companion script

When using the companion script:

<script src="companion.js" data-service-worker="/sw.js"></script>

it would be great to have the option to define the scope with a data attribute, eg.

<script src="companion.js" data-service-worker="/sw.js" data-scope="/blog"></script>

What do you think?

Want to be able to use the Npmjs package as a Node library in builds

First, thanks for this tool, it looks really great and promises to save tons of boilerplate.

I'm trying to use it as a component library in my own service worker build. I'm bundling the service worker instead of using importScripts for each module - Want one trip (no HTTP/2).

I'm using the sw-toolbox npm package 2.0.4, and I'm having difficulties:

  1. Uglify chokes on the pre-built source code.
  2. No 'main' in package.json, so require('sw-toolbox/sw-toolbox') is weird.

The raw error (Uglifying the built code):

WARNING in ./~/sw-toolbox/sw-toolbox.js
Critical dependencies:
17:438-445 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
 @ ./~/sw-toolbox/sw-toolbox.js 17:438-445

ERROR in sw.84e0fb9382841b26f9da.min.js from UglifyJs
Unexpected token name «of», expected punc «;» [./~/sw-toolbox/sw-toolbox.js:50,0]

The npmjs package only has the pre-built source code, not the library code.
I know I can just use the git repo, but prefer npmjs and node package management semantics througout the project.

Any reason not to just publish the library source code in the npm package for a more "node aligned" experience?

Proposal for precache API simplification

cc @addyosmani @wibblymat @jeffposnick

At the moment the precache API allows strings, arrays and promises.

I would like to propose the following:

Change precache to accept only an array, this will cause:

toolbox.precache('/single-asset);

to be written as:

toolbox.precache(['/single-asset']);

Secondly remove support for nested arrays. This would require the developer to flatten the arrays and means the API wouldn't need to have some arbitrary limit on the number of nests.

 toolbox.precache(['/single-asset', ['/asset-nested', '/asset-nested-2']]);

becomes:

     toolbox.precache(['/single-asset', '/asset-nested', '/asset-nested-2']);

I don't feel like asking dev to do this is too much of an ask (lodash has a deepflatten method if consumers of the library wanted a quick solution).

I feel like the majority of users will want several assets cached rather than a single asset for the majority of the time.

I'm struggling what a good reasoning for promises in precache. I can see some value in being able to get an asset list, are there other use cases?

The main reason I see it as being beneficial is largely because the precache method abstracts away the ability to use event.waitUntil , so this support is your only option to perform some async action.

Ideally I'd like to see either precache take a single promise i this scenario and expect consumers of the library to make user of Promise.all or whatever means to manage logic required OR make it such that toolbox caching can be done from within the install step.

For the single promise approach the expectation of this would be to return an array of strings to cache. This would ideally be named something differently to avoid overloading the precache method.

This would result in an API surface of something along the lines of:

toolbox.precache();
toolboxprecacheAsync();

Consider sorting URL parameters before cache matching/fetching

Inspired by https://twitter.com/igrigorik/status/605766338687016960, it could help with cache hits. A naive approach would be to do this prior to populating or checking the cache:

// url is a URL object: https://developer.mozilla.org/en-US/docs/Web/API/URL

url.search = url.search.slice(1).split('&').sort(function(kp1, kp2) {
  return kp1.split('=')[0] > kp2.split('=')[0];
}).join('&');

// url now has sorted search parameters.

I'm sure there's a more efficient way of doing this that doesn't keep re-splitting the key/parameter pairs. An alternative would be to just sort on the full kp1 and kp2 string values, which would be stable but not "properly" sorted if either string contains a character that follows '=' alphabetically.

This is probably safe to do by default, while something like using CacheQueryOptions.ignoreSearch wouldn't be (and isn't currently supported by Chrome, if I recall correctly).

Feature request: Update preFetch files

For the option global.toolbox.precache, it will be good to give an update strategy. Can we have a method or option to update the list of values in precache or take an array and update the cache with latest values.

Unit tests broken

The current unit tests are broken for two reasons:

#39 made it so that the default route only applies to GET requests, and there are a number of tests that exercise the default route with other methods, starting at https://github.com/GoogleChrome/sw-toolbox/blob/master/tests/tests.js#L68 Those tests should probably just be removed.

Also, the tests wait on .ready instead of waiting until the page is controlled by the service worker, which makes the first test in the suite flaky. (See w3c/ServiceWorker#799).

Make the install/activate events opt-in

At the moment we register event handlers for install and activate that are not configurable.

We should instead provide the primitives necessary to get the same effect as the current code and have the developer call them from their own event handlers.

cc @jeffposnick @gauntface

toolbox.precache Arrays of Arrays Need Removing of error on X levels deep

At the moment you can do the following:

self.toolbox.precache([
  '/test/data/files/text.txt',
  [
    '/test/data/files/text-1.txt',
    '/test/data/files/text-2.txt'
  ],
  [
    '/test/data/files/text-3.txt',
    [
      '/test/data/files/text-4.txt',
      [
        '/test/data/files/text-5.txt',
        [
          '/test/data/files/text-6.txt',
          [
            '/test/data/files/text-7.txt',
            [
              '/test/data/files/text-8.txt'
            ]
          ]
        ]
      ]
    ]
  ]
]);

Based on the test results, this will result in 5 assets being cached, presumably text.txt -> text-4.txt. Either this API should be simplified to support a single array level of assets and error if it finds nested arrays or it needs recursively loop through nested arrays.

Personally - I would say it should only include support for a single array.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.