Code Monkey home page Code Monkey logo

hapi-react-views's Introduction

hapi-react-views

A hapi view engine for React components.

Build Status Dependency Status Peer Dependency Status Dev Dependency Status

By default rendering is done using ReactDOMServer.renderToStaticMarkup. You can also choose to use ReactDOMServer.renderToString, preserving the data-react-id attributes so re-mounting client side is possible.

Install

$ npm install hapi-react-views

Note: Your project should have it's own react and react-dom dependencies installed. We depend on these via peerDependencies.

Usage

Configuring the server manually:

const Hapi = require('@hapi/hapi');
const HapiReactViews = require('hapi-react-views');
const Vision = require('@hapi/vision');

require('@babel/register')({
    presets: ['@babel/preset-react', '@babel/preset-env']
});

const main = async function () {
    const server = Hapi.Server();

    await server.register(Vision);

    server.views({
        engines: {
            jsx: HapiReactViews
        },
        compileOptions: {}, // optional
        relativeTo: __dirname,
        path: 'views'
    });

    await server.start();

    console.log(`Server is listening at ${server.info.uri}`);
};

main();

Note: As of hapi-react-views v4.x your project must register a transpiler such as babel. An alternative to this is to transpile ahead of time and save the result to file.

Note: As of hapi v9.x, your project must register the vision plugin in order for the server.views() and server.render() methods to be available.

API

server.views(options)

Please refer to the vision docs on server.views(options) for complete details.

We'll be focusing on the compileOptions property that you can include when passing options to server.views.

The following compileOptions will customize how hapi-react-views works.

  • compileOptions - options object passed to the engine's compile function. Defaults to {}.
    • doctype - a simple string prepended to the response. Defaults to <!DOCTYPE html>
    • renderMethod - the method to invoke on ReactDOMServer to generate our output. Available options are renderToStaticMarkup and renderToString. Defaults to renderToStaticMarkup.
    • removeCache - since transpilers tend to take a while to startup, we can remove templates from the require cache so we don't need to restart the server to see changes. Defaults to 'production' !== process.env.NODE_ENV.
    • removeCacheRegExp - a RegExp pattern string, matching modules in require cache will be removed. Defaults to undefined.
    • layout - the name of the layout file to use.
    • layoutPath - the directory path of where layouts are stored.
    • layoutRenderMethod - same as renderMethod but used for layouts. Defaults to renderToStaticMarkup.

You can override all these compileOptions at runtime.

const context = { name: 'Steve' };
const renderOpts = {
    runtimeOptions: {
        doctype: '<!DOCTYPE html>',
        renderMethod: 'renderToString'
    }
};

const output = await server.render('template', context, renderOpts);

Please refer to vision's docs on server.render(template, context, [options], callback) for complete details.

Examples

Before you can run the examples, you need to clone this repo and install the dependencies.

$ git clone https://github.com/jedireza/hapi-react-views.git
$ cd hapi-react-views
$ npm install

Rendering a simple page

This example renders a component as HTML output. View the code.

$ npm run simple-example

Rendering with layouts

Wrapper style layouts

This example renders components as HTML adding the idea of using wrapper layouts. The wrapping is handled by this module, so it may feel like a bit of magic since there is no direct dependency to the layout in your component views. View the code.

$ npm run layout-example

Component style layouts

This example renders components as HTML but adds the idea of using component layouts. The component layout is a direct dependency of your view components with no magic handling by this module. View the code.

$ npm run layout-component-example

Remounting on the client (universal/isomorphic)

This example demonstrates the idea of rendering the full page on the server and remounting the app view on the client side as a way to to create universal (aka isomorphic) applications.

It uses the wrapper layout feature, making it easy for the layout to be rendered without data-react-id attributes and the app view to be rendered with them. View the code.

$ npm run remount-example

License

MIT

Don't forget

What you create with hapi-react-views is more important than hapi-react-views.

hapi-react-views's People

Contributors

byoigres avatar fullstackforger avatar jedireza avatar nallenscott avatar robbyoconnor avatar stephencranedesign avatar tanepiper avatar tribou avatar yuenesc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hapi-react-views's Issues

Error: Invariant Violation: Element type is invalid

If I try to convert your layout example to use ES6 classes, I'm getting an error. However, I am able to convert the home.jsx.

For example, changing only the home.jsx works with:

const React = require('react');
const Layout = require('./layout.jsx');

