Coder Social home page Coder Social logo

gobble's Introduction

gobble Travis Build Status

the last build tool you'll ever need

Quick start

Install gobble-cli...

npm install -g gobble-cli

...then create a gobblefile.js build definition in your project's root directory. Then, run gobble:

gobble

Why another build tool?

There are many good reasons! Here are a few.

Docs

Plugins

Search for 'gobble' on npm to find plugins: https://www.npmjs.org/search?q=gobble

Caveats

Gobble is still in active development, and may not be ready for primetime yet - APIs may change, and huge swathes of documentation are currently missing. Bear with me!

License

MIT Licensed. Copyright 2014 Rich Harris.

gobble's People

Contributors

alastaircoote avatar evs-chris avatar flaise avatar heavyk avatar ivansanchez avatar lukescott avatar martinkolarik avatar popovichn avatar rich-harris avatar trysound 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

gobble's Issues

Consolidate logging

This is sort of a feature request. gobble-cli has a great logger. The code in grunt-gobble seems very similar. I'm using gulp to kick off the build process, and this is currently what I'm doing:

gulp.task("build", function(cb) {
    var logger = require("gobble-cli/lib/utils/logger")
    var node = require("./gobblefile.js");
    var task = node.build({
        dest: "dist",
        force: true
    });

    task.catch( function ( err ) {
        logger.error( err );
        cb();
    });

    task.on("info",  logger.info);
    task.on("error", logger.error);

    task.on("complete", function() {
        cb();
    });
});

I'm cheating a bit by including gobble-cli's logger ๐Ÿ˜…. And much of the code is inspired from the cli. It would be nice if you could do something like this instead:

gulp.task("build", function(cb) {
    require("./gobblefile.js").build({
        dest: "dist",
        force: true,
        logger: true
    }, cb); // <-- cb: let gulp know when finished
});

I know it's not that great of reduction line wise, but it makes the API more friendly. This would help out a great deal with many CI/CLI tools that may integrate gobble.

Gobble doesn't re-serve after error

Got a transpile error like below. Fixed file, got GOBBLE INFO 1 file changed, but then localhost just hangs

An error occurred while processing /Users/marty/ractive/test/modules/events.js:
Errors transpiling code: ["line 707: reference to unknown global variable Instance"]
------------
stack trace:
Error: Errors transpiling code: ["line 707: reference to unknown global variable Instance"]
    at Object.es6transpiler [as fn] (/Users/marty/ractive/node_modules/gobble-es6-transpiler/index.js:10:9)
    at /Users/marty/ractive/node_modules/gobble/lib/builtins/map.js:51:26
    at EventEmitter.run._run (/Users/marty/ractive/node_modules/gobble/lib/queue/Queue.js:16:3)
    at EventEmitter.Queue.add (/Users/marty/ractive/node_modules/gobble/lib/queue/Queue.js:28:8)
    at /Users/marty/ractive/node_modules/gobble/lib/builtins/map.js:49:13
    at invokeResolver (/Users/marty/ractive/node_modules/gobble/node_modules/promo/node_modules/es6-promise/dist/commonjs/promise/promise.js:41:5)
    at new Promise (/Users/marty/ractive/node_modules/gobble/node_modules/promo/node_modules/es6-promise/dist/commonjs/promise/promise.js:28:3)
    at /Users/marty/ractive/node_modules/gobble/lib/builtins/map.js:46:13
    at invokeCallback (/Users/marty/ractive/node_modules/gobble/node_modules/promo/node_modules/es6-promise/dist/commonjs/promise/promise.js:53:15)
    at publish (/Users/marty/ractive/node_modules/gobble/node_modules/promo/node_modules/es6-promise/dist/commonjs/promise/promise.js:98:5)
    at publishFulfillment (/Users/marty/ractive/node_modules/gobble/node_modules/promo/node_modules/es6-promise/dist/commonjs/promise/promise.js:204:3)

Errors get reported multiple times

Error propagation needs a bit of a refactoring, generally speaking. The various error codes used internally (and externally, e.g. by gobble-cli) should be documented and tested

Flatten sourcemaps lazily when serving

As mentioned here, it'd be great if the sourcemap flattening process happened in the background when gobble is serving. Rather than proactively searching all the built files to see if they have sourcemap chains that need flattening, gobble could wait for a request from the browser and do it then, which would provide a nice boost to perceived speed with sacrificing any of that sourcemappy goodness.

For gobble watch and gobble build it would still need to be proactive though.

6to5 with undefined require

So I'm trying to setup gobble with 6to5 and pretty confused on how to get it working properly. My gobble file is fine and handling the transpiling. I have an index.html where i load requirejs via bower and then load app.js which is the transpiled version coming from http://localhost:4567. I see require is not defined when i exclude requirejs. I see require.js:174 Uncaught Error: Module name "test" has not been loaded yet for context: _. Use require([]) when I load app.js from localhost with requirejs.

a) should i be loading index.html file from my filesystem and connecting to assets via gobble localhost? or should i have it within the localhost gobble generates.
b) Is requirejs required for the require definition?
c) what is a good practice because i couldn't find much information on a proper setup.

Thanks!

gobbledir isn't cleaned up after successful builds

Previously, transformer/merger nodes would clean themselves up after each successful build. That's no longer happening, and it means a) the .gobble directory gets huge, and b) it can take a few seconds to clean it up the next time you start gobbling.

Flatten sourcemap chains automatically?

If you have multiple transformations that each generate sourcemaps...

node = gobble( 'src/coffee' )
  .transform( 'coffee' )
  .transform( 'concat' ) // this plugin doesn't actually generate sourcemaps... yet
  .transform( 'uglify' );

...then the sourcemap that gets generated by the uglify plugin only refers to the output of the concat step, rather than the original CoffeeScript. You can (in theory, it hasn't been widely battle-tested yet) fix this with gobble-sorcery...

node = gobble( 'src/coffee' )
  .transform( 'coffee' )
  .transform( 'concat' )
  .transform( 'uglify' )
  .transform( 'sorcery' );

...but that's kind of a nuisance, and goes against the 'Sourcemaps Just Work' aspiration. Am wondering whether the equivalent transformation should happen automatically. The worst that can happen (again, in theory...) is that a few milliseconds are wasted on a) redundant transformations, or b) transformations that the user doesn't take advantage of, for whatever reason.

Haven't made up my mind yet so will just leave this here.

Issue watching already minified files

Lets say I have a source folder with already minified js files:

|--src
   |--js    
      |--ractive.min.js
|--gobblefile.js   

And your gobble file is setup to just copy the already minified file:

var gobble = require("gobble");
module.exports = gobble("src");

Then run gobble watch out

You'll get a ENOENT error looking for a .map file.

If you manually add the map file:

|--src
   |--js    
      |--ractive.min.js
      |--ractive.min.js.map
|--gobblefile.js   

You'll remove the error, but it'll continually invalidate the build over and over

tshannon@git:~/workspace/test$ gobble watch out
gobble: build completed in 5037ms. Listening for changes...

gobble:



build invalidated (2 files changed). restarting
gobble: build completed in 4509ms. Listening for changes...

gobble:



build invalidated (2 files changed). restarting
gobble: build completed in 4458ms. Listening for changes...

gobble:



build invalidated (2 files changed). restarting
gobble: build completed in 3683ms. Listening for changes...

gobble:



build invalidated (2 files changed). restarting
gobble: build completed in 4205ms. Listening for changes...

gobble:

Changing files rapidly causes build to fail

I believe this is a regression - fairly sure this used to work. If you hammer Cmd-S (or Ctrl-S, if you're one of those people), it's easy to cause gobble to fall over - something about waiting forever for the first build (aborted by the start of the second one) to finish.

Better sourcemap source resolution

A sourcemap source is the first file that doesn't have an associated sourcemap, but that means that if you have a build like this...

module.exports = gobble( 'src' )
  .grab( 'js' )
  .exclude( 'whatever.js' )
  .transform( 'babel' );

...then as far as babel is concerned, the source files are .gobble/02-exclude/[files].js. So that's what shows up in the sources pane in-browser.

Since gobble now owns the sourcemap pipeline, it'd be nice to fix those so that the correct sources are revealed, at least on a best effort basis. On OS X it would be easy enough to just trace the symlinks back to their origin (since in the majority of cases, they will be symlinks to files in an original source dir), but that doesn't work on Windows where symlinks can't be used. So it might take a slightly more sophisticated approach. Perhaps if we store checksums of all the source files, then we can read any sources in the final sourcemaps that live inside .gobble, find their checksums, and match them up.

Gobble a single file?

Gobble will currently fuss at you if you try to gobble a single file, but I may have a use-case for doing so with my toy dependency fetcher giblets. It wants to watch a single config file and pull in directories for each listed dependency, but it is currently required to keep that config file in its own (or at least some non-root) directory for gobbling.

Question - global gobble?

The documentation implies (although I may be misunderstanding) that you should install gobble globally npm install -g gobble-cli , but after installing globally I can't run my gobblefile as I get this error:

gobble: could not find a local copy of gobble. You should probably install it with npm install --save-dev gobble

Should it be run locally or globally?

Transform context

It might be handy to have transforms called with a context that gives them automagic access to the gobble instance that is calling them (in my case for env()). Also handy would be a way to log what's going on in a gobble-friendly in the midst of a long-ish-running transform. Perhaps something like this.log()? console.log is not very pretty jumping in between all the pacman dots :-)

More broken gobble

Dead in the water using gobble-cli 0.4.0. Have rm -rf node_modules as well as same on gobble-cli in global bin. :(

RangeError: Invalid array length
    at /Users/marty/npm/lib/node_modules/gobble-cli/lib/utils/logger.js:54:19
    at Array.forEach (native)
    at indent (/Users/marty/npm/lib/node_modules/gobble-cli/lib/utils/logger.js:50:8)
    at warn (/Users/marty/npm/lib/node_modules/gobble-cli/lib/utils/logger.js:30:26)
    at Object.logger.warn (/Users/marty/npm/lib/node_modules/gobble-cli/lib/utils/logger.js:349:4)
    at Liftoff.<anonymous> (/Users/marty/npm/lib/node_modules/gobble-cli/lib/index.js:88:11)
    at Liftoff.<anonymous> (/Users/marty/npm/lib/node_modules/gobble-cli/node_modules/liftoff/index.js:159:12)
    at module.exports (/Users/marty/npm/lib/node_modules/gobble-cli/node_modules/liftoff/node_modules/flagged-respawn/index.js:17:3)
    at Liftoff.launch (/Users/marty/npm/lib/node_modules/gobble-cli/node_modules/liftoff/index.js:152:5)
    at Object.<anonymous> (/Users/marty/npm/lib/node_modules/gobble-cli/lib/index.js:68:6)

Connect middleware support

It seems like an obvious case to attach gobble into an express app (or anything otherwise connect-enabled):

var gobble = require('gobble/middleware');

app = express();
app.use('/assets', gobble());
app.use('/assets', gobble({ config: 'config/gobblefile.js' ));
app.listen(4000, function () { ... });

Source maps

Going to open this issue before someone else does - one-to-one file transformers need to be able to support source maps somehow.

Not sure what that looks like, but it'd be a shame if plugin authors were to forgo the benefits of file transformers (i.e. using directory transformers instead, so they could read and write source maps) when doing file -> file-plus-sourcemap transforms (or file-plus-sourcemap -> file-plus-sourcemap).

Intermittently getting ENOENT error

This just happens from time to time:

GOBBLE INFO    1 file changed
GOBBLE ERROR   07-merge transformation failedn running...
============
ENOENT, stat '/Users/marty/ractive/.gobble/04-es6transpiler/1/promises-aplus-adaptor.js'
------------
stack trace:
Error: ENOENT, stat '/Users/marty/ractive/.gobble/04-es6transpiler/1/promises-aplus-adaptor.js'
============

wiredep

I noticed there is no wiredep plug-in. Could you provide an example of how I should use wiredep?

Gobble fails on nonexistent folder

Shouldn't kill gobble on bad directory?

GOBBLE WARNING The 'assets/js/vendor' directory does not exist!
GOBBLE INFO    59-sassFilter transformation finished in 15ms
GOBBLE INFO    60-myplugin transformation finished in 1ms
GOBBLE INFO    61-ractive transformation finished in 6ms
GOBBLE INFO    55-include transformation finished in 1ms
GOBBLE INFO    56-es6transpiler transformation finished in 14ms
GOBBLE INFO    62-merge finished in 3ms
GOBBLE INFO    63-browserify transformation finished in 990ms
GOBBLE INFO    58-sass transformation finished in 4ms
TypeError: Cannot read property 'length' of undefined
    at /Users/marty/ractive-project/node_modules/gobble/lib/file/ls.js:24:25
    at ReaddirReq.Req.done (/Users/marty/ractive-project/node_modules/gobble/node_modules/graceful-fs/graceful-fs.js:141:5)
    at ReaddirReq.done (/Users/marty/ractive-project/node_modules/gobble/node_modules/graceful-fs/graceful-fs.js:88:22)
    at Object.oncomplete (fs.js:107:15)

0.9.0 broken, cannot find directory ./lib ?

gobble: error starting gobble

Cannot find module './lib'
Error: Cannot find module './lib'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object. (./node_modules/gobble/index.js:2:18)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:364:17)
<<<

Adding Mocha within Gobble

Is there a way to run mocha tests within Gobble? So a build would re-run tests when changes happened.

Sublime crashes

It seems that Sublime Text 3 can't cope with a lot of file changes at the same time. Not sure what exactly is going on, but it's fairly annoying - with large projects, it'll just die (no error message etc, the windows just disappear) every few times you run gobble.

Save checksums between builds, and extend checksum check to all transforms

Idea from @evs-chris (see ractivejs/ractive#1544 (comment)). Currently, the built-in map transformer (which orchestrates one-to-one file transformations) calculates a checksum of each input file, and sees if it matches the last checksum - if so, the transformation isn't repeated. (This might seem inefficient compared to e.g. checking timestamps, but it's intrinsically more reliable and turns out to be very fast).

This could happen in a more structured way - the check could happen before each transformation, and if it turned out that nothing had actually changed, none of the downstream transformations would need to be re-run. I think it's likely that the time saved on unnecessary transformations would outweigh the cost of performing the check. Transformers could potentially use this information themselves, if it was exposed as this.changes or similar (e.g. gobble-concat could simply reuse the previous result if the list of changes didn't include any of the files to be concatenated).

Furthermore, the results of the check could be saved to disk. That way, as long as the temporary files weren't discarded between builds (i.e. no-one deletes the .gobble folder), it ought to be possible to drastically cut down the duration of cold builds (because they wouldn't actually be cold).

Possible to run a build watch instead of a server?

I like the concepts in Gobble and how they are presented. But I am having difficulty finding how to support my use-case. I already have a web server for my build process. What I need from Gobble is just a fast build server, i.e. just the watch feature. Is this possible? Or perhaps in the works?

Just for reference, I am thinking along the lines of what some are requesting to be done with the Broccoli CLI.

Appreciate the help.

`gobble --help`

It seems pretty reasonable to expect this to work :) Right now it seems to spawn up node --help.

Does an observer node make sense?

Something that can participate in the build process but doesn't necessarily produce any files. For instance, running a node app or linting. Using a directory transform means you either copy all of the files or leave the output empty and have a node that can't go any further.

For running a server, the directory transform approach seems to be ok, since you typically don't care so much about the output once it's kicked off. It might be pretty handy for a linter though, so it could fail the build and just pass its input dir downstream.

Or have I strayed too far from build tool into task runner territory?

Getting 404s on sourcemaps

Recently with our builds we've been getting 404s on all of our sourcemaps. I tried clearing out .gobble, .gobble-build and also node_modules/.bin/gobble but haven't had any luck solving the problem. I saw another issue recently posted about sourcemaps and was wondering if it was related? Looking for any kind of help since we can't debug right now :)

EEXIST with chained sourcemaps

Don't fully understand how this only showed up just now, but there seems to be some conflict that happens sometimes when two map transformations generate sourcemaps. Most likely related to this change.

More fun with sourcemaps

Automatic sourcemap flattening, introduced in 0.8, is great when it works. When it doesn't work, it's more of a nuisance than anything.

Two problems in particular have become fairly obvious:

  • It currently looks at all output files to try to flatten sourcemaps, when it should only really be looking at .js and .css files. (This became painfully clear when gobble tried to find sourcemap comments in several hundred megabytes of images...)
  • The trick of storing sourcemaps in memory, rather than with sourceMappingURL comments, doesn't work too well when sourcemap-generating transforms are mixed with non-sourcemap-generating transforms (such as merger nodes, .include() and other built-ins, gobble-derequire and so on), because sorcery can't find the sourcemap. Comments do at least persist across non-sourcemap-generating transform boundaries.

Am playing around with some fixes, all very WIP. Ironically the more I fight this stuff the more convinced I am that automatically flattening sourcemaps is the right thing to do - they're just such a massive pain to set up. Just need to concoct a medicine that isn't worse than the disease.

I suspect #63 is related as well.

Directory transformer function signature - one callback or two?

Am creating this issue so that I can link to it from documentation etc.

Right now, the directory transformer function signature looks like this:

function myPlugin ( inputdir, outputdir, options, callback, errback ) {
  // code goes here...
}

This is rather un-node-like. Most asynchronous node functions take a single callback that serves a dual purpose - if it's called with an argument, it's an errback, otherwise it's regular continuation passing style (CPS). The merits or otherwise of that convention are out of scope for this issue - that's how it is in node, and that's that. The question is whether Gobble should do it that way.

Motivation for the callback, errback style

Let's say we used the node convention. In simple cases where you're dealing with other functions that adhere to the CPS convention, that'd be nice and simple, because you could do

function myPlugin ( inputdir, outputdir, options, callback ) {
  // code goes here...
  fs.writeFile( path.join( outputdir, options.dest ), callback );
}

But in real life you'll want to handle the result yourself if:

  • you want to intercept the error and handle it (e.g. passing a more informative error)
  • you are writing multiple files, because no one writeFile operation can own the callback
  • you are using promises

The last of these - promises - provided the original motivation for the callback, errback style. If you had a single (dual-purpose) callback, but you were using a promise-based fs wrapper (I wrote such a thing - sander - precisely because fs is rather low-level, and becomes a bit painful once you try and do anything meaningful with it), you'd have to write code like this:

function myPlugin ( inputdir, outputdir, options, callback ) {
  // code goes here...
  sander.writeFile( outputdir, options.dest ).then( callback, callback );
}

That's weird. And if you couldn't remember whether that function resolved with a value or not, and couldn't be bothered to look it up, you'd probably do this instead to ensure that an 'error' (the value the promise resolved with) wasn't wrongly passed to the callback:

function myPlugin ( inputdir, outputdir, options, callback ) {
  // code goes here...
  sander.writeFile( outputdir, options.dest ).then( function () {
    callback();
  }, callback );
}

If callback and errback are separate, dedicated functions, that don't violate the single responsibility principle, then you'd write this instead:

function myPlugin ( inputdir, outputdir, options, callback, errback ) {
  // code goes here...
  sander.writeFile( outputdir, options.dest ).then( callback, errback );
}

In essence, callback and errback are equivalent to a promise's fulfil and reject.

I like promises...

...and as of ES6 they're the 'correct' way to handle asynchronicity in JavaScript. They're much easier to combine and manipulate, and they result in much nicer code in almost all cases. But as the code above shows, CPS and promises are at odds with each other.

Options

  1. Use the conventions of the language, i.e. promises, and make life a bit more difficult for people using regular Node functions.
  2. Use the conventions of node, and use CPS - making life more difficult for people who use promises.
  3. A hybrid approach - use a single callback, but allow plugin authors to return a promise instead (i.e. if the transformer returns a 'thenable', attach callback and errback to it, and disregard them if they're called within the transformer).

Any thoughts?

Inline sourcemaps don't get fixed

If a file transformer adds an inline sourcemap (with a data URI), it doesn't get fixed (with correct file, sources and sourcesContent information), unlike when transformers return a { code, map } object. This can cause problems with resolution later on.

Unchanged files can have the wrong extension

If you have a one-to-one transformation that changes file extensions, those files will be copied with the wrong name on transformations after the first one, if their contents don't change:

# initial build
foo.coffee -> foo.js
bar.coffee -> bar.js

# foo changes
foo.coffee -> foo.js
bar.coffee -> bar.coffee

'gobble build [dest]' doesn't bail if one of the transforms fails

When scripting with gobble using gobble build --force build, if a transform fails, gobble does not terminate. Should it terminate with a non-zero exit or provide a flag to do so?

For reference, I'm trying to have a super simple build/test script for npm test along the lines of gobble build --force build && node test/node.js while trying to simplify the Ractive build/test system.

Method for nodes to register dependencies programmatically

Gobble build definitions are defined as a sequence of transformations form source to result, rather than (as in JavaScript bundlers like webpack/browserify etc) by taking some final entry point and recursively discovering its dependencies. Generally speaking that's a more appropriate model for the (more general purpose) job Gobble is trying to do.

There are some occasions when it would be useful for a transformer to be able to declare its dependencies (that are outside its inputdir) programmatically. For example, if you have a bunch of markdown documents that you want to turn into HTML pages, you probably have an HTML template to wrap around the content:

var fs = require( 'fs' ),
    marked = require( 'marked' ),
    gobble = require( 'gobble' );

var template = fs.readFileSync( 'template.html', 'utf-8' );
var html = gobble( 'markdown' ).transform( function ( markdown ) {
  return template.replace( '__CONTENT__', marked( markdown ) );
});

In this example the html node would contain the expected result, but if you changed the template.html file, Gobble wouldn't know that it needed to re-run the transformation.

A few quick API ideas:

// synchronous `gobble.read()` function returns file contents (caches the result
// in memory so it doesn't hit the filesystem each time, obvs) and marks it
// as a dependency
var html = gobble( 'markdown' ).transform( function ( markdown ) {
  return gobble.read( 'template.html' ).replace( '__CONTENT__', marked( markdown ) );
});

// `.dependsOn(filename)` method registers dependency and returns `this`. Allows
// explictly declaring dependencies in the build definition in an efficient way, but
// doesn't allow programmatic declaration. Also, no easy caching
var html = gobble( 'markdown' ).transform( function ( markdown ) {
  var template = fs.readFileSync( 'template.html', 'utf-8' );
  return template.replace( '__CONTENT__', marked( markdown ) );
}).dependsOn( 'template.html' );

// dependency is explicity declared inside the function, webpack style. Again,
// no help with caching
var html = gobble( 'markdown' ).transform( function ( markdown ) {
  this.addDependency( 'template.html' );
  var template = fs.readFileSync( 'template.html', 'utf-8' );
  return template.replace( '__CONTENT__', marked( markdown ) );
});

// file node has a `.contents()` method which returns the contents and
// registers the dependency
var template = gobble( 'template.html' ); // depends on issue #23
var html = gobble( 'markdown' ).transform( function ( markdown ) {
  return template.contents().replace( '__CONTENT__', marked( markdown ) );
});

(A synchronous API is preferable I think, since it means it can be used with both directory and file transformers.)

None of them leap out as being The Answer - would be interested if anyone out there has any feedback. Figuring this out would mean never again having to use static site generators (which in my experience compensate for their lack of intrinsic flexibility with overwhelmingly complex configuration).

/cc @OliverJAsh and @theefer, since this is related to the stuff we were talking about a while back. Have you encountered this problem with Plumber?

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.