Coder Social home page Coder Social logo

fastly / js-compute-runtime Goto Github PK

View Code? Open in Web Editor NEW
190.0 28.0 25.0 19.98 MB

JavaScript SDK and runtime for building Fastly Compute applications

Home Page: https://developer.fastly.com/learning/compute/javascript/

License: Apache License 2.0

JavaScript 26.41% Rust 0.31% Makefile 0.41% C++ 46.96% C 24.91% Shell 0.32% HTML 0.08% TypeScript 0.57% CMake 0.03%
compute-sdk fastly-product

js-compute-runtime's Introduction

@fastly/js-compute

JavaScript SDK and CLI for building JavaScript applications on Fastly Compute.

npm version npm downloads per month

Getting Started

We recommend using the Fastly CLI to create, build, and deploy JavaScript Fastly Compute services, as described on the Fastly Developer Hub.

Detailed documentation for JavaScript Fastly Compute services is also available on Fastly Developer Hub.

Usage

JavaScript Examples

The Fastly Developer Hub has a collection of example JavaScript applications.

Here is a small example application:

/// <reference types="@fastly/js-compute" />

async function app(event) {
    const request = event.request;
    return new Response(`You made a request to ${request.url}`)
}

addEventListener("fetch", event => {
  event.respondWith(app(event));
});

API documentation

The API documentation for the JavaScript SDK is located at https://js-compute-reference-docs.edgecompute.app.

Security

If you find any security issues, see the Fastly Security Reporting Page or send an email to: [email protected]

We plan to disclose any found security vulnerabilities per the GitHub security vulnerability guidance. Note that communications related to security issues in Fastly-maintained OSS as described here are distinct from Fastly security advisories.

Changelog

The changelog can be found here.

License

Apache-2.0 WITH LLVM-exception

js-compute-runtime's People

Contributors

acfoltzer avatar acme avatar andersdjohnson avatar andrebenedetti avatar bekahs4 avatar black2d avatar cfallin avatar davidmturner avatar dependabot[bot] avatar doramatadora avatar elliottt avatar github-actions[bot] avatar guybedford avatar harmony7 avatar jakechampion avatar jameysharp avatar jsocol avatar kphillips avatar mxdvl avatar remore avatar torch2424 avatar triblondon avatar tschneidereit avatar wh0 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-compute-runtime's Issues

AbortController Support

I am trying to create a Rest API with Worktop & Faunadb. The Worktop Routing Works, but Faunadb JS Library needs AbortController which doesn't seems to be Present in the Global Object of Compute@Edge JS Runtime, it says AbortController is not present in global object, you have to Polyfill it. What do you Recommend to do? Is these a Compute@Edge JS Runtime issue?

Provide option to capture performance profile

When using Firefox one can profile the javascript running in SpiderMonkey and get a flame chart either directly in there or by exporting the data and visualizing it in eg. https://github.com/jlfwong/speedscope

To enable understanding in how the WASM-compiled SpiderMonkey executes ones code and to more aggressively profile that code it would be fabulous to be able to export such profiling data from it as well, either by setting a flag when compiling or through a similar mechanism as enableDebugLogging().

I've tried digging into the code of SpiderMonkey/Firefox to understand how to achieve this, but unfortunately its a bit outside of my expertise so I haven't found out how, hence opening an issue rather than a PR.

Console.trace should be Console.debug

The Compute@Edge JavaScript runtime's Console provides the log, trace, info, warn, and error functions:

  const JSFunctionSpec methods[] = {
    JS_FN("log", (console_out<PREFIX_LOG, 3>), 1, JSPROP_ENUMERATE),
    JS_FN("trace", (console_out<PREFIX_TRACE, 5>), 1, JSPROP_ENUMERATE),
    JS_FN("info", (console_out<PREFIX_INFO, 4>), 1, JSPROP_ENUMERATE),
    JS_FN("warn", (console_out<PREFIX_WARN, 4>), 1, JSPROP_ENUMERATE),
    JS_FN("error", (console_out<PREFIX_ERROR, 5>), 1, JSPROP_ENUMERATE),
    JS_FS_END
  };