export default class Component extends React.Component {
    render() {

        return (
            <Layout title="Home Page">
                <h1>Welcome to the plot device.</h1>
            </Layout>
        );
    }
}

However, when I convert the layout.jsx file as well like this:

const React = require('react');

export default class Component extends React.Component {
    render() {

        return (
            <html>
                <head>
                    <title>{this.props.title}</title>
                </head>
                <body>
                    {this.props.children}
                    <hr />
                    <p>
                        <a href="/">Home</a> | <a href="/about">About Us</a>
                    </p>
                </body>
            </html>
        );
    }
}

I get this error:

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `Component`.
Debug: internal, implementation, error
    Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `Component`.: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `Component`.
    at invariant (/Users/user/dev/hapi-react-views/node_modules/fbjs/lib/invariant.js:39:15)
    at [object Object].instantiateReactComponent [as _instantiateReactComponent] (/Users/user/dev/hapi-react-views/node_modules/react/lib/instantiateReactComponent.js:64:134)
    at [object Object].ReactCompositeComponentMixin.mountComponent (/Users/user/dev/hapi-react-views/node_modules/react/lib/ReactCompositeComponent.js:223:36)
    at [object Object].wrapper [as mountComponent] (/Users/user/dev/hapi-react-views/node_modules/react/lib/ReactPerf.js:66:21)
    at /Users/user/dev/hapi-react-views/node_modules/react/lib/ReactServerRendering.js:70:32
    at ReactServerRenderingTransaction.Mixin.perform (/Users/user/dev/hapi-react-views/node_modules/react/lib/Transaction.js:136:20)
    at Object.renderToStaticMarkup (/Users/user/dev/hapi-react-views/node_modules/react/lib/ReactServerRendering.js:68:24)
    at runtime (/Users/user/dev/hapi-react-views/index.js:31:58)
    at Object.renderer (/Users/user/dev/hapi-react-views/node_modules/vision/lib/manager.js:141:36)
    at [object Object].internals.Manager._loadPartials.internals.Manager._loadHelpers.internals.Manager.render.internals.Manager._prepare.internals.Manager._prepareEngine.internals.Manager._prepareTemplates.callback._path.internals.Manager._path.internals.Manager._render.compiled.template [as _render] (/Users/user/dev/hapi-react-views/node_modules/vision/lib/manager.js:468:14)

Am I implementing this correctly?

Coverage is suppressed when loading `babel-register`

I recently opened an issue on Lab that doesn't seem to really have anything to do with it. Since I encountered this while working with hapi-react-views, I thought I'd throw this here too, just in case.

Looks like Lab doesn't also report coverage errors if I comment out any fixtures in hapi-react-views itself. It begins to care about coverage only if I comment out the require('babel-register') (of course in addition to other test failures).

In my own test project I've tried requiring babel-register inside of a dummy plugin, and then registering it at the end after all the other plugins:

// babel-registrar.js

require('babel-register')({
    presets: ['react', 'es2015']
});


exports.register = function (server, options, next) {

    next();
};


exports.register.attributes = {
    name: 'babel-registrar'
};
// manifest.js

...
plugins: {
    'vision': {},
    'visionary': {...},
    ...,
    './babel-registrar': {}
}
...

This somehow defers whatever's causing this issue and makes Lab start reporting coverage again. Would you know what may be the problem and if there's a better way to fix this?

Layout feature proposal

