GithubHelp home page GithubHelp logo

vue-sse's Introduction

VueSSE

GitHub issues license

VueSSE enables effortless use of Server-Sent Events by providing a high-level interface to an underlying EventSource.

Install

# npm
npm install --save vue-sse

# OR yarn
yarn add vue-sse
// in main.js
import VueSSE from 'vue-sse';

// using defaults
Vue.use(VueSSE);

// OR specify custom defaults (described below)
Vue.use(VueSSE, {
  format: 'json',
  polyfill: true,
  url: '/my-events-server',
  withCredentials: true,
});

Quickstart

this.$sse.create('/my-events-server')
  .on('message', (msg) => console.info('Message:', msg))
  .on('error', (err) => console.error('Failed to parse or lost connection:', err))
  .connect()
  .catch((err) => console.error('Failed make initial connection:', err));

Usage

Clients can be created from the Vue object via Vue.$sse.create(...) or from within components via this.$sse.create(...)

All of the following are valid calls to create a client:

  • this.$sse.create('/your-events-endpoint') to connect to the specified URL without specifying any config
  • this.$sse.create({ url: '/your-events-endpoint', format: 'json' }) will automatically parse incoming messages as JSON
  • this.$sse.create({ url: '/your-events-endpoint', withCredentials: true }) will set CORS on the request

Once you've created a client, you can add handlers before or after calling connect(), which must be called.

Configuration

$sse.create accepts the following config options when installing VueSSE via Vue.use and when calling $sse.create.

Option Type Description Default
format "plain" | "json" | (event: MessageEvent) => any Specify pre-processing, if any, to perform on incoming messages. Messages that fail formatting will emit an error. "plain"
url string The location of the SSE server. ""
withCredentials boolean Indicates if CORS should be set to include credentials. false
polyfill boolean Include an EventSource polyfill for older browsers. false
forcePolyfill boolean Forces the EventSource polyfill to always be used over native. false
polyfillOptions object Custom options to provide to the EventSource polyfill. Only used if forcePolyfill is true. null

If $sse.create is called with a string, it must be the URL to the SSE server.

Methods

Once you've successfully connected to an events server, a client will be returned with the following methods:

Name Description
connect(): Promise Connects to the server. Must be called.
on(event: string, (data: any) => void): SSEClient Adds an event-specific listener to the event stream. The handler function receives the message as its argument (formatted if a format was specified), and the original underlying Event. For non-event messages, specify "" or "message" as the event.
once(event: string, (data: any) => void): SSEClient Same as on(...), but only triggered once.
off(event: string, (data: any => void)): SSEClient Removes the given handler from the event stream. The function must be the same as provided to on/once.
on('error', (err) => void): SSEClient Allows your application to handle any errors thrown, such as loss of server connection and pre-processing errors.
disconnect(): void Closes the connection. The client can be re-used by calling connect(). Must be called! (Usually, in the beforeDestroy of your component.)

Properties

Name Type Description
source EventSource Returns the underlying EventSource.

Cleanup

Every connection must be disconnected when the component is destroyed. There are two ways to achieve this:

  1. Call disconnect() on the client during beforeDestroy, or
  2. Add the following option to your component to have them automatically closed for you during beforeDestroy:
export default {
    name: 'my-component',
    data() { /* ... */ },
    // ...
    sse: {
        cleanup: true,
    },
    // ...
}

Vue 3

This plugin works the same in both Vue 2 and 3. The Composition API is not yet supported.

Example

An example project is provided at tserkov/vue-sse-example.

Kitchen Sink

<template>
  <div>
    <p
      v-for="(message, idx) in messages"
      :key="idx"
    >{{ message }}</p>
  </div>
</template>

<script>
// We store the reference to the SSE client out here
// so we can access it from other methods
let sseClient;