However, the standard Console functions should be log, debug, info, warn, error. In fact, in the standard Console, trace() will output a stack trace.

Console's trace should be renamed to debug.

Improve handling of hostcall errors

In a lot of places, we currently turn a hostcall error code into a JS exception containing the error code and the C++ source location of the hostcall. That's very rarely helpful in debugging JS code, and we should improve on it :)

JS_GC trap issue.

Hi,

I am using this repo and execute the runtime on wasmtime.

What I observed is that 1 out of 3 times if I call JS_GC at the end of the function that I called, js-compute-runtime can trigger a HeapOutOfBound trap in wasmtime.

Is there any suggestions on this why this is happening?

Thanks

Missing some build instructions on README?

Missing some instructions on README for the build?

I encountered errors during the following build commands on README.md:

$ git submodule update --recursive --init
$ (cd c-dependencies/spidermonkey && sh download-engine.sh)
$ cargo build --release // ERROR

Not sure if this is common for other people, but I share what I've done, for the record.

Environment:

  • hash: dbd9386
  • platform: M1 Mac (darwin, arm64)

`text()` does not strip UTF-8 BOM from HTTP response

Version: 0.2.4

We have an HTTP backend which adds a UTF-8 BOM to the start of HTTP responses. We noticed that it is present in the string returned by text(). It seems Node's own fetch() method have recently added a fix which strips out BOMs:

node-fetch/node-fetch#1482

Might be worth considering doing something similar? It doesn't feel right that text() returns a string which still contains a BOM. For now, we have made use of https://www.npmjs.com/package/strip-bom to remove the BOM from the string returned by text()

Large Compilations

I am following the directions for building the runtime and I can produce the executables however the runtime executable and the wasm file are huge.

372525848 Jan 3 13:16 js-compute-runtime
353101412 Jan 3 13:12 js-compute-runtime.wasm

I tried a few different times but I must be missing something, is there a trick to compile it smaller?

Compare a bare-bones rust and js service for startup time

We should profile a bare-bones rust and js service to see what the current difference in startup time for the two is. It would also be worth making a version that handles the request without interacting with spidermonkey at all, handling the request entirely in c++, as that would help attribute cost to spidermonkey startup.

If we discover that the slowdown is in spidermonkey, we could next investigate heap access patterns to see if there are any changes we could make to optimize that.

WebAssembly trapped manipulating ReadableStreams

Hi,
Following #10, I tried to reproduce a clone response function using ReadableStream::tee(), making 2 new responses from one.
The function looks like that:

function cloneResponse(response) {
    const teedOff = response.body.tee();
    return {
        currentResponse: new Response(teedOff[0], { headers: cloneHeaders(response.headers), status: response.status }),
        newResponse: new Response(teedOff[1], { headers: cloneHeaders(response.headers), status: response.status }),
    }
}

By doing that, I can read the responses body using the ReadableStream::getReader(), they are not locked.
But if I want to use the Response::json(), Response::text() or Response::arrayBuffer() instead of the reader, I get this error:

Aug 12 15:57:25.102 ERROR request{id=0}: WebAssembly trapped: wasm trap: unreachable
wasm backtrace:
    0: 0x5a6b - <unknown>!<wasm function 69>
    1: 0x593c - <unknown>!<wasm function 68>
    2: 0x11d6e - <unknown>!<wasm function 181>
    3: 0x129f1 - <unknown>!<wasm function 186>
    4: 0x384ca - <unknown>!<wasm function 475>
    5: 0x316ee - <unknown>!<wasm function 455>
    6: 0x299a9 - <unknown>!<wasm function 452>
    7: 0x387f9 - <unknown>!<wasm function 475>
    8: 0x3b701 - <unknown>!<wasm function 498>
    9: 0x177517 - <unknown>!<wasm function 3190>
   10: 0x96905 - <unknown>!<wasm function 1403>
   11: 0x1236ff - <unknown>!<wasm function 2376>
   12: 0x384ca - <unknown>!<wasm function 475>
   13: 0x3b701 - <unknown>!<wasm function 498>
   14: 0xa5a0e - <unknown>!<wasm function 1557>
   15: 0xfc9a5 - <unknown>!<wasm function 2121>
   16: 0x142cb - <unknown>!<wasm function 219>
   17: 0x3eb380 - <unknown>!<wasm function 8540>
   18: 0x140cf - <unknown>!<wasm function 218>

