{"id":33987615,"url":"https://github.com/pagespeed-pro/async","last_synced_at":"2026-03-08T16:36:20.173Z","repository":{"id":45766337,"uuid":"187382781","full_name":"pagespeed-pro/async","owner":"pagespeed-pro","description":"A lightweight and high performance async CSS and script loader for frontend optimization.","archived":false,"fork":false,"pushed_at":"2021-12-03T12:16:26.000Z","size":1079,"stargazers_count":19,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-13T15:39:56.545Z","etag":null,"topics":["async","async-css","capture","css-loader","localstorage","script-loader"],"latest_commit_sha":null,"homepage":"https://pagespeed.pro/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pagespeed-pro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-18T16:49:50.000Z","updated_at":"2024-08-07T19:26:11.000Z","dependencies_parsed_at":"2022-09-08T04:51:48.542Z","dependency_job_id":null,"html_url":"https://github.com/pagespeed-pro/async","commit_stats":null,"previous_names":["style-tools/async"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/pagespeed-pro/async","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pagespeed-pro%2Fasync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pagespeed-pro%2Fasync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pagespeed-pro%2Fasync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pagespeed-pro%2Fasync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pagespeed-pro","download_url":"https://codeload.github.com/pagespeed-pro/async/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pagespeed-pro%2Fasync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27700973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-13T02:00:09.769Z","response_time":147,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","async-css","capture","css-loader","localstorage","script-loader"],"created_at":"2025-12-13T05:31:24.412Z","updated_at":"2025-12-13T05:31:24.977Z","avatar_url":"https://github.com/pagespeed-pro.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.com/style-tools/async.svg?branch=master)](https://travis-ci.com/style-tools/async) [![Version](https://img.shields.io/github/release/style-tools/async.svg)](https://github.com/style-tools/async/releases) [![npm version](https://badge.fury.io/js/%40style.tools%2Fasync.svg)](http://badge.fury.io/js/%40style.tools%2Fasync) [![Latest Stable Version](https://poser.pugx.org/styletools/async/v/stable.png)](https://packagist.org/packages/styletools/async)\n\n# `$async` Async CSS and Script Loader\n\nA lightweight and high performance async CSS and script loader with state of the art features for frontend optimization (FEO). \n\n### Install via npm\n\n```bash\nnpm install @style.tools/async --save\n```\n\n### Install via PHP Composer\n\n```bash\ncomposer require styletools/async\n```\n\n## Examples\n\n```javascript\n$async([\n   'sheet.css',\n   'script.js'\n]).then(function() { /* ready */ });\n```\n\n`$async` can be controlled from a HTML attribute which enables strict security.\n\n```html\n\u003c!-- config via an HTML attribute --\u003e\n\u003cscript async src=\"js/async-iife.js\" data-c='[\n   [\n      \"css/sheet1.css\",\n      \"js/script.js\",\n      {\n         \"href\": \"https://cdn.com/css/sheet2.css\",\n         \"attributes\": {\n            \"integrity\": \"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC\",\n            \"crossorigin\": \"anonymous\"\n         }\n      },\n      {\n         \"src\": \"https://cdn.com/js/script2.js\",\n         \"attributes\": {\n            \"integrity\": \"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC\",\n            \"crossorigin\": \"anonymous\"\n         },\n         \"load_timing\": \"domReady\",\n         \"ref\": \"x\"\n      },\n      {\n         \"src\": \"js/script3.js\",\n         \"dependencies\": \"x\"\n      }\n   ],\n   {\n      \"render_timing\": \"requestAnimationFrame\",\n      \"exec_timing\": {\n         \"type\": \"requestIdleCallback\",\n         \"timeout\": 1000\n      }\n   }\n]'\u003e\u003c/script\u003e\n```\n\nThe JSON configuration can be compressed to save size in the HTML ([online compressor](https://style.tools/async/)).\n\n```html\n\u003cscript async src=\"js/async-iife.js\" data-c='[[\"css/sheet1.css\",\"js/script.js\",{\"4\":\"https://cdn.com/css/sheet2.css\",\"14\":{\"integrity\":\"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC\",\"crossorigin\":\"anonymous\"}},{\"5\":\"https://cdn.com/js/script2.js\",\"14\":{\"integrity\":\"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC\",\"crossorigin\":\"anonymous\"},\"16\":\"x\",\"48\":54},{\"5\":\"js/script3.js\",\"15\":\"x\"}],{\"49\":52,\"60\":{\"2\":53,\"57\":1000}}]'\u003e\u003c/script\u003e\n```\n\n## Documentation\n\nDocumentation is available on [docs.style.tools/async](https://docs.style.tools/async).\n\n- [Online IIFE generator](https://style.tools/iife/)\n- [JSON config editor and compressor](https://style.tools/async/)\n\n\n## Description\n\n$async is designed as the ultimate CSS and script loader for modern frontend optimization (FEO). It provides state of the art features, the absolute best performance and the tiniest HTML footprint. $async supports all browsers including IE9+.\n\n- 100% JSON control.\n- Google Closure Compiler (GCC) with _Advanced mode_ script compression (reliable and performant in all browsers).\n\n### Modular\n$async is modular and easy to use: select only the features that are needed to achieve the tiniest script size.\n- simply stitch pre-optimized GCC modules together for a performant IIFE. You can wrap the modules in [dist/](./dist/) into an IIFE, e.g. `!function(){/* stitched modules */}();`. Follow the module order in [package.json](./package.json).\n- [Online IIFE generator](https://style.tools/iife/) (adds an extra GCC _Advanced mode_ compression layer)\n- [Node.js/CLI IIFE generator](https://github.com/style-tools/async-iife) (adds an extra GCC _Advanced mode_ compression layer)\n- PHP IIFE generator (available on request: info@style.tools)\n\n### Chainable\n```javascript\n$async\n   .on('load',function(sheet, sheetEl){\n      //  sheet.css or other-sheet.css loaded\n   }) \n   .on('sheet-ref',function() { }) // sheet with ref-name loaded\n   .on('sheet.css', function() {}); // sheet with href loaded\n   .load({\n      href: 'sheet.css', \n      ref: 'sheet-ref'\n   })\n   .then(function() { }) // sheet.css loaded\n   .load('other-sheet.css');\n```\n\n### Security\n$async supports a strict Content-Security-Policy (CSP) and SRI security by using a HTML attribute on the script element. The `data-c` attribute accepts JSON config.\n```html\n\u003cscript async src=\"js/async.js\" data-c='[\n   [\n      \"css/sheet1.css\",\n      {\n         \"href\": \"https://cdn.com/css/sheet2.css\",\n         \"attributes\": {\n            \"integrity\": \"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC\",\n            \"crossorigin\": \"anonymous\"\n         }\n      }\n   ]\n]'\u003e\u003c/script\u003e\n```\n\n### Advanced download and exec/render timing\n$async provides advanced loading and timing techniques.\n- control the insert target.\n- time the download and/or exec/render using methods such as `requestAnimationFrame`, `requestIdleCallback` and [$lazy](https://github.com/style-tools/lazy) (Intersection Observer).\n- dependency based loading.\n- responsive `Media Query` based loading with cross-browser support for viewport changes.\n- `just-in-time` loading using a custom javascript method.\n```javascript\n$async(\n   [\n      \"sheet.css\",\n      {\n         href:\"other-sheet.css\",\n         dependencies: [\"sheet.css\"], // wait for sheet.css via dependencies\n         load_timing: {\n            type: \"lazy\", // use $lazy for timing (Intersection Observer)\n            config: [\".selector-in-view\", 0, \"200px\"], // visible within 200 pixels\n         },\n         ref: \"other\"\n      }, \n      {\n         href:\"mobile-sheet.css\",\n         dependencies: \"other\", // dependency by ref\n         target: {\n            after: \"meta[charset]\" // control insert target\n         },\n         load_timing: {\n            type: \"media\", // download stylesheet based on a media query (works with viewport changes, e.g. viewport rotate)\n            media: \"screen and (max-width: 600px)\"\n         }\n      },\n      {\n         inline: \"inline_script_with_timing_and_dependency();\",\n         ref: \"inline-code\"\n      },\n      {\n         src: \"script.js\",\n         exec_timing: \"requestIdleCallback\",\n         dependencies: \"inline-code\"\n      }\n   ],\n   /* global options: applied to all stylesheets */\n   {\n      // base directory for relative sheet URLs\n      base: \"/long/path/to/css/\",\n\n      // render timing: paint sheet with requestAnimationFrame\n      render_timing: \"requestAnimationFrame\"\n   } \n)\n.then(function() { /* ready */ });\n```\n\n###  `just-in-time` loading\n```javascript\n$async(\n   {\n      href:\"popup-css.css\",\n      load_timing: {\n         type: \"method\", // trigger download using custom javascript method\n         method: \"load_popup_css\"\n      }\n   },{\n      src:\"popup-script.js\",\n      load_timing: {\n         type: \"method\",\n         method: \"load_popup_js\"\n      }\n   }\n);\n\n// just-in-time loading\njQuery('button.popup').on('click', function() {\n\n   // user clicks a button\n   // load popup script/css just-in-time\n\n    load_popup_css().then(function() {\n      alert('popup CSS loaded');\n    });\n\n    load_popup_js().then(function() {\n      alert('popup script loaded');\n    });\n});\n```\n### API's \n$async provides API's for access to the dependency resolver and timing methods.\n```javascript\n// dependency resolver\n$async.dependencies(['name'], function() { /* dependency loaded */ });\n\n// timing method\n$async.time(\"requestAnimationFrame\", function() { /* callback */ });\n$async.time(48, function() {}); // the same using the JSON compression index key for 'requestAnimationFrame'\n```\n### `localStorage` cache\n$async enables to load stylesheets and script from `localStorage` or [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) cache which is much faster than browser cache. \n\nFor a demo, see [css-art.com](https://css-art.com).\n\n```javascript\n$async({\n   href: \"sheet.css\",\n   cache: {\n      type: \"localstorage\",\n      max_size: 10000, // cache only \u003c10kb\n      fallback: \"cache-api\", // fallback to Cache-API for bigger sheets\n      update: {\n         head: true, // use HTTP HEAD request to check for 304 - Not Modified\n         interval: 86400 // update once per day\n      },\n\n      // control the source methods\n      source: [\"cssText\",\"xhr\",\"cors\"], // default\n\n      // optional: CORS proxy for retrieving the source code from external stylesheet URLs\n      cors: {\n         proxy: \"https://cors-anywhere.herokuapp.com/\", // more proxies on https://gist.github.com/jimmywarting/ac1be6ea0297c16c477e17f8fbe51347\n      },\n\n      // custom XHR config\n      xhr: {\n         headers: {\n            \"x-special-header\": \"secret-key\" // request header to include in XHR requests\n         }\n      }\n   }\n});\n```\n### JSON compression\n$async provides a JSON compression technique to minimize the size of configuration. \n\n[Online compressor](https://style.tools/iife/) | [Node.js/CLI](https://github.com/style-tools/async-iife)\n```javascript\n/* original config: \n{\n   \"href\":\"other-sheet.css\",\n   \"dependencies\": [\"sheet.css\"],\n   \"load_timing\":{\n      \"type\":\"lazy\",\n      \"config\": [\".selector-in-view\",0,\"200px\"]\n   },\n   \"ref\":\"other\"\n} */\n\n// compressed\n$async({\"4\":\"other-sheet.css\",\"15\":[\"sheet.css\"],\"16\":\"other\",\"48\":{\"2\":62,\"89\":[\".selector-in-view\",0,\"200px\"]}});\n```\n### Async script-injected stylesheet/script capture\n$async provides an innovation to capture and rewrite, remove or modify/optimize script-injected stylesheets and scripts. The solution supports both native DOM insert method rewriting and `MutationObserver`.\n- rewrite\n- remove\n- modify\n- optimize (code optimization, apply timing, responsive loading, dependencies etc.)\n```javascript\n// capture and remove async script-injected sheet\n$async.capture(\n   [\n      {\n         match: \"bloated-sheet.css\",\n         action: {\n            \"type\": \"remove\"\n         }\n      },\n      {\n         match: \"/\u003cscript[^\u003e]+bloated-script-id[^\u003e]+\u003e/\",\n         regex: true,\n         match_type: \"node\",\n         action: {\n            \"type\": \"remove\"\n         }\n      },\n      {\n         match: \"external-widget.com\",\n         action: {\n            type: \"rewrite\",\n            search: '/^.*cdn\\.external-widget\\.com/(.*).css$',\n            regex: true,\n            replace: \"/local-nginx-proxy/$1.css\",\n            async: {\n               \"load_timing\": \"requestIdleCallback\",\n               \"target\": {\n                  \"after\": \"media[charset]\"\n               },\n               \"attributes\": {\n                  \"data-cdn\": \"external-widget.com\"\n               }\n            }\n         }\n      },\n      {\n         match: \"customer-review.js\",\n         action: {\n            async: { \n               \"load_timing\": {\n                  type: 'lazy',\n                  config: '#customer-review' // load script when customer review widget enters viewport\n               }\n            }\n         }\n      }\n   ],\n   {\n      insert: true // use DOM insert method rewriting\n      // observer: true // alternative: use MutationObserver\n   }\n);\n```\n### Performance API timings for loading performance optimization\n$async provides a debug mode with advanced [Performance API](https://developer.mozilla.org/en-US/docs/Web/API/Performance) timings that enables to analyse and optimize the CSS and script loading performance.\n\n![$async demo](./async-debug-console.png)\n\n## Demo\n\n$async is in use on www.e-scooter.co (demo website) and [css-art.com](https://css-art.com) (test environment).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpagespeed-pro%2Fasync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpagespeed-pro%2Fasync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpagespeed-pro%2Fasync/lists"}