export default {
  name: 'sse-test',
  data() {
    return {
      messages: [],
    };
  },
  mounted() {
    sseClient = this.$sse.create({
      url: '/your-events-server',
      format: 'json',
      withCredentials: true,
      polyfill: true,
    });

    // Catch any errors (ie. lost connections, etc.)
    sseClient.on('error', (e) => {
      console.error('lost connection or failed to parse!', e);

      // If this error is due to an unexpected disconnection, EventSource will
      // automatically attempt to reconnect indefinitely. You will _not_ need to
      // re-add your handlers.
    });

    // Handle messages without a specific event
    sseClient.on('message', this.handleMessage);

    // Handle 'chat' messages
    sseClient.on('chat', this.handleChat);

    // Handle once for a ban message
    sseClient.once('ban', this.handleBan);

    sseClient.connect()
      .then(sse => {
        console.log('We\'re connected!');

        // Unsubscribes from event-less messages after 7 seconds
        setTimeout(() => {
          sseClient.off('message', this.handleMessage);
          console.log('Stopped listening to event-less messages!');
        }, 7000);

        // Unsubscribes from chat messages after 14 seconds
        setTimeout(() => {
          sse.off('chat', this.handleChat);
          console.log('Stopped listening to chat messages!');
        }, 14000);
      })
      .catch((err) => {
        // When this error is caught, it means the initial connection to the
        // events server failed.  No automatic attempts to reconnect will be made.
        console.error('Failed to connect to server', err);
      });
  },
  methods: {
    handleBan(banMessage) {
      // Note that we can access properties of message, since our parser is set to JSON
      // and the hypothetical object has a `reason` property.
      this.messages.push(`You've been banned! Reason: ${banMessage.reason}`);
    },
    handleChat(message) {
      // Note that we can access properties of message, since our parser is set to JSON
      // and the hypothetical object has these properties.
      this.messages.push(`${message.user} said: ${message.text}`);
    },
    handleMessage(message, lastEventId) {
      console.warn('Received a message w/o an event!', message, lastEventId);
    },
  },
  beforeDestroy() {
    // Make sure to close the connection with the events server
    // when the component is destroyed, or we'll have ghost connections!
    sseClient.disconnect();

    // Alternatively, we could have added the `sse: { cleanup: true }` option to our component,
    // and the SSEManager would have automatically disconnected during beforeDestroy.
  },
};
</script>

vue-sse's People

Contributors

clayadavis avatar mattee12 avatar supersonictw avatar tserkov 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

vue-sse's Issues

Edge IE11

Hi,
I have a problem when I use this package in Vue in Edge and IE11 I get a blank screen and get a SCRIPT1002: Syntax error in the code under this part:

/***/ "./node_modules/vue-sse/src/vue-sse.js":
/*!*********************************************!*\
  !*** ./node_modules/vue-sse/src/vue-sse.js ***!
  \*********************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var eventsource_polyfill__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! eventsource-polyfill */ \"./node_modules/even

I have set this as babel.config.js

[
			'@babel/preset-env',
			{
				'targets': {
					'chrome': '58',
					'ie': '11'
				}
			}
		]

Feature: Passing custom headers

Hello, I noted that the polyfill allows to pass custom headers.

const es = new EventSourcePolyfill('/events', {
  headers: {
    'X-Custom-Header': 'value'
  }
});

Is this feature supported by vue-sse?

I tried registering VueSSE as follows but with no results:

Vue.use(VueSSE, {
  format: "json",
  polyfill: true,
  url: `${process.env.SERVER_API}/events/`,
  withCredentials: true,
  headers: {
    "X-Custom-Header": "value",
  },
})

I'd need to pass an auth token to the server and passing it with something like

url: `${process.env.SERVER_API}/events/?token=123456`

is not an option.

Eventually, could it technically be added as a new feature? In this case, if you don't want to implement it and maybe with some help, I could try.

Add autoclose feature

Regarding #12 (comment), I see you are working on a v2.

There is some new feature I would like to see in it. Tell me if it makes sense to you and if you need help.