Am I doing something wrong ?
Thanks !

Copy less for request/response objects

We do a lot of copying for Request and Response objects currently, as their fields may be accessed by the javascript runtime after the corresponding handles in the host have been closed. If we had the ability to clone a request or response handle with a new host call, we could keep that around instead of copying all the data across into the runtime.

Inconsistencies between Local & Deployment Versions

When I develop My GraphQL API with Fastly CLI in My Local Machine everything was working fine but, after a Deployment Unexpected Error will Pop Like Service Unavailable Error. Please Fix these Inconsistencies as they are bad for anyone who don't see Error in Development & then the App Crashes after Production Deployment.

You can use My GraphQL Yoga Project as an Example in here:
https://github.com/Abiti-936/graphql-yoga-compute-edge
https://gql-yoga.edgecompute.app

Missing `FormData` and `Request.formData`

I'm building a C@E app which reads a html form submission but I found that FormData and the helper method Request.formData currently are not implemented in the runtime.

Are these planned to be implemented in the runtime?

js-compute-runtime 0.2.0 potential regressions

When using version 0.1.0, projects needed to polyfill URL and URLSearchParams as they were not implemented in the runtime

In version 0.2.0 these globals are now implemented but when building a project which tries to still polyfill these features, a Wizer error is thrown:

Error: failed to initialize JS

Caused by:
0: the wizer.initialize function trapped
1: wasm trap: unreachable
wasm backtrace:

I confirmed this was the polyfills by commenting out this one line in my project and the project then being able to be compiled:

globalThis.URL = require("core-js/features/url");

I assume this means that the globals are currently frozen intrinsics, is this an intentional decision or should these be writable and configurable?

Throw error exit code for failed compilation

If I compile a syntactically valid javascript file that is still not valid we get a wizer error. However the exit code is 0.

Example input index.js:

spaghetti

output of js-compute-runtime --skip-pkg bin/index.js bin/main.wasm:

Exception while evaluating JS: (new ReferenceError("spaghetti is not defined", "<stdin>", 1))
  @<stdin>:1:29
  @<stdin>:1:121

Error: failed to initialize JS

Caused by:
    0: the `wizer.initialize` function trapped
    1: Exited with i32 exit status 1
       wasm backtrace:
           0: 0x3d82a1 - <unknown>!<wasm function 8744>
           1: 0x3d9434 - <unknown>!<wasm function 8760>
           2: 0x1c23a - <unknown>!<wasm function 300>
           3: 0x1bfd5 - <unknown>!<wasm function 298>
           4: 0x1c554 - <unknown>!<wasm function 303>
       
Wizer failed with status: exit status: 1

This is the correct error but the status code is 0:

...
Wizer failed with status: exit status: 1
 
➜  echo $?
0

This makes it impossible for tooling to detect build errors.

Can't call functions of classes derived from built-in classes

Consider the following code that works as expected:

class Base {
  fn() { return 'fn'; }
}
class Derived extends Base {
  constructor() {
    super();
    this.foo = () => { return 'foo'; };
  }
  bar() { return 'bar'; }
  get baz() { return 'baz'; }
}

const obj = new Derived();
console.log(Object.getOwnPropertyNames(Base.prototype));    // constructor,fn
console.log(Object.getOwnPropertyNames(Derived.prototype)); // constructor,bar,baz
console.log(Object.getOwnPropertyNames(obj));               // foo
console.log(obj.fn());                                      // fn
console.log(obj.foo());                                     // foo
console.log(obj.bar());                                     // bar
console.log(obj.baz);                                       // baz
console.log(obj.foo === undefined);                         // false
console.log(obj.bar === undefined);                         // false
console.log(obj.baz === undefined);                         // false

