npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

recontainer

v1.0.0

Published

Simple dependency injection for TypeScript and JavaScript React web applications.

Downloads

25

Readme

gzip size

Can be used in any Node.js or browser applications. Built-in integration with React.

Why?

In most cases, ES6 modules are efficient way to share dependencies throughout application.

There are some situations though, where you need a single point of configuration to achieve better decoupling between multiple components. One of these cases is server-side rendering, in which you might want to change implementation that depends on browser APIs to something more suitable for a Node.js application.

Moreover, using global instances imported as ES6 module can lead to memory-leaks and bugs on server-side. Take for example a global instance of event publisher, to which application subscribes on each request. Since it is not disposed after each request, any failure to unsubscribe will cause a linear leak of memory.

server.jsx

import React from 'react';
import express from 'express';
import { renderToString } from 'react-dom/server';
import { createContainer } from 'recontainer';
import { createInject, ContainerProvider } from 'recontainer/lib/react';

class Greeting extends React.Component {
  render() {
    return (
      <h1>{this.props.greeting}</h1>
    )
  }
}

const inject = createInject();
const GreetingContainer = inject('greeting')(Greeting);

const greetingFactory = container => `Hello, ${container.get('name')}!`;
const app = express();

app.use((req, res, next) => {
  const container = createContainer({ // Container gets disposed after each request
    name: () => 'John',
    greeting: greetingFactory,
  });

  const html = renderToString(
    <ContainerProvider container={container}>
      <GreetingContainer /> {/* <h1>Hello, John!</h1> */}
    </ContainerProvider>
  );

  res.send(html);
});

app.listen(3000, () => {
  console.log(`Listening on port 3000.`);
});

Why not Redux?

Redux is great at distributing state throughout application and decoupling your React components. Although you could share almost any object via store, it is generally a good practice to keep the state serializable. Many redux-related libraries (eg. next-redux-wrapper) will not work if the state couldn't be serialized.

Functions and object instances (eg. Promise) are not serializable, thus we should keep them elsewhere.

Features

  • 100% Type-safe

    When used with TypeScript, recontainer protects you from type errors and allows you to extract the full potential of your editor's code completion features

  • Light-weight

    Total module size is 914 bytes gzipped

  • Simple

Examples

types.ts

export interface User {
  id: string;
  name: string;
}

container.ts

import { ContainerConfig } from 'recontainer';
import { createInject, createContainerHook } from 'recontainer/lib/react';
import { User } from './types';

export interface Dependencies {
  user: User;
  greeting: string;
  greetingProvider: (user: User) => string;
}

const user = {
  id: 'john-doe',
  name: 'John Doe',
};

export const config: ContainerConfig<Dependencies> = {
  user: () => user,
  greetingProvider: () => (user: User) => `Hello ${user.name}!`,
  greeting: container => {
    const greetingProvider = container.get('greetingProvider');
    const user = container.get('user');

    return greetingProvider(user);
  },
};

export const useContainer = createContainerHook<Dependencies>();
export const inject = createInject<Dependencies>();

Greeter.tsx

import * as React from 'react';
import { useContainer } from './container';

const Greeter: React.FunctionComponent = () => {
  const { greeting, user } = useContainer('greeting', 'user');
  
  return (
    <div>
      <h1>{greeting}</h1>
      ID: {user.id}
    </div>
  );
}

// OR
const Greeter: React.FunctionComponent = () => {
  // Note that useContainer returns container instance when called without arguments
  const container = useContainer();
  
  return (
    <div>
      <h1>{container.get('greeting')}</h1>
      ID: {container.get('user').id}
    </div>
  );
}

export default Greeter;
import * as React from 'react';
import { inject } from './container';

interface GreeterProps {
  greeting: string;
  user: User;
}

const Greeter: React.FunctionComponent<GreeterProps> = ({
  user,
  greeting,
}) => (
  <div>
    <h1>{greeting}</h1>
    ID: {user.id}
  </div>
);

export default inject('greeting', 'user')(Greeter);
import * as React from 'react';
import { withContainer, ContainerProps } from 'recontainer/lib/react';
import { Dependencies } from './container';

interface GreeterProps extends ContainerProps<Dependencies> {
  
}

const Greeter: React.FunctionComponent<GreeterProps> = ({
  container
}) => (
  <div>
    <h1>{container.get('greeting')}</h1>
    ID: {container.get('user').id}
  </div>
);

export default withContainer(Greeter);

App.tsx

import * as React from 'react';
import { createContainer } from 'recontainer';
import { ContainerProvider } from 'recontainer/lib/react';
import { config } from './container';
import Greeter from './Greeter';

const container = createContainer(config);

export const App: React.FunctionComponent = () => (
  <ContainerProvider container={container}>
    <Greeter />
    {/* 
        <div>
          <h1>Hello John Doe!</h1>
          ID: john-doe
        </div>
    */}
  </ContainerProvider>
);

container.js

import { createInject, createContainerHook } from 'recontainer/lib/react';

const user = {
  id: 'john-doe',
  name: 'John Doe',
};

export const config = {
  user: () => user,
  greetingProvider: () => user => `Hello ${user.name}!`,
  greeting: container => {
    const greetingProvider = container.get('greetingProvider');
    const user = container.get('user');

    return greetingProvider(user);
  },
};

export const useContainer = createContainerHook();
export const inject = createInject();

Greeter.jsx

import React from 'react';
import { useContainer } from './container';

const Greeter = () => {
  const { greeting, user } = useContainer('greeting', 'user');

  return (
    <div>
      <h1>{greeting}</h1>
      ID: {user.id}
    </div>
  );
}

export default Greeter;
import React from 'react';
import { inject } from './container';

const Greeter = ({
  user,
  greeting,
}) => (
  <div>
    <h1>{greeting}</h1>
    ID: {user.id}
  </div>
);

export default inject('greeting', 'user')(Greeter);
import React from 'react';
import { withContainer } from 'recontainer';

const Greeter = ({
  container
}) => (
  <div>
    <h1>{container.get('greeting')}</h1>
    ID: {container.get('user').id}
  </div>
);

export default withContainer(Greeter);

App.jsx

import React from 'react';
import { createContainer, ContainerProvider } from 'recontainer';
import { config } from './container';
import Greeter from './Greeter';

const container = createContainer(config);

export const App = () => (
  <ContainerProvider container={container}>
    <Greeter />
    {/* 
        <div>
          <h1>Hello John Doe!</h1>
          ID: john-doe
        </div>
    */}
  </ContainerProvider>
);

Installation

With yarn

$ yarn add recontainer

With npm

$ npm install recontainer

Please note that types are included, thus there is no need to install @types/recontainer package

Requirements

Docs

Container methods

get
 const container = createContainer({
   logger: () => message => console.log(message),
 });

 const log = container.get('logger');

 log('Hello World!'); // Console output: Hello World!
getAll
 const container = createContainer({
   logger: () => message => console.log(message),
   message: () => 'Foo bar',
 });

 const { logger, message } = container.getAll();

 logger(message); // Console output: Foo bar