(full disclosure, I'm writing this fork atm, would love to be able to issue a PR later to add it into the main stream)

My use case: I want the entire document tree (HTML, Head, etc) rendered by React on the server (controlled by a Store, etc) but this is problematic on the Client if you want to have the ability to embed third party scripts, analytics, etc. So you need to have the client render the core of your app somewhere in the Body.

If you render into a component other than HTML (when you're controlling the whole document on the server) then checksums will fail (assuming renderToStaticMarkup) because the reactroot is different when you render on the client - and if you don't use checksums then you're blitzing the node content which defeats some of the performance gains from having an Isomorphic app.

IDEALLY I'd have the ability to have a wrapper for whatever view I pass. This wrapper would always be use rendertoString and the wrapped component would use whatever was set in options (in my case renderToStaticMarkup). This is probably best handled in the options as a config.

Handling it in the options allows overriding it in the reply interface as well - which is very helpful.

an example:

reply.view("myAppComponent", componentPropsObj, {wrapper: myHTMLComponent, wrapperProps: wrapperPropsObj})

Thoughts on if this would be a desired optional feature? It certainly is extremely useful for fully controlled apps.

Possibility to use .js extension for views

Wondering if it's already possible, or if not if it could be made possible to use .js for view extensions.
I prefer to transpile my code and babel renames the .jsx to .js in the output directory. I run my server from the dist transpiled directory.

I'm working around it currently with a separate gulp task that uses gulp-extname to force a .jsx extension in the output directory, but it'd be much cleaner if I could just use .js to begin with and have server.render find the .js view.

Thanks for the great project by the way!

view helpers

Is is possible to use view helpers in the react views? For instance, I'm trying to use hapi-named-routes [1]
in the views to generate urls correctly. If not, what's the best practice for utilising useful methods (mixins?) in react views that require server context.

[1] https://github.com/poeticninja/hapi-named-routes

Isomorphic Hot Reload Question

Sorry to bother again, but is there any support for hot module reloading of serve side components? Not sure if this would be done through hapi-react-views but my client side code is reloading but not the server. Also adding nodemon seems to create a lot of extra emissions versus running the server with just node. Haven't found any info on this anywhere but if it's possible having an example here would be very helpful.

Update dependencies

Please update this to only use hapi dependencies from the new @hapi/ scoped modules. This will help me keep it used in vision tests. Let me know if you need help.

Babel-register on production

Hi..
Just a question: Is it safe to use babel-register ( mandatory for the JSX View ) in production? I'm currently using your package in a small app but after doing some tweaks I've stumbled into this.

Any thoughts?

Thanks

Internal implementation error

I am in the process of updating a project from react 13 to 14 and hapi 11 along with updating to all the latest node modules in the project (based on dependencies). I've been able to sort out all the issues but am stuck on this one as it says it is an internal error. It seems to point to issue with rendering views by hapi-react-views but there is not enough info in the debug for me to figure it out. It appears to be an issue with an unexpected token <: but the project uses babel loader on all the jsx files. I have tried using the useNodeJsx:false in the manifest and that had no effect.

Is there some sort of compatibility issue with hapi-react-views and vision?

Here is the debug output. Any insight is appreciated.

Debug: internal, implementation, error
    SyntaxError: Unexpected token <: Unexpected token <
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:414:25)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Module.require (module.js:366:17)
    at require (module.js:385:17)
    at runtime (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi-react-views\index.js:24:25)
    at Object.renderer (C:\Data\captchatheprize.com\dev\gamewww\node_modules\vision\lib\manager.js:143:36)
    at internals.Manager._loadPartials.internals.Manager._loadHelpers.internals.Manager.render.internals.Manager._prepare.internals.Manager._prepareEngine.internals.Manager._prepareTemplates.callback._path.internals.Manager._path.internals.Manager._render.compiled.template [as _render] (C:\Data\captchatheprize.com\dev\gamewww\node_modules\vision\lib\manager.js:470:14)
    at Object.internals.Manager._loadPartials.internals.Manager._loadHelpers.internals.Manager.render.internals.Manager._prepare.internals.Manager._prepareEngine.internals.Manager._prepareTemplates.callback._path.internals.Manager._path.internals.Manager._render.internals.Manager._compile.internals.marshal.callback [as marshal] (C:\Data\captchatheprize.com\dev\gamewww\node_modules\vision\lib\manager.js:564:13)
    at internals.Response._prepare.internals.Response._processPrepare.internals.Response._marshal.next [as _marshal] (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\response.js:464:22)
    at C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\transmit.js:124:18
    at C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\transmit.js:508:20
    at done (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\node_modules\items\lib\index.js:63:25)
    at autoValue (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\transmit.js:479:20)
    at Object.exports.parallel (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\node_modules\items\lib\index.js:70:13)
    at Object.exports.send.internals.marshal.internals.fail.internals.transmit.internals.state.Items.parallel [as state] (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\transmit.js:501:11)
    at Object.exports.send.internals.marshal.internals.state [as marshal] (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\transmit.js:98:15)
    at Object.exports.send.callback [as send] (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\transmit.js:30:15)
    at transmit (C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\request.js:439:18)
    at C:\Data\captchatheprize.com\dev\gamewww\node_modules\hapi\lib\protect.js:52:16

Layout feature requires JSX file extension

Just found this bug in the Layout feature.

const layoutPath = Path.join(renderOpts.layoutPath, renderOpts.layout + '.jsx');

That hardcodes .jsx which... is less than optimal. Thoughts as to a workaround? (not all projects use .jsx as the extension - in fact none of the ones I've worked on - closed or open - do).

Originally I had that variable as a full filename - so without the string concatenation. Thoughts?

usage with react-router?

I was able to get the example view.jsx file to show by putting this in my handler.

reply.view(view, { title : 'test' })

but here is whats confusing. view.jsx doesn't have the usual React.render ( "< Component />", 'div');

Is there a working example with react router?


Router.run(routes, function (Handler) {  
  React.render(<Handler/>, document.body);
});

React: onClick does not work

I cannot use onClick within a view. Maybe I am doing it wrong.

Code to reproduce

var React = require('react')

class Hello extends React.Component {

  handleClick() {
    console.log("click")
  }
  render() {
    return (
      <button onClick={this.handleClick}>Hello</button>
    )
  }
}

module.exports = Hello

hapi: 13.3
hapi-react-views: 7.0
react: 15.0.2

Support removeCache option for any file extension

Currently, removeCache is only supported by .jsx extensions as stated in the README. However, I think I found an easy way to remove the current view and layout no matter what the extension. Let me know if I'm misunderstanding why you're removing all .jsx modules from cache.

Git Clone Link not working

Just wanted to let you know.

git clone [email protected]:jedireza/hapi-react-views.git

In the Example section of the README gives a permissions error. I had to clone it by using the clone/download green button instead.

Tiny issue, but thought you would like to know.

React Events?

I was trying to add forms and events (onSubmit, onChange, onClick) to a template. It seems those do not get attached to the rendered html output?

`
import React from 'react'

class Component extends React.Component {
constructor() {
super()
this.state = {clicked: false}
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({clicked: !this.state.clicked})
}
render() {
return (



Click



)
}
}

export default Component
`

Any hints?

additional rendering options

would you consider supporting additional rendering approaches?

i'd like to use emotion and support SSR of styles, which would require processing with emotion after rendering the component.

i'm sure you dont want to couple this plugin to emotion, so the best option might be to allow providing a function for renderMethod in addition to the current string options. it could expect to receive ViewElement and context as input and return the viewOutput string.

for example:

import { renderToString } from 'react-dom/server'
import { renderStylesToString } from 'emotion-server'

const context = { name: 'Steve' };
const renderOpts = {
    runtimeOptions: {
        doctype: '<!DOCTYPE html>',
        renderMethod: (ViewElement, context) => {
          return renderStylesToString(renderToString(ViewElement(context)));
        }
    }
};

const output = await server.render('template', context, renderOpts);

i'd be open to sending a PR if this seems like a reasonable option to you.

How to use babel as the jsx-transformer?

the doc says when using another jsx-transformer instead of node-jsx, one should set useNodeJsx to false.

i want to use babel as the transformer, my configuration looks like this:

'visionary': {
            engines: {
                jsx: 'hapi-react-views'
            },
            compileOptions: { useNodeJsx: false },
            relativeTo: __dirname,
            path: './server/views'
        }

i simply added require(babel/register) at the top of home.jsx, then this error occurred.

Debug: internal, implementation, error 
    /Users/gnimuc/Documents/test/server/views/home.jsx:25
            <div className="commentBox">
            ^
SyntaxError: Unexpected token <

i guess this is not the correct way to change the jsx-transformer.

i'm very new to nodejs, sorry for disturbing.

Create an example

Is it possible to create an example. If possible a somewhat complex example with multiple components and working client side injecting of React (with renderToString)?

Push State and static files

Hello.
I'm trying to use your plugin in my app but I've came across with a question: How can I use Push state ( for React routing ) in Hapi react views?

I've tried:

        server.views({
            engines: {
                jsx: HapiReactViews
            },
            relativeTo: __dirname,
            path: 'src',
            compileOptions: {
                renderToString: true
            }
        });

        server.route({
            method: 'GET',
            path: '/{param*}',
            handler: {
                view: 'Default'
            }   
        });

and this works but all my static files ( images and styles mainly ) are transferred with the wrong Mime type.

If I use a path like this:

path: '/'

My routing works only if I initiate in the '/' URL. The navigation works but when I try to refresh inside a path ( e.g /users/1 ) it shows a 404 error.
Does the best option ( and only ) would be to explicit make "several routes" for my react routes routes in my server.js?
Something like:

        server.route({
            method: 'GET',
            path: '/',
            handler: {
                view: 'Default'
            }   
        });

        server.route({
            method: 'GET',
            path: '/users/{id}',
            handler: {
                view: 'Default'
            }   
        });

Thanks!

Odd error after updating

[1] ==> ๐ŸŒŽ  Listening at http://localhost:8000
[1] Debug: internal, implementation, error 
[1]     SyntaxError: Unexpected token <: Unexpected token <
[1]     at exports.runInThisContext (vm.js:53:16)
[1]     at Module._compile (module.js:414:25)
[1]     at Object.Module._extensions..js (module.js:442:10)
[1]     at Module.load (module.js:356:32)
[1]     at Function.Module._load (module.js:311:12)
[1]     at Module.require (module.js:366:17)
[1]     at require (module.js:385:17)
[1]     at runtime (/Project/node_modules/hapi-react-views/index.js:22:25)
[1]     at Object.renderer (/Project/node_modules/vision/lib/manager.js:142:36)
[1]     at internals.Manager._render (/Project/node_modules/vision/lib/manager.js:477:14)
[1]     at Object.internals.marshal (/Project/node_modules/vision/lib/manager.js:571:13)
[1]     at internals.Response._prepare.internals.Response._processPrepare.internals.Response._marshal.next [as _marshal] (/Project/node_modules/hapi/lib/response.js:464:22)
[1]     at /Project/node_modules/hapi/lib/transmit.js:124:18
[1]     at /Project/node_modules/hapi/lib/transmit.js:499:20
[1]     at Object.exports.parallel (/Project/node_modules/hapi/node_modules/items/lib/index.js:47:9)
[1]     at Object.exports.send.internals.marshal.internals.fail.internals.transmit.internals.state.Items.parallel [as state] (/Project/node_modules/hapi/lib/transmit.js:492:11)

Babel transpile JSX to JS - Handling for different file extensions

I use Babel CLI for production to compile my ES6 code to ES5. The files with the extension .jsx be compiled to .js. The server will only recognize the .jsx ending. How do you solve the problem?

  server.views({
    engines: {
      jsx: HapiReactViews,
    },
    compileOptions: {
      doctype: '',
    },
    relativeTo: __dirname,
    path: 'views',
  });

Not issue but recommendation for updating documentation

Hello,
I tried to use hapi 17 with hapi-react-views and mongo-models (hapi-mongo-models) and I found the issue when I joined all together.
In general, babel (required by React) creates an error when I try to use a model.
Recommendation if using react-views and mongo-models add to app .babelrc with:
{ "ignore": [ "server/api/*.js", "server/models/*.js" ] }
(replace my path with your).

ps. maybe this should go to hapi-mongo-models :-)

React Events?

I was trying to add forms and events (onSubmit, onChange, onClick) to a template. It seems those do not get attached to the rendered html output?

import React from 'react'
class Component extends React.Component {
  constructor() {
    super()
    this.state = {clicked: false}
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({clicked: !this.state.clicked})
  }
  render() {
    return (
      <div>
        <form>
          <div onClick={this.handleClick}> Click </div>
        </form>
      </div>
    )
  }
}
export default Component

Any hints?

How do I set the `title` when using a layout?

Thanks so much for this lib, really enjoying it! Just experimenting with your layout example and I need to ask, how can I set this.props.title?

I tried setting defaultProps in Auth.tsx (just a component):

import * as React from 'react'

interface ILayoutProps {
  title: string
}

export default class extends React.Component<ILayoutProps, undefined> {
  public static defaultProps: ILayoutProps = {
    title: 'Authenticate'
  }

  public render () {
    return (
      <a href="/auth/google/callback">Login with Google</a>
    )
  }
}

But this.props.title is still undefined in Layout ๐Ÿ˜ฒ

Any thoughts? Thanks!

Question about isomorphic/universal example

I'm pretty new to React and having a hard time understanding how multiple views (pages) are rendered when using this module to set up an isomorphic application.

I see that client.js calls render on app.jsx, but how does this work when you have more than just app.jsx? I created two separate views, but it looks like the second page is trying to render with app.jsx. How do I set this up to accept multiple views? If this isn't what I should be doing, can you tell me how I should be going about this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.