When you try to do the same thing by extending builtins:

class MyRequest extends Request {
  constructor(input, init) {
    super(input, init);
    this.foo = () => { return 'foo'; };
  }
  bar() { return 'bar'; }
  get baz() { return 'baz'; }
}

const request = new MyRequest('https://www.google.com/');
console.log(Object.getOwnPropertyNames(Request.prototype));   // constructor,method,url,version,headers,body,bodyUsed,arrayBuffer,json,text,setCacheOverride
console.log(Object.getOwnPropertyNames(MyRequest.prototype)); // ** constructor,bar,baz
console.log(Object.getOwnPropertyNames(request));             // foo
console.log(request.url);                                     // https://www.google.com/
console.log(request.foo());                                   // foo
console.log(request.bar());                                   // ** Error: request.bar is not a function
console.log(request.baz);                                     // ** undefined
console.log(request.foo === undefined);                       // false
console.log(request.bar === undefined);                       // ** true
console.log(request.baz === undefined);                       // ** true

Look at the logs relating to bar and baz (marked with asterisks above). You can see that the two methods (bar method and baz getter) added through the class definition are added to the prototype but have undefined values. Note that the property added in the constructor (foo) does work, however.

The same problem happens whether we are extending Request, Response, Headers, URL, URLSearchParams, etc. so I believe it is just for the builtins, and I believe it's a bug.

Request does not wait for ReadableStream.pipeTo() to finish

We have a basic TransformStream defined like so:

Pretty please provide this directly in the sdk

export class TransformStream<R = any, T = any> {
  readonly writable: WritableStream<R>
  readonly readable: ReadableStream<T>
  private transform: (chunk: R) => T
  private readableController?: ReadableStreamController<T>

  constructor(props: { transform: (chunk: R) => T }) {
    this.transform = props.transform
    this.readable = new ReadableStream({
      start: (constroller) => {
        this.readableController = constroller
      }
    })
    this.writable = new WritableStream({
      write: (chunk: R) => this.readableController?.enqueue(this.transform(chunk)),
      close: () => this.readableController?.close()
    })
  }
}

We're then using this transform stream like so:

addEventListener('fetch', (event) => event.respondWith(handleRequest(event)))

async function handleRequest(event: FetchEvent) {
  const res = await fetch(...)
  const ts = new TransformStream(...)
  res.pipeTo(ts.writable)
  return new Response(ts.readable)
}

This usage of pipeTo is not waiting for the entire stream to be piped through the transform stream.

If I implement our own version of pipeTo it works correctly, but is slow:

addEventListener('fetch', (event) => event.respondWith(handleRequest(event)))

async function handleRequest(event: FetchEvent) {
  const res = await fetch(...)
  const ts = new TransformStream(...)
  _pipeTo(res, ts.writable)
  return new Response(ts.readable)
}

async function _pipeTo<T>(
  fromStream: ReadableStream<T>,
  toStream: WritableStream<T>
): Promise<void> {
  const reader = fromStream.getReader()
  // eslint-disable-next-line no-constant-condition
  while (true) {
    const res = await reader.read()
    if (res.done) {
      return
    }
    await toStream.getWriter().write(res.value)
  }
}

Investigate delaying GC

We should see if we can delay GC as long as possible, working from the assumption that our services are very short-lived. Avoiding GC during the fetch handler should be possible for small services.

More conretely, we might be able to change the size of the nursery so that we have more space for short-lived allocations, though some allocations skip the nursery so this won't be unambiguously better.

Support for Web Standard APIs

As I seen Fastly Compute@Edge only offers restricted amount of Web Standard APIs in the Reference Website, but Most Web Standard APIs are Just Very Important in most cases like setTimeout, AbortController & more ...
Please Implement Web Standard APIs that are not dependent on the Dom or Browsers. You can Reference core-js & Cloudflare Workers.

Missing globals `URL` and `URLSearchParams`

Hi, this is likely the wrong place to open this issue but I could not find a public repository for the @fastly/js-compute npm package

I wanted to report that URL and URLSearchParams are documented on the website to exist but they don't actually exist when running the code using fastly compute serve or deploying it to Fastly