As a user, in my default usage I just want to be able to subscribe to events and change my vue when event is raised.
Most of the time, I don't want to thinking about re-connection or closing source.

So the idea would be to let vue-sse do it for me :

  1. handle closing source on beforeDestroy() (The most important part to me)
  2. handle reconnection. (I'm not sure if this is needed)

For :

  1. plugin mixing could be used (examples)
  2. Reading #7 or speficication, I'm not sure if this feature is really needed. But if reconnection is needed a default simple way would be good.

All of this would be the default behavior and could be deactivate to handle it manually.
(Optionally, we could imagine configuration do set the reconnection or automatic close behavior)

So finally the user code will just look something like this :

<template>
  <div>
    <p v-for="message in messages">{{ message }}</p>
  </div>
</template>

<script>
export default {
  name: 'sse-test',
  data() {
    return {
      messages: [],
    };
  },
  mounted() {
    this.$sse('/your-events-server', { format: 'json' }) // or { format: 'plain' }
      .then(sse => {
        // Catch any errors (ie. lost connections, etc.)
        sse.onError(e => {
          console.error('lost connection; giving up!', e);
        });

        // Listen for messages based on their event (in this case, "chat")
        sse.subscribe('chat', (message, rawEvent) => {
          this.messages.push(message);
        });
      })
      .catch(err => {
        // When this error is caught, it means the initial connection to the
        // events server failed.  No automatic attempts to reconnect will be made.
        console.error('Failed to connect to server', err);
      });
  },
};
</script>

Is v2 branch usable?

Hello, I need to integrate SSE with vue and found this project, very nice opportunity to use it.

Just to know, which branch should I use? I see a v2 updated recently but not sure if it's OK to use it right now (issue #12 is closed but #13 is not). Any opinion?

Thanks!

OT
Do you have any objection adding vue-sse to https://github.com/vuejs/awesome-vue? I can do the pull request if you like the idea.

i need help,thanks

image

I want to create a progress bar using vue-sse. After initiating the request, each time it reaches the 10-second mark. It goes to the error branch.
image

Vue 3 package dependency compatibility

Hello and thanks for building this package!

I'd like to use it in a Vue 3 based project, but the default installation fails due to package dependency incompatibility:

$ npm install --save vue-sse
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/vue
npm ERR!   vue@"^3.2.13" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer vue@"^2.0.0" from [email protected]
npm ERR! node_modules/vue-sse
npm ERR!   vue-sse@"*" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

I saw that the docs are saying that is compatible with Vue 3, and the vue-sse-example is based on Vue 2.

Shall I --force install it?

Thanks!

No matter what, event source returns error

Hello,

I have been unable to get vue-sse to actually fetch the data. Which is strange, because when I check Data > XHR and Fetch in Chrome's DevTools, I can clearly see the data coming in, yet the only thing firing off is an error, and what's worse is the error is not descriptive at all. Anyways, here's my code:

// PortfolioLongDesc.vue
mounted() {
        (async () => {
            try {
                msgServer =  await this.$sse('longDesc', {format: 'plain'})
                .then(sse => {

                    sse.onError(e => {
                        console.log("Lost connection: ", e);
                 });
                 console.log("Subscribing to all events...");
                 sse.subscribe('', description => {
                     this.description = description;
                 });
                })

            } catch(err)
            {
                console.log("Failed to connect: ", err);
            }
        })();

On the server, I am simply intercepting the "/longDesc" path, setting the content-type to "text/event-stream" and sending back "data: My description" e.g.:

// server.js
if(pathname === "./longDesc")
    {
        result.setHeader("Content-type", "text/event-stream");
        result.end("data: " + middleware.getLongDesc());
        return;
    }
// middleware.js
const fs = require("fs");
module.exports = {
    getLongDesc: function (){
        rs = fs.readFileSync('./description.txt', 'utf8');
        return rs;
        
    }
}

As I said, the data seems to come in just fine, it just seems that vue-sse is registering the the event as an error, and never calling the subscription handler.

Changing default config value

I don't know if this is doable with the current version. (Reading the code I guess it's not)
I would like to be able to set the default config of vue-sse.

Example changing the default format to use :

// in plugins/sse.js
import VueSSE from 'vue-sse';
import Vue from "vue";

VueSSE.defaultconfig.format = 'json';
Vue.use(VueSSE);

sse.once(event,fn), fn triggered multiple times

Use this.$sse.once(), it will be triggered continuously instead of only once.

sorry,I won't use jest to write this test (-。-!)

I made the following modifications to test the feasibility:

path: src/sse-client.js

api: once

`once(event, handler) {

//old   
-    this.on(event, (e) => {
-     this.off(event, handler);
-     handler(e);
-    });


//new change-1: start
 const once = e => {
   handler(e);
   this.off(event, handler);
 };
 once.initialhandle = handler;//
 this.on(event, once);

//change-1: end
return this;

}`

api: off

`off(event, handler) {
if (!this._handlers[event]) {
// no handlers registered for event
return this;
}

  //old
  const idx = this._handlers[event].indexOf(handler);
     if (idx === -1) {
     // handler not registered for event
     return this;
   }
   // remove handler from event
   this._handlers[event].splice(idx, 1);

  //new  change-2 start
  // if handler is null ,remove all handler from event
  if (!handler) {
    delete this._handlers[event];
    return this;
  }

  //initialhandle 标识出 once 的handler
  this._handlers[event] = this._handlers[event].filter(
    item => item !== handler && item.initialhandle != handler
  );
  //change-2 end


  if (this._handlers[event].length === 0) {
    // remove listener since no handlers exist
    this._source.removeEventListener(event, this._listeners[event]);
    delete this._handlers[event];
    delete this._listeners[event];
  }
  return this;


}

`

Error in mounted hook: "TypeError: this.$sse is not a function"

Hi,

I am trying to use this module with my Vue application. I registered the plugin in my main.js file:

import VueSSE from 'vue-sse'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

Vue.use(Buefy, Vuex, axios, VueAxios, VueSSE)

And I try to use this in my component:

mounted () {
  this.$sse('http://192.168.178.93:8000/api/get/statusupdate', { format: 'json' })
    .then(sse => {
      msgServer = sse

      sse.onError(e => {
        console.error('Connection lost', e)
      })
      sse.subscribe('', data => {
        console.warn('Received a message w/o an event!', data)
      })
    })
  },

But in my console I get this error:

[Vue warn]: Error in mounted hook: "TypeError: this.$sse is not a function"

found in

---> <RecordForm> at src/components/RecordForm.vue
   <BaseLayout> at src/components/BaseLayout.vue
     <Index> at src/views/Index.vue
       <App> at src/App.vue
         <Root>

I don't know what the problem is...

If I log this.$sse I get "undefined" which seems to be part of the problem.

Add CONTRIBUTING.md

For future contributors, would you mind adding a quick CONTRIBUTING.md? The main points I'd love to see there:

  • What linting and/or testing we should do before submitting a PR
  • Whether or not to include dist/ files in a PR

Remove promise wrapper

Hello! I think there is no need return Promise from $sse factory function. Return a promise causes some problem. If sse server not available when component mounted, reject function triggered and resolve will never be fired.
This will lead to the fact that we will not get the wrapper object when restoring the connection to the server. This way we lose the parent EventSource object in the closure and can't close it. This situation is especially dangerous in SPA applications. I believe that EventSource already provides the necessary functions for working with async and Promise is a redundant solution here

Memory leak if onopen event received after we close a component.

I begin to play with vue-sse and I maybe find an issue.

My code looks like :

export default {
  mounted() {
    console.log("MOUNTED", this.sse);
    this.$sse("api/event", { format: "json" })
      .then((sse) => {
        this.sse = sse; // store sse to close in on Destroy
        console.log("CONNECTED");
        sse.onError((e) => {
          console.error("on error", e);
        });
        sse.subscribe("UPDATED", () => {
          console.log("UPDATED");
        });
      })
      .catch((err) => {
        console.error("Failed to connect to server", err);
      });
  },
  beforeDestroy() {
    console.log("DESTROYED", this.sse ? "sse defined" : "sse undefined");
    this.sse.close();
  },
};

This sounds OK but for a reason I can not explain for now the onopen call take a lot of time before to be called. (I don't know if this is an issue but this reveals what it looks like a real design issue)

Here is the normal use case :

MOUNTED  // I open my vue
CONNECTED // get connected
UPDATED  // received some messages
UPDATED 
UPDATED 
UPDATED 
DESTROYED source defined // close the vue

Now this is the failing use case where I close my view before to get connected

MOUNTED // I open my vue
DESTROYED source undefined  // I close it before the onopen
[Vue warn]: Error in beforeDestroy hook: "TypeError: this.sse is undefined"
CONNECTED // onopen is called after beforeDestroy and so will live "forever"
UPDATED
UPDATED
UPDATED

It seems to me that my usecase is a "classic" one and so unless I missed something there is maybe a design issue ? 🤔
Adapting vue-sse code to get the wrapper object immediatly without waiting the onopen event (like proposed in #7), this resolved my issue.

If there is no issue in the code and if there is a good way to handle this, I guess there is at least an issue in README examples.

EventSource undefined when using Polyfill

Hi! There is a typo in the EventSourcePolyfill initialization that causes this._source to be undefined.

if (this.forcePolyfill) {
  this._source = EventSourcePolyfill(
    this.url,
    Object.assign({}, this.polyfillOptions, {
      withCredentials: this.withCredentials,
    }),
  );
}

I suppose that the problem is that you are trying to call the constructor, and not a function. Adding new should be enough.

I'll try locally and, if it works, I'll do the PR.

Wrong Documentation

Hi, I've been using your module for a while and all worked ok.

I saw you made breaking changes and when tried to apply the changes I realize your documentation is a mix between the old way and the new one.

I guess now we have to use on("error", fn) instead of onError(fn), and after this.$sse.create we have to use await sse.connect, and later sse.disconnect.

Am I right?

Your examples are all old, can you please update the documentation?

Regards.

Small typo in the promises example

I noticed a small typo in the example using promises:

        // Listen for messages without a specified event
        sse.subscribe('', (message, rawEvent) => {
          console.warn('Received a message w/o an event!', data);
        });

data should have been message.

Subscribing to '' returns messages from all events

Not sure if this is intended, but the example is worded like it is not.

From the example + addition:

    // Listen for messages without a specified event
    sse.subscribe('', (message, rawEvent) => {
        console.warn('Received a message w/o an event!', message,rawEvent);
    });

    // Listen for messages based on their event (in this case, "message")
    sse.subscribe('message', (message, rawEvent) => {
        console.log('Received message for event "message"',message,rawEvent);
        this.messages.push(message);
    });

Reading this my expectation is that the console.warn() outputs messages that have no event.

Setup:
Using the Go SSE server implementation from https://github.com/SubChord/go-sse

    count++
    api.broker.Broadcast(net.StringEvent{
        Id:    fmt.Sprintf("event-id-%v", count),
        Event: "message",
        Data:  strconv.Itoa(count),
    })

Result:

: heartbeat

id: event-id-3108
event: message
data: 3108

id: event-id-3109
event: message
data: 3109

id: event-id-3110
event: message
data: 3110

: heartbeat

id: event-id-3111
event: message
data: 3111

image

Vue 3?

Hello

Does vue-sse supports Vue 3? If yes, how do I write the code for Compose API?

How to supress no activity error

I am getting a console error after 45 seconds, that there was no activity and EventSource will reconnect.

Error: No activity within 45000 milliseconds. 2 chars received. Reconnecting.
    at onTimeout (vue-sse.esm.js?0292:948)
    at eval (vue-sse.esm.js?0292:957)

I tried to catch the error to supress it but weather
.on('error, (err) => ... )
nor
this.$sse.source.addEventListener('error', (err) => ... )
nor
.connect().then((client) => client.source.addEventListener
did surpress the original error message. Id did catch the error, but it stills logged the original error to the console.

I cannot send a null byte from the server, because I do not have access to the feed and I am okay that there is a reconnect, but how can I make it silent?

Trying to get this to work with an existing Vue application and running into error

vue-sse.js?4318:49 Uncaught TypeError: source.onerror is not a function
at EventSource.listener (vue-sse.js?4318:49)
listener @ vue-sse.js?4318:49

  mounted () {
    console.log('main mounted')
    this.$sse('http://localhost:8999/events', {format: 'json'})
    .then(sse => {
      sse.onError(e => {
        console.error('lost connection; giving up!', e)
      })
      sse.subscribe('', data => {
        console.warn('Received a message w/o an event!', data)
      })
      sse.subscribe('ss', (message) => {
        console.log('got one ' + message)
      })
      sse.onerror(e => {
        console.log('got an error ' + e)
      })
    })
    console.log('returning')
  },

Add option to define the HTTP method

Hi,

According to [1], I didn`t see a way to define the HTTP method. I think it should provide a way to define it. Ex.:

sseClient = this.$sse.create({
      url: '/your-events-server',
      method: 'POST',
      format: 'json',
      withCredentials: true,
      polyfill: true,
    });

Let me know if it makes sense. If so, can I prepare a PR?

[1] -

this.url,

Client initialization breaks when using forcePolyfill

Hi! I was trying to use the recent feature you added to specify custom headers forcing Polyfill (#21) .
I am passing an Authorization header with a JWT. The code breaks constructing the EventSourcePolyfill:

if (this.forcePolyfill) {
  this._source = eventsource.EventSourcePolyfill(
    this.url,
    Object.assign({}, this.config.polyfillOptions, {
      withCredentials: this.withCredentials,
    })
  );
}

The error is:

TypeError: Cannot read properties of undefined (reading 'polyfillOptions')

It appears that this.config is undefined.
In the constructor, you are setting the properties extracting them from the config object, but you are not saving the config object itself:

this.url = config.url;
this.withCredentials = !!config.withCredentials;
this.polyfillOptions = config.polyfillOptions || {};
this.forcePolyfill = !!config.forcePolyfill;

The fix should be easy: assigning this.polyfillOptions instead of this.config.polyfillOptions. I can do a pull request.

Thanks in advance!

Feature: Vue 3 support

When trying to install VueSSE with Vue 3, you may receive a warning:

[email protected]" has incorrect peer dependency "vue@^2.0.0".

When trying to use according to the instructions, an error occurs:

Uncaught TypeError: Vue.prototype is undefined

Are you planning to add support for Vue 3 (including the Composition API)?

Thanks!

Allow passing of custom EventSource or allow HTTP headers.

The classic EventSource does not allow setting of HTTP headers (See this discussion that ook place over the past 5 years). This makes things like authentication incredibly cumbersome as there is no easy way to pass user info or auth tokens. Luckily there is a popular drop-in replacement for EventSource by Yaffle which allows for setting a header just like you would on any other http request.

import {  EventSourcePolyfill } from 'event-source-polyfill';

const source = new EventSourcePolyfill(url, { headers: { Authorization: "some_authentication_token" } });

But these options results in a conflict for us fragile Vue users: Do we want authentication or do we want the ease-of-use of the vue-sse package?

As a solution I suggest to either allow passing a custom EventSource object as a parameter for SSEclient (looking at the source code of this package it shouldn't be too big of a change), or (if we're really going to be developer-friendly) use Yaffle's EventSource object under the hood and allow for passing of headers directly in the SSEclient.

If nobody is able to implement this feature I would be willing to create a PR and implement it myself (but I must admit that I am not too experienced with JS development).

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.