{"id":24904611,"url":"https://github.com/reiss-d/lazy-init","last_synced_at":"2026-01-30T08:11:53.941Z","repository":{"id":148982691,"uuid":"621076952","full_name":"reiss-d/lazy-init","owner":"reiss-d","description":"Lazily initialise values by deferring their creation until first use, resulting in better performance.","archived":false,"fork":false,"pushed_at":"2024-02-26T22:02:44.000Z","size":808,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-14T16:08:26.743Z","etag":null,"topics":["defer","hoist","initialize","lazy","nextjs","react","static","swc","swc-plugin","typescript"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/reiss-d.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-30T00:16:19.000Z","updated_at":"2024-08-30T23:56:10.000Z","dependencies_parsed_at":"2024-08-23T03:00:41.550Z","dependency_job_id":null,"html_url":"https://github.com/reiss-d/lazy-init","commit_stats":{"total_commits":105,"total_committers":1,"mean_commits":105.0,"dds":0.0,"last_synced_commit":"4bb617a8a6d33e1a914a1bd053d29d98acad7e2f"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/reiss-d/lazy-init","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reiss-d%2Flazy-init","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reiss-d%2Flazy-init/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reiss-d%2Flazy-init/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reiss-d%2Flazy-init/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reiss-d","download_url":"https://codeload.github.com/reiss-d/lazy-init/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reiss-d%2Flazy-init/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259843342,"owners_count":22920313,"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","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":["defer","hoist","initialize","lazy","nextjs","react","static","swc","swc-plugin","typescript"],"created_at":"2025-02-01T23:26:51.282Z","updated_at":"2026-01-30T08:11:48.919Z","avatar_url":"https://github.com/reiss-d.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lazy-init\n\nLazily initialize values by deferring their creation until first use, resulting in better performance.\n\n### Now also bringing block expressions to JavaScript/TypeScript.\n\n## Index\n\n\u003c!-- TODO: add Plugin Config section. --\u003e\n\n- [Overview](#overview)\n- [Installation](#installation)\n  - [Next.js](#nextjs)\n  - [SWC](#swc---swccore)\n  - [esbuild](#eslint)\n  - [tsup](#tsup)\n  - [eslint](#eslint)\n- [Basic Usage](#basic-usage)\n- [Methods](#methods)\n  - [block](#methods)\n  - [lz](#methods)\n  - [lazyFn](#methods)\n  - [lazyAsync](#methods)\n- [Caching](#caching)\n- [Freezing](#freezing)\n- [License](#license)\n\n\u003c!-- * [FAQ](#faq) --\u003e\n\u003c!-- * [Benchmarks](#benchmarks) --\u003e\n\n## Installation\n\nThis library **requires** your code is transpilied with any of the following:\n\n- [SWC](https://swc.rs) (includes [Next.js](https://nextjs.org/docs/advanced-features/compiler))\n- [esbuild](https://github.com/evanw/esbuild)\n- [tsup](https://github.com/egoist/tsup)\n\nIf you require a version of next/swc unsupported by the plugin and it is listed [here](https://swc.rs/docs/plugin/selecting-swc-core),\ncreate an issue requesting support.\n\n### Next.js\n\n| Version                 |           Plugin            |\n| :---------------------- | :-------------------------: |\n| `\u003e= v13.4.20-canary.32` | `@lazy-init/plugin-swc-v83` |\n| `\u003e= v13.4.10-canary.1`  | `@lazy-init/plugin-swc-v81` |\n\n\u003c!-- \u003e Next.js v13.2.4 ~ v13.3.1 cannot execute SWC Wasm plugins, [due to a bug](https://github.com/vercel/next.js/issues/46989#issuecomment-1486989081). --\u003e\n\n```bash\n# using npm\nnpm install lazy-init \u0026\u0026 npm install --save-dev @lazy-init/plugin-swc-{{version}}\n# using pnpm\npnpm add lazy-init \u0026\u0026 pnpm add -D @lazy-init/plugin-swc-{{version}}\n```\n\nAdd the following to your next config file:\n\n\u003e next.config.js\n\n```js\nmodule.exports = {\n   experimental: {\n      swcPlugins: [\n         // empty config object `{}` is required.\n         [require.resolve('@lazy-init/plugin-swc-{{version}}'), {}],\n      ],\n   },\n}\n```\n\n\u003e next.config.mjs (ESM)\n\n```js\nimport { createRequire } from 'node:module'\nconst require = createRequire(import.meta.url)\n\nexport default {\n   experimental: {\n      swcPlugins: [\n         // empty config object `{}` is required.\n         [require.resolve('@lazy-init/plugin-swc-{{version}}'), {}],\n      ],\n   },\n}\n```\n\n### SWC - @swc/core\n\n| Version     |          Supported          |\n| :---------- | :-------------------------: |\n| `\u003e= 1.3.81` | `@lazy-init/plugin-swc-v83` |\n| `\u003e= 1.3.68` | `@lazy-init/plugin-swc-v81` |\n\n```bash\n# using npm\nnpm install lazy-init \u0026\u0026 npm install --save-dev @lazy-init/plugin-swc-{{version}} \n# using pnpm\npnpm add lazy-init \u0026\u0026 pnpm add -D @lazy-init/plugin-swc-{{version}}\n```\n\nThe empty config object `{}` is required.\n\n```json\n// .swcrc\n{\n   \"jsc\": {\n      \"experimental\": {\n         \"plugins\": [\n            [\"@lazy-init/plugin-swc-{{version}}\", {}]\n         ]\n      }\n   }\n}\n```\n\n### esbuild\n\n\u003c!-- TODO: document bundle performance impact of esbuild/tsup plugin --\u003e\n\n| Version              |          Supported          |\n| :------------------- | :-------------------------: |\n| `0.18.x \\|\\| 0.19.x` | `@lazy-init/esbuild-plugin` |\n\n```bash\n# using npm\nnpm install lazy-init \u0026\u0026 npm install --save-dev @lazy-init/esbuild-plugin\n# using pnpm\npnpm add lazy-init \u0026\u0026 pnpm add -D @lazy-init/esbuild-plugin\n```\n\nThe `include` and `exclude` properties are glob arrays which follow the same\nbehaviour as [include](https://www.typescriptlang.org/tsconfig#include) and\n[exclude](https://www.typescriptlang.org/tsconfig#exclude) in Typescripts `tsconfig.json`.\n\nThese options are not required. However, providing either will improve performance.\n\nBy default, imports from `node_modules` will be skipped by this plugin unless\n`excludeNodeModules` is set to `false`.\n\n```js\n// your build file\nconst { lazyInitPlugin } = require('@lazy-init/esbuild-plugin')\nconst esbuild = require('esbuild')\n\nesbuild.build({\n   // ... other options\n   plugins: [\n      // If you are using plugins that transform paths, place them first.\n      lazyInitPlugin({\n         include: ['src'],\n         exclude: ['src/**/*.test.ts'],\n         excludeNodeModules: true, // default\n      }),\n   ],\n})\n```\n\n### tsup\n\ntsup uses esbuild internally, therefore everything documented in the\n[esbuild section](#esbuild) applies here. The only difference\nis a slight change in the configuration.\n\n| Version    |          Supported          |\n| :--------- | :-------------------------: |\n| `\u003e= 7.x.x` | `@lazy-init/esbuild-plugin` |\n\n\u003e Note: just copy the `include` and `exclude` arrays from your `tsconfig.json`.\n\n```ts\n// tsup.config.ts\nimport { lazyInitPlugin } from '@lazy-init/esbuild-plugin'\nimport { defineConfig } from 'tsup'\n\nexport default defineConfig({\n   // ... other options\n   esbuildPlugins: [\n      // If you are using plugins that transform paths, place them first.\n      lazyInitPlugin({\n         include: ['src'],\n         exclude: ['src/**/*.test.ts'],\n         excludeNodeModules: true, // default\n      }),\n   ],\n})\n```\n\n### eslint\n\nThis plugin is only necessary if you want to use the `lz.async` method while\nusing [@typescript-eslint](https://typescript-eslint.io/) with a configuration\nthat extends rules which [require type checking](https://typescript-eslint.io/getting-started/typed-linting).\n\nSee [`eslint-plugin-lazy-init`](https://github.com/reiss-d/lazy-init/blob/main/packages/eslint-plugin-lazy-init/README.md).\n\n## Basic Usage\n\nFor more in-depth examples, see the per method [documentation](#methods).\n\n```ts\nimport { lz, lzc } from 'lazy-init' // ESM\nconst { lz, lzc } = require('lazy-init') // Common JS\n\n// call `lz` for non-primitive values\nlz({ foo: 1 })\nlz([1, 2, 3])\nlz(new Map([['key', 'value']]))\n\n// call `lz.fn` for sync functions\nlz.fn(() =\u003e {})\n\n// call `lz.async` for async functions\nlz.async(async () =\u003e {})\n\n// call `lzc` to cache by default\nconst first = lzc({ a: 'foo' })\nconst second = lzc({ a: 'foo' })\n\nconsole.log(first === second) // true\n```\n\n## Methods\n\nClick the method to see its documentation:\n\n- [`block`](https://github.com/reiss-d/lazy-init/blob/main/packages/lazy-init/src/methods/block/README.md)\n- [`lz`](https://github.com/reiss-d/lazy-init/blob/main/packages/lazy-init/src/methods/obj/README.md)\n- [`lz.fn`](https://github.com/reiss-d/lazy-init/blob/main/packages/lazy-init/src/methods/fn/README.md)\n- [`lz.async`](https://github.com/reiss-d/lazy-init/blob/main/packages/lazy-init/src/methods/async/README.md)\n\n## Caching\n\nCaching results in only a single value ever being created for the given\nvalue structure. This can improve performance and reduce memory usage.\n\nCaching can be enabled by setting the `cache` property to `true` on a\noptions object or by using the `lzc` method where caching is enabled by\ndefault.\n\n```ts\n// using `lz`\nlz({}) // not cached\nlz({}, { cache: true }) // cached\n\n// using `lzc`\nlzc({}) // cached\nlzc({}, { cache: false }) // not cached\n```\n\nWhen caching is enabled, the value will also be frozen unless you explicitly\nsay otherwise. This is because caching an object that is not frozen is\ndangerous.\n\nThe object may mistakenly be mutated by the user, yet other\nrecipients of this cached object do not expect it to change.\n\n```ts\n// using `lz`\nlz({}) // N/A\nlz({}, { cache: true, freeze: false }) // cached\nlz({}, { cache: true }) // cached \u0026 frozen\n\n// using `lzc`\nlzc({}) // cached \u0026 frozen\nlzc({}, { freeze: false }) // cached\nlzc({}, { cache: false }) // N/A\n```\n\nReferentially comparing cached and non-cached values:\n\n```ts\n// `cfoo` and `cbar` share the same structure and are both\n// cached, therefore they are the same object.\nconst cfoo = lzc({ a: 1 })\nconst cbar = lzc({ a: 1 })\ncfoo === cbar // true\n```\n\n```ts\n// `cfoo` and `buzz` share the same structure, however, `buzz`\n//  is not cached, therefore they are different objects.\nconst buzz = lzc({ a: 1 }, { cache: false })\ncfoo === buzz // false\n```\n\n```ts\n// `cfoo` and `cdiff` are cached, however, they do not share the\n// same structure and are therefore different objects.\nconst cdiff = lzc({ a: 5 })\ncfoo === cdiff // false\n```\n\nThere are separate caches for frozen and non-frozen objects. Therefore,\nfrozen and non-frozen objects with the same structure will not be the same\nobject.\n\n```ts\nconst cfoo = lzc({ a: 1 })\nconst cbar = lzc({ a: 1 }, { freeze: false })\ncfoo === cbar // false\n```\n\n## Freezing\n\nBy default, freezing a value will perform a deep freeze on it.\n\nTo change this behaviour, set the environment variable `LAZY_INIT_FREEZE_MODE`\nto one of the following values:\n\n- `\"deep\"` (default)\n- `\"shallow\"`\n- `\"none\"`\n\n### Deep Freeze\n\nThe values of each key and symbol property will be recursively frozen.\nHowever, this only applies to arrays and plain objects. Other objects such\nas `Set` and `Map` will not be frozen.\n\n```ts\nconst foo = lz({\n   val: 'bar',\n   obj: { a: 0, b: [], c: new Set() },\n}, true)\nfoo.val = 'buzz' // error\nfoo.obj.a = 2 // error\nfoo.obj.b.push(1) // error\nfoo.obj.c.add(1) // ok\nfoo.obj.c = null // error\n```\n\n### Shallow Freeze\n\nOnly the value itself will be frozen, not any of its array/object properties.\n\n```ts\nconst foo = lz({\n   val: 'bar',\n   obj: { a: 0 },\n}, true)\nfoo.val = 'buzz' // error\nfoo.obj.a = 2 // ok\nfoo.obj = {} // error\n```\n\n### None\n\nThe value will not be frozen.\n\n## License\n\nThis repository is licensed under the MIT License found [here](./LICENSE).\nEach package/crate may contain a LICENSE file in its root which takes precedence\nand may include or depend on third-party code with its own licensing conditions.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freiss-d%2Flazy-init","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freiss-d%2Flazy-init","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freiss-d%2Flazy-init/lists"}