I can see that the compute-starter-kit-javascript-default uses Webpack and a polyfill from Core-JS to provide these globals - would it be possible to provide these polyfills within the @fastly/js-compute package itself?

https://github.com/fastly/compute-starter-kit-javascript-default/blob/22fe9f050d8a2c715d23da5ea29935765192566d/webpack.config.js#L15-L19

Serialisation issue with Headers and Set-Cookie

When setting set-cookie headers with header.append() there can sometimes be an issue where the set-cookie header is serialised into one header which is comma seperated:
image

This is not accepted as multiple cookies by browsers, after some digging I have found that this only happens when using a Header object which is then passed as a HeaderInit object when creating a response.

This works (creates multiple headers):

addEventListener("fetch", (event) => {
  let r = new Response("Hello");

  r.headers.append("Set-Cookie", "test=1");
  r.headers.append("Set-Cookie", "test2=2");
  r.headers.append("Set-Cookie", "test3=3");
  
  event.respondWith(r)
});

This does not (single comma separated header):

addEventListener("fetch", (event) => {
  let h = new Headers();

  h.append("Set-Cookie", "test=1");
  h.append("Set-Cookie", "test2=2");
  h.append("Set-Cookie", "test3=3");
  
  event.respondWith(new Response("Hello", {
    headers: h
  }))
});

Geoip example code fails silently.

Given the code example for geoip located at https://developer.fastly.com/solutions/examples/geo-ip-api-at-the-edge, this example will fail silently, and return a status 200, zero byte response.

Adding the line console.info("Body response: ", respBody); before the response return, generates the following output :

stderr | b015fc9a | Exception while dispatching FetchEvent
stderr | b015fc9a | : (new Error("get_geo_info: Invalid argument. - Fastly error code 2\n", "", 1))
stderr | b015fc9a | @:1:90
stderr | b015fc9a | @:1:363
stderr | b015fc9a |

Larger Header sizes cause failures

Upon testing I have found the default c@e js runtime limit is 4k for headers. This causes issues with larger cookie and other headers.

This causes any js files that read the headers or try to pass them to origin to fail.

Console logs show the following:


Jan 05 14:39:33.497  INFO request{id=2}: handling request GET http://127.0.0.1:7878/
Log: headers
Jan 05 14:39:33.512 ERROR request{id=2}: Hostcall yielded an error: Buffer length error: buf too long to fit in buf.len()
Error while running request handler: retrieve_value_for_header_from_handle: Buffer length error. Buffer is too long. - Fastly error code 4

Stack:
  handleRequest@<stdin>:66:21
  @<stdin>:11:56

Missing SharedArrayBuffer implementation

When building a project which makes use of SharedArrayBuffer, this error is thrown:

Exception while evaluating JS: (new ReferenceError("SharedArrayBuffer is not defined", "", 622))

I've worked around the issue in my project with a very hacky patch (globalThis.SharedArrayBuffer = ArrayBuffer;)

I think we should add a SharedArrayBuffer implementation as it is used within some packages such as the data-urls package which is used in reference/example code on the Fastly Docs website -- https://developer.fastly.com/learning/compute/migrate/#build-an-image-response

Support overriding `Content-Length` header

Client set up a new JS C@E service and everything is working correctly with the exception that our content-length header is not being returned. Turns out in practice this doesn’t matter a ton because clients are looking for the content-range which is being returned correctly. But we would definitely want this fixed before completely switching over to C@E in production.

@tschneidereit

Internal error code and line shown when calling Dictionary.get method

I have an edge dictionary named aliases containing an item named default, when I try to get the item the service throws an error internal to the runtime, which I've posted below:
The error: /home/runner/work/fst-js-compute-runtime/fst-js-compute-runtime/c-dependencies/js-compute-runtime/../js-compute-runtime/js-compute-builtins.cpp:1789 (get) - Fastly error code 3

That error comes from this function:

