Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

unctx

Package Overview
Dependencies
Maintainers
2
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

unctx - npm Package Compare versions

Comparing version 1.0.2 to 1.1.0

dist/index.cjs

6

dist/index.d.ts

@@ -6,2 +6,3 @@ interface UseContext<T> {

call: <R>(instance: T, cb: () => R) => R;
callAsync: <R>(instance: T, cb: () => R | Promise<R>) => Promise<R>;
}

@@ -18,3 +19,6 @@ declare function createContext<T = any>(): UseContext<T>;

declare const useContext: <T>(key: string) => () => T;
declare type AsyncFn<T> = () => Promise<T>;
declare function executeAsync<T>(fn: AsyncFn<T>): [Promise<T>, () => void];
declare function withAsyncContext<T = any>(fn: AsyncFn<T>, transformed?: boolean): AsyncFn<T>;
export { ContextNamespace, UseContext, createContext, createNamespace, defaultNamespace, getContext, useContext };
export { ContextNamespace, UseContext, createContext, createNamespace, defaultNamespace, executeAsync, getContext, useContext, withAsyncContext };

52

package.json
{
"name": "unctx",
"version": "1.0.2",
"version": "1.1.0",
"description": "Composition-api in Vanilla js",

@@ -10,7 +10,18 @@ "repository": "unjs/unctx",

".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs"
"require": "./dist/index.cjs",
"import": "./dist/index.mjs",
"types": "./dist/index.d.ts"
},
"./transform": {
"require": "./dist/transform.cjs",
"import": "./dist/transform.mjs",
"types": "./dist/transform.d.ts"
},
"./plugin": {
"require": "./dist/plugin.cjs",
"import": "./dist/plugin.mjs",
"types": "./dist/plugin.d.ts"
}
},
"main": "./dist/index.js",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",

@@ -21,9 +32,7 @@ "types": "./dist/index.d.ts",

],
"scripts": {
"build": "siroc build",
"dev": "jest --watch",
"lint": "eslint --ext .ts,.js .",
"prepublishOnly": "yarn build",
"release": "yarn test && standard-version && git push --follow-tags && npm publish",
"test": "yarn lint && yarn jest"
"dependencies": {
"acorn": "^8.7.0",
"estree-walker": "^2.0.2",
"magic-string": "^0.26.1",
"unplugin": "^0.5.2"
},

@@ -34,9 +43,18 @@ "devDependencies": {

"@types/node": "latest",
"c8": "latest",
"eslint": "latest",
"jest": "latest",
"siroc": "latest",
"standard-version": "latest",
"ts-jest": "latest",
"typescript": "latest"
}
}
"typescript": "latest",
"unbuild": "latest",
"vitest": "latest"
},
"packageManager": "pnpm@6.32.3",
"scripts": {
"build": "unbuild",
"dev": "vitest",
"lint": "eslint --ext .ts,.js .",
"release": "pnpm test && standard-version && git push --follow-tags && pnpm publish",
"test": "pnpm lint && vitest run --coverage"
},
"readme": "# 🍦 unctx\n\n> Composition-api in Vanilla js\n\n[![npm version][npm-v-src]][npm-v-href]\n[![npm downloads][npm-dm-src]][npm-dm-href]\n[![package phobia][packagephobia-src]][packagephobia-href]\n[![bundle phobia][bundlephobia-src]][bundlephobia-href]\n[![codecov][codecov-src]][codecov-href]\n\n## What is it?\n\n[Vue.js](https://vuejs.org) introduced an amazing pattern called [Composition API](https://v3.vuejs.org/guide/composition-api-introduction.html) that allows organizing complex logic by splitting it into reusable functions and grouping in logical order. `unctx` allows easily implementing composition api pattern in your javascript libraries without hassle.\n\n## Integration\n\nIn your **awesome** library:\n\n```bash\nyarn add unctx\n# or\nnpm install unctx\n```\n\n```js\nimport { createContext } from 'unctx'\n\nconst ctx = createContext()\n\nexport const useAwesome = ctx.use\n\n// ...\nctx.call({ test: 1 }, () => {\n // This is similar to vue setup function\n // Any function called here, can use `useAwesome` to get { test: 1 }\n})\n```\n\nUser code:\n\n```js\nimport { useAwesome } from 'awesome-lib'\n\n// ...\nfunction setup() {\n const ctx = useAwesome()\n}\n```\n\n## Using Namespaces\n\nTo avoid issues with multiple version of library, `unctx` provides a safe global namespace to access context by key (kept in [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)). **Important:** Please use a verbose name for key to avoid conflict with other js libraries. Using npm package name is recommended. Using symbols has no effect since it still causes multiple context issue.\n\n```js\nimport { useContext, getContext } from 'unctx'\n\nconst useAwesome = useContext('awesome-lib')\n\n// or\n// const awesomeContext = getContext('awesome-lib')\n```\n\nYou can also create your own internal namespace with `createNamespace` utility for more advanced use cases.\n\n## Singleton Pattern\n\nIf you are sure it is safe to use a shared instance (not depending to request), you can also use `ctx.set` and `ctx.unset` for a [singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern).\n\n**Note:** You cannot combine `set` with `call`. Always use `unset` before replacing instance otherwise you will get `Context conflict` error.\n\n```js\nimport { createContext } from 'unctx'\n\nconst ctx = createContext()\nctx.set(new Awesome())\n\n// Replacing instance without unset\n// ctx.set(new Awesome(), true)\n\nexport const useAwesome = ctx.use\n```\n\n## Typescript\n\nA generic type exists on all utilities to be set for instance/context type:\n\n```ts\n// Return type of useAwesome is Awesome | null\nconst { use: useAwesome } = createContext<Awesome>()\n```\n\n## Async Context\n\nNormally, using context is only possible before first await statement:\n\n```js\nasync function setup() {\n console.log(useAwesome()) // Returns context\n await new Promise(resolve => setTimeout(resolve, 1000))\n console.log(useAwesome()) // Returns null\n}\n```\n\nA simple workaround, is caching context before first await and use it directly:\n\n```js\nasync function setup() {\n const ctx = useAwesome()\n await new Promise(resolve => setTimeout(resolve, 1000))\n console.log(ctx) // We can directly access cached version of ctx\n}\n```\n\nHowever, this is not always as easy as making a variable when using nested composables.\n\nUnctx provides a better solution that transforms async to automatically restore context after each await call. This requires using a bundler such as Rollup, Vite or Webpack.\n\nImport and register transform plugin:\n\n```js\nimport { unctxPlugin } from 'unctx/plugin'\n\n// Rollup\n// TODO: Add to rollup configuration\nunctxPlugin.rollup()\n\n// Vite\n// TODO: Add to vite configuration\nunctxPlugin.vite()\n\n// Webpack\n// TODO: Add to webpack configuration\nunctxPlugin.webpack()\n```\n\nUse `ctx.callAsync` instead of `ctx.call`:\n\n```js\nawait ctx.callAsync('test', setup)\n```\n\nAny async function that requires context, should be wrapped with `withAsyncContext`:\n\n```js\nimport { withAsyncContext } from 'unctx'\n\nconst setup = withAsyncContext(async () => {\n console.log(useAwesome()) // Returns context\n await new Promise(resolve => setTimeout(resolve, 1000))\n console.log(useAwesome()) // Still returns context with dark magic!\n})\n```\n\n## Under the hood\n\nComposition of functions is possible using temporary context injection. When calling `ctx.call(instance, cb)`, `instance` argument will be stored in a temporary variable then `cb` is called. Any function inside `cb`, can then implicitly access instance by using `ctx.use` (or `useAwesome`)\n\n## Pitfalls\n\n**context can be only used before first await**:\n\nPlease check Async context section.\n\n**`Context conflict` error**:\n\nIn your library, you should only keep one `call()` running at a time (unless calling with same reference for first argument)\n\nFor instance this makes an error:\n\n```js\nctx.call({ test: 1 }, () => {\n ctx.call({ test: 2 }, () => {\n // Throws error!\n })\n})\n```\n\n## License\n\nMIT. Made with 💖\n\n<!-- Refs -->\n[npm-v-src]: https://flat.badgen.net/npm/v/unctx/latest\n[npm-v-href]: https://npmjs.com/package/unctx\n\n[npm-dm-src]: https://flat.badgen.net/npm/dm/unctx\n[npm-dm-href]: https://npmjs.com/package/unctx\n\n[packagephobia-src]: https://flat.badgen.net/packagephobia/install/unctx\n[packagephobia-href]: https://packagephobia.now.sh/result?p=unctx\n\n[bundlephobia-src]: https://flat.badgen.net/bundlephobia/min/unctx\n[bundlephobia-href]: https://bundlephobia.com/result?p=unctx\n\n[codecov-src]: https://flat.badgen.net/codecov/c/github/unjs/unctx/master\n[codecov-href]: https://codecov.io/gh/unjs/unctx\n"
}

