Lazily initialize values by deferring their creation until first use, resulting in better performance.
This library requires your code is transpilied with any of the following:
If you require a version of next/swc unsupported by the plugin and it is listed here, create an issue requesting support.
Version | Plugin |
---|---|
>= v13.4.20-canary.32 |
@lazy-init/plugin-swc-v83 |
>= v13.4.10-canary.1 |
@lazy-init/plugin-swc-v81 |
# using npm
npm install lazy-init && npm install --save-dev @lazy-init/plugin-swc-{{version}}
# using pnpm
pnpm add lazy-init && pnpm add -D @lazy-init/plugin-swc-{{version}}
Add the following to your next config file:
next.config.js
module.exports = {
experimental: {
swcPlugins: [
// empty config object `{}` is required.
[require.resolve('@lazy-init/plugin-swc-{{version}}'), {}],
],
},
}
next.config.mjs (ESM)
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
export default {
experimental: {
swcPlugins: [
// empty config object `{}` is required.
[require.resolve('@lazy-init/plugin-swc-{{version}}'), {}],
],
},
}
Version | Supported |
---|---|
>= 1.3.81 |
@lazy-init/plugin-swc-v83 |
>= 1.3.68 |
@lazy-init/plugin-swc-v81 |
# using npm
npm install lazy-init && npm install --save-dev @lazy-init/plugin-swc-{{version}}
# using pnpm
pnpm add lazy-init && pnpm add -D @lazy-init/plugin-swc-{{version}}
The empty config object {}
is required.
// .swcrc
{
"jsc": {
"experimental": {
"plugins": [
["@lazy-init/plugin-swc-{{version}}", {}]
]
}
}
}
Version | Supported |
---|---|
0.18.x || 0.19.x |
@lazy-init/esbuild-plugin |
# using npm
npm install lazy-init && npm install --save-dev @lazy-init/esbuild-plugin
# using pnpm
pnpm add lazy-init && pnpm add -D @lazy-init/esbuild-plugin
The include
and exclude
properties are glob arrays which follow the same
behaviour as include and
exclude in Typescripts tsconfig.json
.
These options are not required. However, providing either will improve performance.
By default, imports from node_modules
will be skipped by this plugin unless
excludeNodeModules
is set to false
.
// your build file
const { lazyInitPlugin } = require('@lazy-init/esbuild-plugin')
const esbuild = require('esbuild')
esbuild.build({
// ... other options
plugins: [
// If you are using plugins that transform paths, place them first.
lazyInitPlugin({
include: ['src'],
exclude: ['src/**/*.test.ts'],
excludeNodeModules: true, // default
}),
],
})
tsup uses esbuild internally, therefore everything documented in the esbuild section applies here. The only difference is a slight change in the configuration.
Version | Supported |
---|---|
>= 7.x.x |
@lazy-init/esbuild-plugin |
Note: just copy the
include
andexclude
arrays from yourtsconfig.json
.
// tsup.config.ts
import { lazyInitPlugin } from '@lazy-init/esbuild-plugin'
import { defineConfig } from 'tsup'
export default defineConfig({
// ... other options
esbuildPlugins: [
// If you are using plugins that transform paths, place them first.
lazyInitPlugin({
include: ['src'],
exclude: ['src/**/*.test.ts'],
excludeNodeModules: true, // default
}),
],
})
This plugin is only necessary if you want to use the lz.async
method while
using @typescript-eslint with a configuration
that extends rules which require type checking.
For more in-depth examples, see the per method documentation.
import { lz, lzc } from 'lazy-init' // ESM
const { lz, lzc } = require('lazy-init') // Common JS
// call `lz` for non-primitive values
lz({ foo: 1 })
lz([1, 2, 3])
lz(new Map([['key', 'value']]))
// call `lz.fn` for sync functions
lz.fn(() => {})
// call `lz.async` for async functions
lz.async(async () => {})
// call `lzc` to cache by default
const first = lzc({ a: 'foo' })
const second = lzc({ a: 'foo' })
console.log(first === second) // true
Click the method to see its documentation:
Caching results in only a single value ever being created for the given value structure. This can improve performance and reduce memory usage.
Caching can be enabled by setting the cache
property to true
on a
options object or by using the lzc
method where caching is enabled by
default.
// using `lz`
lz({}) // not cached
lz({}, { cache: true }) // cached
// using `lzc`
lzc({}) // cached
lzc({}, { cache: false }) // not cached
When caching is enabled, the value will also be frozen unless you explicitly say otherwise. This is because caching an object that is not frozen is dangerous.
The object may mistakenly be mutated by the user, yet other recipients of this cached object do not expect it to change.
// using `lz`
lz({}) // N/A
lz({}, { cache: true, freeze: false }) // cached
lz({}, { cache: true }) // cached & frozen
// using `lzc`
lzc({}) // cached & frozen
lzc({}, { freeze: false }) // cached
lzc({}, { cache: false }) // N/A
Referentially comparing cached and non-cached values:
// `cfoo` and `cbar` share the same structure and are both
// cached, therefore they are the same object.
const cfoo = lzc({ a: 1 })
const cbar = lzc({ a: 1 })
cfoo === cbar // true
// `cfoo` and `buzz` share the same structure, however, `buzz`
// is not cached, therefore they are different objects.
const buzz = lzc({ a: 1 }, { cache: false })
cfoo === buzz // false
// `cfoo` and `cdiff` are cached, however, they do not share the
// same structure and are therefore different objects.
const cdiff = lzc({ a: 5 })
cfoo === cdiff // false
There are separate caches for frozen and non-frozen objects. Therefore, frozen and non-frozen objects with the same structure will not be the same object.
const cfoo = lzc({ a: 1 })
const cbar = lzc({ a: 1 }, { freeze: false })
cfoo === cbar // false
By default, freezing a value will perform a deep freeze on it.
To change this behaviour, set the environment variable LAZY_INIT_FREEZE_MODE
to one of the following values:
"deep"
(default)"shallow"
"none"
The values of each key and symbol property will be recursively frozen.
However, this only applies to arrays and plain objects. Other objects such
as Set
and Map
will not be frozen.
const foo = lz({
val: 'bar',
obj: { a: 0, b: [], c: new Set() },
}, true)
foo.val = 'buzz' // error
foo.obj.a = 2 // error
foo.obj.b.push(1) // error
foo.obj.c.add(1) // ok
foo.obj.c = null // error
Only the value itself will be frozen, not any of its array/object properties.
const foo = lz({
val: 'bar',
obj: { a: 0 },
}, true)
foo.val = 'buzz' // error
foo.obj.a = 2 // ok
foo.obj = {} // error
The value will not be frozen.
This repository is licensed under the MIT License found here. Each package/crate may contain a LICENSE file in its root which takes precedence and may include or depend on third-party code with its own licensing conditions.