bool get(JSContext* cx, unsigned argc, Value* vp) {
METHOD_HEADER(1)
size_t name_len;
UniqueChars name = encode(cx, args[0], &name_len);
OwnedHostCallBuffer buffer;
size_t nwritten = 0;
if (!HANDLE_RESULT(cx, xqd_dictionary_get(dictionary_handle(self), name.get(), name_len,
buffer.get(), DICTIONARY_ENTRY_MAX_LEN,
&nwritten)))
{
return false;
}

I'm not sure what is causing the code to error unfortunately -- hopefully this is enough information to help figure out the root cause

Internal error when using request.headers.delete() with a non-existing header name

How to reproduce: call request.headers.delete(name) with name being the name of a header that doesn't exist in the list

Error: /home/runner/work/fst-js-compute-runtime/fst-js-compute-runtime/c-dependencies/js-compute-runtime/../js-compute-runtime/js-compute-builtins.cpp:2592 (delete_) - Fastly error code 2

The error comes from this function:

bool delete_(JSContext* cx, unsigned argc, Value* vp) {
METHOD_HEADER(1)
NORMALIZE_NAME(args[0], "Headers.delete")
Mode mode = detail::mode(self);
if (mode != Mode::Standalone) {
HeaderRemoveOperation* op;
if (mode == Mode::ProxyToRequest)
op = (HeaderRemoveOperation*)xqd_req_header_remove;
else
op = (HeaderRemoveOperation*)xqd_resp_header_remove;
if (!HANDLE_RESULT(cx, op(detail::handle(self), name_chars.get(), name_len)))
return false;
}
bool has;
RootedObject map(cx, detail::backing_map(self));
if (!JS::MapDelete(cx, map, normalized_name, &has))
return false;
args.rval().setUndefined();
return true;
}

Hope this helps :)

ReadableStream.tee causes fetch to hang

Running the following example:

  fastly.enableDebugLogging(true);                                                 
                                                                                   
  addEventListener("fetch", event => event.respondWith(handleRequest(event.request)));
                                                                                   
  async function handleRequest(req) {                                     
    let [body1, _body2] = req.body.tee();                                          
                                                                                   
    return fetch(new Request(req.url, {                                            
      body: body1,                                                                 
      headers: req.headers,                                                        
      method: req.method,                                                          
      backend: "origin_0"                                                          
    }));                                                                           
  }

the response is never delivered, and the runtime hangs in process_pending_requests at the host call for xqd_req_pending_req_select (pending_req_select in viceroy). I've only verified this working locally with viceroy, but it does exhibit the same failure mode in a fastly fiddle.

It's worth noting that the following program works fine, and exits the call to xqd_req_pending_req_select immediately:

  fastly.enableDebugLogging(true);                                                 
                                                                                   
  addEventListener("fetch", event => event.respondWith(handleRequest(event.request)));
                                                                                   
  async function handleRequest(req) {     
    let body1 = req.body;                                
    // let [body1, _body2] = req.body.tee();                                          
                                                                                   
    return fetch(new Request(req.url, {                                            
      body: body1,                                                                 
      headers: req.headers,                                                        
      method: req.method,                                                          
      backend: "origin_0"                                                          
    }));                                                                           
  }

Provide useful implementations of `toString()` and `toJSON()` for important builtin objects

Logging important builtin objects such as Request, Response, FetchEvent, etc currently doesn't result in useful output. To address this, we should evaluate for which we can implement toString() and toJSON() in useful ways.

Note that we might not be able to do useful things for all of them, because the stringification behavior is fixed by specifications for some or all of them. E.g. JSON.stringify(new Request("http:example.com")) results in the string "{}" in browsers.

Add support for Apple Silicon

We currently don't produce a target binary for apple silicon (i.e. arm64).

This should hopefully be a simple addition to the CI pipline matrix. However the current worflow in the CI pipeline makes certain assumptions that macOS is a single architecture, and therefore may need somne light refactoring.

JS C@E build error "too much recursion"

A customer raised an issue in the CLI repo here:
fastly/cli#361

I'll be investigating why the CLI didn't stop the 'build' process once Wiser had reported an error, but I believe the rest of the comments in that issue are best discussed here.

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.