@@ -92,2 +92,64 @@ # 🍦 unctx

## Async Context
Normally, using context is only possible before first await statement:
```js
async function setup() {
console.log(useAwesome()) // Returns context
await new Promise(resolve => setTimeout(resolve, 1000))
console.log(useAwesome()) // Returns null
}
```
A simple workaround, is caching context before first await and use it directly:
```js
async function setup() {
const ctx = useAwesome()
await new Promise(resolve => setTimeout(resolve, 1000))
console.log(ctx) // We can directly access cached version of ctx
}
```
However, this is not always as easy as making a variable when using nested composables.
Unctx provides a better solution that transforms async to automatically restore context after each await call. This requires using a bundler such as Rollup, Vite or Webpack.
Import and register transform plugin:
```js
import { unctxPlugin } from 'unctx/plugin'
// Rollup
// TODO: Add to rollup configuration
unctxPlugin.rollup()
// Vite
// TODO: Add to vite configuration
unctxPlugin.vite()
// Webpack
// TODO: Add to webpack configuration
unctxPlugin.webpack()
```
Use `ctx.callAsync` instead of `ctx.call`:
```js
await ctx.callAsync('test', setup)
```
Any async function that requires context, should be wrapped with `withAsyncContext`:
```js
import { withAsyncContext } from 'unctx'
const setup = withAsyncContext(async () => {
console.log(useAwesome()) // Returns context
await new Promise(resolve => setTimeout(resolve, 1000))
console.log(useAwesome()) // Still returns context with dark magic!
})
```
## Under the hood

@@ -101,12 +163,4 @@

To avoid leaking context, `call` method synchronously sets context and unset it as soon as possible. Because of this, `useAwesome` should happen before first `await` call and reused if necessary.
Please check Async context section.
```js
async function setup() {
const awesome = useAwesome()
await someFunction()
// useAwesome() returns null here
}
```
**`Context conflict` error**:

@@ -113,0 +167,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc