├── .npmrc ├── .npmignore ├── example ├── cached │ ├── file1.md │ └── file2.gif ├── .gitignore ├── README.md ├── index.html ├── package.json └── netlify.toml ├── .gitignore ├── manifest.yml ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── package.json ├── index.js └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | .netlify/ 3 | example/ 4 | -------------------------------------------------------------------------------- /example/cached/file1.md: -------------------------------------------------------------------------------- 1 | This is a file. A cached file. 2 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Local Netlify folder 2 | .netlify 3 | 4 | cache-output.json 5 | package-lock.json 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local Netlify folder 2 | .netlify 3 | 4 | node_modules/ 5 | package-lock.json 6 | npm-debug.log* 7 | -------------------------------------------------------------------------------- /example/cached/file2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakejarvis/netlify-plugin-cache/HEAD/example/cached/file2.gif -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | name: netlify-plugin-cache 2 | inputs: 3 | - name: paths 4 | description: Array of files and/or directories to cache between builds. 5 | default: [".cache"] 6 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | [![Netlify Status](https://api.netlify.com/api/v1/badges/8ceb6251-650b-481a-976c-fec1a4f95800/deploy-status)](https://app.netlify.com/sites/infallible-wing-581e78/deploys) 2 | 3 | https://infallible-wing-581e78.netlify.app/cache-output.json 4 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Hello world!

5 |

This is an example of netlify-plugin-cache. ⚡

6 |

7 | 8 | 9 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "netlify-plugin-cache-example", 4 | "version": "1.0.0", 5 | "description": "Just a test of netlify-plugin-cache.", 6 | "dependencies": { 7 | "netlify-plugin-cache": "file:../", 8 | "netlify-plugin-debug-cache": "^1.0.3" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/netlify.toml: -------------------------------------------------------------------------------- 1 | # only used in this example to build from parent directory 2 | [[plugins]] 3 | package = "@netlify/plugin-local-install-core" 4 | 5 | # package would normally equal `netlify-plugin-cache` 6 | [[plugins]] 7 | package = "../" 8 | [plugins.inputs] 9 | paths = ["cached"] 10 | 11 | [[plugins]] 12 | package = "netlify-plugin-debug-cache" 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | node: [14.x, 13.x, 12.x, 10.x] 10 | fail-fast: false 11 | runs-on: ubuntu-latest 12 | name: Node ${{ matrix.node }} 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: ${{ matrix.node }} 18 | - name: Install dependencies 19 | run: npm install --no-package-lock --no-optional 20 | - name: Run tests 21 | run: npm run test 22 | - name: Build example site locally with plugin 23 | run: npm run build 24 | env: 25 | NETLIFY_SITE_ID: '8ceb6251-650b-481a-976c-fec1a4f95800' 26 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jake Jarvis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netlify-plugin-cache", 3 | "version": "1.0.3", 4 | "description": "Generic cache plugin for saving and restoring files and/or folders between Netlify builds", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Jake Jarvis", 8 | "email": "jake@jarv.is", 9 | "url": "http://jarv.is/" 10 | }, 11 | "homepage": "https://github.com/jakejarvis/netlify-plugin-cache#readme", 12 | "bugs": "https://github.com/jakejarvis/netlify-plugin-cache/issues", 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/jakejarvis/netlify-plugin-cache.git" 16 | }, 17 | "main": "index.js", 18 | "scripts": { 19 | "build": "netlify build", 20 | "test": "xo" 21 | }, 22 | "dependencies": {}, 23 | "devDependencies": { 24 | "netlify-cli": "*", 25 | "xo": "~0.32.0" 26 | }, 27 | "engines": { 28 | "node": ">=10.18" 29 | }, 30 | "keywords": [ 31 | "netlify", 32 | "netlify-plugin", 33 | "cache", 34 | "ci", 35 | "build", 36 | "plugin" 37 | ], 38 | "xo": { 39 | "semicolon": false, 40 | "space": 2, 41 | "rules": { 42 | "object-curly-spacing": 0 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Netlify Plugin: netlify-plugin-cache 2 | // https://github.com/jakejarvis/netlify-plugin-cache 3 | // 4 | // This plugin is essentially a wrapper around Netlify's native `cache-utils`: 5 | // https://github.com/netlify/build/blob/master/packages/cache-utils/README.md 6 | 7 | module.exports = { 8 | // Try to restore cache before build begins, if it exists 9 | onPreBuild: async ({ utils: { cache }, inputs }) => { 10 | if (await cache.restore(inputs.paths)) { 11 | const files = await cache.list(inputs.paths) 12 | console.log(`Successfully restored: ${inputs.paths.join(', ')} ... ${files.length} files in total.`) 13 | } else { 14 | console.log(`A cache of '${inputs.paths.join(', ')}' doesn't exist (yet).`) 15 | } 16 | }, 17 | 18 | // Only save/update cache if build was successful 19 | onSuccess: async ({ utils: { cache, status }, inputs }) => { 20 | if (await cache.save(inputs.paths)) { 21 | const files = await cache.list(inputs.paths) 22 | console.log(`Successfully cached: ${inputs.paths.join(', ')} ... ${files.length} files in total.`) 23 | 24 | // Show success & more detail in deploy summary 25 | status.show({ 26 | title: `${files.length} files cached`, 27 | summary: 'These will be restored on the next build! ⚡', 28 | text: `${inputs.paths.join(', ')}` 29 | }) 30 | } else { 31 | // This probably happened because the default `paths` is set, so provide instructions to fix 32 | console.log(`Attempted to cache: ${inputs.paths.join(', ')} ... but failed. :(`) 33 | console.log('Try setting the \'paths\' input appropriately in your netlify.toml configuration.') 34 | console.log('More details: https://jrvs.io/netlify-cache-usage') 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚡ Netlify Plugin: Custom Cache [![npm](https://img.shields.io/npm/v/netlify-plugin-cache?logo=npm&color=red)](https://www.npmjs.com/package/netlify-plugin-cache) ![CI](https://github.com/jakejarvis/netlify-plugin-cache/workflows/CI/badge.svg) 2 | 3 | A generic cache plugin for saving and restoring files and/or folders between Netlify builds for impressive speed improvements. Worry less about running out of build minutes! ⏰ 4 | 5 | Essentially, this plugin is a pretty wrapper around [Netlify's native cache utility](https://github.com/netlify/build/blob/master/packages/cache-utils/README.md) — it isn't tied to any specific static site generator (on purpose). 6 | 7 | ## 💿 Install 8 | 9 | Add the following lines to your `netlify.toml`: 10 | 11 | ```toml 12 | [[plugins]] 13 | package = "netlify-plugin-cache" 14 | [plugins.inputs] 15 | # Optional (but highly recommended). Defaults to [".cache"]. 16 | paths = ["resources", "_vendor", "folder/file.md"] 17 | ``` 18 | 19 | This plugin only takes one input named `paths`: an array of files and/or directories relative to your project's root. These files/directories are restored before a build and saved in cache after a build **if it is successful**. 20 | 21 | **🚨 Important:** `paths` defaults to `[".cache"]`, but it's **highly recommended** you set this yourself based on the tool(s) you're using to generate your site. See examples below. 22 | 23 | Read more about plugin configuration at [the official Netlify Plugin docs](https://docs.netlify.com/configure-builds/build-plugins/#install-a-plugin). 24 | 25 | ## 👩‍💻 Usage 26 | 27 | - **Hugo:** Caching the `resources` directory can speed up your build greatly if you [process](https://gohugo.io/content-management/image-processing/) a lot of images, or compile SASS/SCSS via Hugo pipes. You can also cache the `public` directory to avoid completely rebuilding the entire site on each deploy. [More info here.](https://gohugo.io/getting-started/directory-structure/#directory-structure-explained) 28 | - **Gatsby:** By default, the `.cache` directory holds persistent data between builds. You can also cache the `dist` directory to avoid completely rebuilding the entire site on each deploy. [More info here.](https://www.gatsbyjs.org/docs/build-caching/) 29 | - **Jekyll:** A caching API was added as of v4. The notoriously slow SSG can become (relatively) faster by caching the `.jekyll-cache` directory. [More info here.](https://jekyllrb.com/tutorials/cache-api/) 30 | - **Next.js:** The `.next` directory holds the build output. [More info here.](https://nextjs.org/docs/api-reference/next.config.js/setting-a-custom-build-directory) 31 | - **Anything else:** This is the reason I kept this plugin as generic as possible! Research the caching behavior of your static site generator (and how to customize it if necessary). Feel free to open a PR and list it here as well! 32 | 33 | ## 🐛 Debugging 34 | 35 | This plugin doesn't provide a way to output a list of files that were cached or restored, because Netlify already provides an official plugin named [`netlify-plugin-debug-cache`](https://github.com/netlify-labs/netlify-plugin-debug-cache) to do exactly that. No need to re-invent the wheel! 36 | 37 | You can add the debug plugin **after** this plugin in your `netlify.toml`. (And yes, you need a `[[plugins]]` line for _each_ plugin you add.) 38 | 39 | ```toml 40 | [[plugins]] 41 | package = "netlify-plugin-debug-cache" 42 | ``` 43 | 44 | The debug plugin will generate a file named `cache-output.json` at the root of your project's publish directory. [See an example file](https://infallible-wing-581e78.netlify.app/cache-output.json) or [learn more about this plugin](https://github.com/netlify-labs/netlify-plugin-debug-cache). 45 | 46 | ## 📜 License 47 | 48 | This project is distributed under the [MIT license](LICENSE). 49 | --------------------------------------------------------------------------------