Giter Club home page Giter Club logo

gzip's Introduction

GZIP gin's middleware

Run Tests codecov Go Report Card GoDoc

Gin middleware to enable GZIP support.

Usage

Download and install it:

go get github.com/gin-contrib/gzip

Import it in your code:

import "github.com/gin-contrib/gzip"

Canonical example:

package main

import (
  "fmt"
  "net/http"
  "time"

  "github.com/gin-contrib/gzip"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()
  r.Use(gzip.Gzip(gzip.DefaultCompression))
  r.GET("/ping", func(c *gin.Context) {
    c.String(http.StatusOK, "pong "+fmt.Sprint(time.Now().Unix()))
  })

  // Listen and Server in 0.0.0.0:8080
  if err := r.Run(":8080"); err != nil {
    log.Fatal(err)
  }
}

Customized Excluded Extensions

package main

import (
  "fmt"
  "net/http"
  "time"

  "github.com/gin-contrib/gzip"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()
  r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedExtensions([]string{".pdf", ".mp4"})))
  r.GET("/ping", func(c *gin.Context) {
    c.String(http.StatusOK, "pong "+fmt.Sprint(time.Now().Unix()))
  })

  // Listen and Server in 0.0.0.0:8080
  if err := r.Run(":8080"); err != nil {
    log.Fatal(err)
  }
}

Customized Excluded Paths

package main

import (
  "fmt"
  "net/http"
  "time"

  "github.com/gin-contrib/gzip"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()
  r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{"/api/"})))
  r.GET("/ping", func(c *gin.Context) {
    c.String(http.StatusOK, "pong "+fmt.Sprint(time.Now().Unix()))
  })

  // Listen and Server in 0.0.0.0:8080
  if err := r.Run(":8080"); err != nil {
    log.Fatal(err)
  }
}

Customized Excluded Paths

package main

import (
  "fmt"
  "net/http"
  "time"

  "github.com/gin-contrib/gzip"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()
  r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPathsRegexs([]string{".*"})))
  r.GET("/ping", func(c *gin.Context) {
    c.String(http.StatusOK, "pong "+fmt.Sprint(time.Now().Unix()))
  })

  // Listen and Server in 0.0.0.0:8080
  if err := r.Run(":8080"); err != nil {
    log.Fatal(err)
  }
}

gzip's People

Contributors

appleboy avatar danielheckrath avatar dengoswei avatar dependabot[bot] avatar jorritsalverda avatar kishorkunal-raj avatar micanzhang avatar mkfsn avatar nickbug avatar prymitive avatar segevfiner avatar tankbusta avatar thaiwood avatar thinkerou avatar zzjin 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

gzip's Issues

Snyk vulnerability HTTP Response Splitting on older version of github.com/gin-gonic/gin

We are using the latest version of github.com/gin-contrib/[email protected] which internally uses the gin-gonic library and the version is github.com/gin-gonic/[email protected] in go.mod

This has introduced snyk vulnerability HTTP Response Splitting with the following path:
Introduced through: [email protected] › github.com/gin-contrib/[email protected] › github.com/gin-gonic/[email protected]

Snyk link issue: https://security.snyk.io/vuln/SNYK-GOLANG-GITHUBCOMGINGONICGIN-1041736

In master branch in go.mod, I see gin-gonic version has been upgraded to v1.8.1

What is the estimated date to release this master branch changes?

conflict with gin cache

I have a problem when using gin cache.
The first request serves correctly, but second request that was cached in gin cache middleware returns response with length 0

Stack overflow with Go 1.12

I've updated my local Go install to 1.12 and updated gzip with go get -u github.com/gin-contrib/gzip and am now seeing stack overflows on both Windows and Ubuntu in my Gin app.

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
runtime stack:
runtime.throw(0x12c659b, 0xe)
	C:/Go/src/runtime/panic.go:617 +0x79
runtime.newstack()
	C:/Go/src/runtime/stack.go:1041 +0x77c
runtime.morestack()
	C:/Go/src/runtime/asm_amd64.s:429 +0x97
goroutine 473 [running]:
compress/flate.(*huffmanEncoder).bitCounts(0xc000280790, 0xc000a34400, 0x67, 0x11f, 0xf, 0x0, 0x0, 0x0)
	C:/Go/src/compress/flate/huffman_code.go:134 +0x9fc fp=0xc021801658 sp=0xc021801650 pc=0x9c7ddc
compress/flate.(*huffmanEncoder).generate(0xc000280790, 0xc000ba6900, 0x11e, 0x11e, 0xc00000000f)
	C:/Go/src/compress/flate/huffman_code.go:309 +0x423 fp=0xc021801780 sp=0xc021801658 pc=0x9c8543
compress/flate.(*huffmanBitWriter).indexTokens(0xc0000021e0, 0xc000f5c000, 0x789, 0x4001, 0x116, 0x19)
	C:/Go/src/compress/flate/huffman_bit_writer.go:570 +0x4a6 fp=0xc021801868 sp=0xc021801780 pc=0x9c5f06
compress/flate.(*huffmanBitWriter).writeBlock(0xc0000021e0, 0xc000f5c000, 0x789, 0x4001, 0x0, 0xc001471576, 0x0, 0xea8a)
	C:/Go/src/compress/flate/huffman_bit_writer.go:440 +0xc6 fp=0xc0218019b0 sp=0xc021801868 pc=0x9c4ec6
compress/flate.(*compressor).writeBlock(0xc00133e000, 0xc000f5c000, 0x788, 0x4001, 0x1576, 0x0, 0x0)
	C:/Go/src/compress/flate/deflate.go:170 +0x15f fp=0xc021801a28 sp=0xc0218019b0 pc=0x9bc08f
compress/flate.(*compressor).deflate(0xc00133e000)
	C:/Go/src/compress/flate/deflate.go:415 +0x3e9 fp=0xc021801ba0 sp=0xc021801a28 pc=0x9bdc99
compress/flate.(*compressor).write(0xc00133e000, 0xc000002200, 0xeb, 0xf8, 0xeb, 0x0, 0x0)
	C:/Go/src/compress/flate/deflate.go:551 +0xdd fp=0xc021801c08 sp=0xc021801ba0 pc=0x9bf2fd
compress/flate.(*Writer).Write(0xc00133e000, 0xc000002200, 0xeb, 0xf8, 0x0, 0x0, 0x0)
	C:/Go/src/compress/flate/deflate.go:709 +0x86 fp=0xc021801c88 sp=0xc021801c08 pc=0x9c03b6
compress/gzip.(*Writer).Write(0xc001480420, 0xc000002200, 0xeb, 0xf8, 0x0, 0x0, 0x0)
	C:/Go/src/compress/gzip/gzip.go:196 +0x1ab fp=0xc021801dc8 sp=0xc021801c88 pc=0x9d265b
github.com/gin-contrib/gzip.(*gzipWriter).Write(0xc0016a3ca0, 0xc000002200, 0xeb, 0xf8, 0x0, 0x0, 0x0)
	C:/dev/go/src/github.com/gin-contrib/gzip/gzip.go:61 +0x8a fp=0xc021801e48 sp=0xc021801dc8 pc=0xfea10a
[repeating...]

I haven't identified any particular trigger for it yet, but it's happening regularly on the app under both OS's.

Vary headers gets overwritten instead of it being added.

package main

import (
	"fmt"
	"github.com/gin-contrib/gzip"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"time"
)

func main() {

	r := gin.Default()
	r.Use(func(c *gin.Context) {
		c.Writer.Header().Add("Vary", "Origin")
	}, gzip.Gzip(gzip.DefaultCompression))
	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "pong "+fmt.Sprint(time.Now().Unix()))
	})

	// Listen and Server in 0.0.0.0:8080
	if err := r.Run(":9000"); err != nil {
		log.Fatal(err)
	}

}

when running the folowing setup. i expect the Vary headers to contain
Accept-Encoding and Origin

but due to the behavior of the gzip middleware, the Vary header is being overwritten

shouldnt gzip add the the Accept-Encoding instead over overwriting it ?

feature: exclude based on original content-type

I have an API that often returns images. If the Content-Type header was originally image/jpeg (or anything starting with image/) then I'd like the response not to be gzipped. Is this possible? Thanks for providing this library!

gzip.WithExcludedPaths missing since last merge

Hi, is there any alternative to add below statement?
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{"/admin/", "/monitor/"})))

Since today, when I am trying to build, below issues occurred:

  1. Unable to fetch through dep ensure for master branch, getting below error:
    Solving failure: No versions of github.com/gin-contrib/gzip met constraints:
    v0.0.1: Could not introduce github.com/gin-contrib/[email protected], as it is not allowed by constraint master from project dailyhunt.in/ugc/groups-service.
    master: unable to update checked out version: fatal: reference is not a tree: 4b4a6f0
    : command failed: [git checkout 4b4a6f0]: exit status 128

  2. After resolving through go get, got below compilation error:
    r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{"/admin/", "/monitor/"})))

too many arguments in call to gzip.Gzip
undefined: gzip.WithExcludedPaths

Server-sent events get buffered

When using gin to send a stream of server-sent events (SSE) this middleware's buffering gets in the way so below code waits for all events to be emitted before sending the response.

r := gin.Default()

r.Use(gzip.Gzip(gzip.DefaultCompression))

r.GET("/stream", func(c *gin.Context) {
	chanStream := make(chan int, 10)
	go func() {
		defer close(chanStream)
		for i := 0; i < 5; i++ {
			chanStream <- i
			time.Sleep(time.Second * 1)
		}
	}()

	c.Stream(func(w io.Writer) bool {
		if msg, ok := <-chanStream; ok {
			c.SSEvent("message", msg)
			return true
		}
		return false
	})
})

r.Run()

Is it possible to detect that a Stream is used and bypass the buffering automatically? Now I have to resort to grouping routes and using gzip for most of them, except for the ones using this streaming functionality.

Gunzip incoming requests

Hello @appleboy I am responsible for an API developed with Gin and the incoming requests are gzip (Content-Encoding).
I realise (or I cannot find) any lib supporting this, so I need to gunzip incoming buffer before doing anything.
Would it be appropriate to do a PR into this project in order to automatically gunzip incoming bodies if Content-Encoding is set to "gzip"?

If enable the gzip middleware, the gin server returns an incorrect response for 404 status by default

Enable the gzip middleware, that 404 response like this:

HTTP/1.1 404 Not Found
Vary: Accept-Encoding
Date: Wed, 29 Dec 2021 09:44:42 GMT
Content-Length: 0

Disable the gzip middleware, that 404 response like this:

HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Wed, 29 Dec 2021 09:47:08 GMT
Content-Length: 18

404 page not found

Because of the gz.Close() will writing the GZIP footer to c.Writer.

gzip/handler.go

Lines 55 to 60 in c784c8e

c.Writer = &gzipWriter{c.Writer, gz}
defer func() {
gz.Close()
c.Header("Content-Length", fmt.Sprint(c.Writer.Size()))
}()
c.Next()

So gin will not write default404Body in serveError func.
We need to customize the gin.Engine.NoRoute that responds to the correct 404 content now.

https://github.com/gin-gonic/gin/blob/d062a6a6155236883f4c3292379ab94b1eac8b05/gin.go#L632-L637

Possible memory leak

I am not sure if this is a gzip or gin issue, but I will start here since it has to do with compression.

I have an api that is using the contrib/gzip lib, It is obviously running continuously.

After about a day the service crashes due to memory exhaustion on the host.

Using pprof I see flate.NewWriter is using 90.05% of inuse_space. I have event forked this project and swapped stock gzip for klauspost

go version go1.11.1 linux/amd64

Time: Jun 20, 2019 at 1:28pm (CDT)
Showing nodes accounting for 20518.91MB, 97.75% of 20990.94MB total
Dropped 221 nodes (cum <= 104.95MB)
flat flat% sum% cum cum%
17767.65MB 84.64% 84.64% 18902.19MB 90.05% compress/flate.NewWriter
1075.50MB 5.12% 89.77% 1134.55MB 5.40% compress/flate.(*compressor).init

Using GZIP with gin DataFromReader is not behaving correctly

I have a requirement where upon clicking a link the file gets downloaded. As the file may be large I use gin's DataFromReader so that the download can happen in chunks. But when the gzip compression is enabled, the file is getting corrupted and chrome shows some error like network error. I disabled the gzip middleware and it worked normally.

Any pointers on where to look or some configuration needs to be done for handling this correctly. Please advise.

Gzip middleware breaks Recovery middleware setting the status code

Build:

package main

import (
	"github.com/gin-contrib/gzip"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.Use(gzip.Gzip(gzip.DefaultCompression))
	r.GET("/", func(c *gin.Context) {
		panic("panic")
	})
	r.Run()
}

Run:

$ curl -v --compressed http://localhost:8080/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Accept-Encoding: deflate, gzip
> 
< HTTP/1.1 200 OK
< Content-Encoding: gzip
< Vary: Accept-Encoding
< Date: Tue, 09 Jul 2019 10:02:44 GMT
< Content-Length: 23
< Content-Type: application/x-gzip
< 
* Connection #0 to host localhost left intact

You get the following warning from Gin:

[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 200 with 500

the defect of gzip middleware

		defer func() {
			**c.Header("Content-Length", "0")**
			gz.Close()
		}()

it can't work:

  1. if want to remove header, you should use c.Header("Content-Length", "")
  2. in fact, the header couldn't be changed after data is filled. It is limited of GIN.

Another issue:
The middleware always compresses everything, even though the data is small.

Can we remove this Reset?

defer gz.Reset(io.Discard)

Reset use many cpu,because it will call memclrNoHeapPointers.

I think just use Reset when we get it from pool will be better, remove Reset(io.Discard)

What do youk think?

Gzip will compress the compressed body again

Gzip will compress the compressed body again when I use third-party handlers to handle gin context,
like httputil.ReverseProxy, promhttp.

It seems if the target HTTP server returns a gzip-compressed body, the middleware will compress it again,
which could result in the client can't decompress the response correctly.

For example, Prometheus can't scrape the target response correctly or some responses will be garbled, due to the double compression.

Though I can solve this problem by setting the gzip.WithExcludedPaths or other ExcludedOptions, I don't think it is the best way. Because sometimes we want to solve this problem more wisely and elegantly, rather than coding the ExcludedOptions hardly.

I also tried to fix this problem by myself. And past all default unit tests.

Am I welcomed to make a pr?

gin gzip is failed. maybe should fix it

please check . the same to Issue#400

Yes. I found gzip is invalid.

package main

import (
	"fmt"
	"github.com/gin-gonic/contrib/gzip"

	"github.com/gin-gonic/gin"
)
func main() {
	r := gin.Default()
	r.Use(gzip.Gzip(gzip.BestCompression))
	r.GET("/ping", func(c *gin.Context) {
		fmt.Println("return string")
		c.String(200, "welcome to china, baby")
	})
	r.Run(":80")
}

GOPATH\src\github.com\gin-gonic\contrib\gzip\gzip.go

func Gzip(level int) gin.HandlerFunc {
	return func(c *gin.Context) {

		if !shouldCompress(c.Request) {
			return
		}

		gz, err := gzip.NewWriterLevel(c.Writer, level)
		if err != nil {
			return
		}

		c.Header("Content-Encoding", "gzip")
		c.Header("Vary", "Accept-Encoding")
		c.Writer = &gzipWriter{c.Writer, gz}

		defer func() {
			c.Header("Content-Length", "0")
			gz.Close()
		}()
		c.Next()
	}
}

questions:

  1. if set
    c.Header("xxxContent-Encoding", "aaa")
    c.Header("123Content-Encoding", "aaa")
    you can track the before Http header .
    but if set
    c.Header("Content-Encodingxxxx", "aaa")
    couldn't track it
    <&emsp>
  2. couldn't find any zip information . except: Vary: Accept-Encoding
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Vary: Accept-Encoding
Date: Thu, 19 Jan 2017 07:36:37 GMT
Content-Length: 22
welcome to china, baby

gzip doesn't work

After enabling this middleware browser downloads page! and I can't see result in browser

Chinese garbled

We used the master version but response body was Chinese garbled.

main.go

r := gin.Default()
r.Use(gzip.Gzip(gzip.DefaultCompression))

response body

{"errno":101000,"msg":"�数缺失 Key: 'RequestCommentInfo.ItemID' Error:Field validation for 'ItemID' failed on the 'required' tag"}

Min GZIP value

Hi everyone, thanks for this project, great work!

I was wondering if there was an option to set a minimum value for the GZIP compression to take effect. The reason for this min value would me to prevent very small response bodies to be compressed which in some cases would make the responses even bigger.

Thanks and best regards
Marc

net::ERR_HTTP2_PROTOCOL_ERROR

Hi !

Over https with letsencrypt, I get intermittent net::ERR_HTTP2_PROTOCOL_ERROR on POST methods. Looking around, I found this could be caused by incorrectly setting the content-length. I don't have this issue when I disable the gzip middleware.

Best,
E.

GZIP isn't being used

Google Chrome's Lighthouse gives me a warning explaining that I should use text compression and that I could reduce transfer sizes by ~76%. To confirm this, I tested how large the file is on the server, and what the browser receives and they were bit for bit the same. My code is below

package main

import (
	"github.com/gin-gonic/autotls"
	"github.com/gin-gonic/gin"
	"github.com/gin-contrib/gzip"
	"fmt"
)
var (
	//Domain cannot be an IP Address, unless you are willing to sacrifice HTTPS
	domain       = "MYDOMAINNAME"
	subdirectory = ""
)

func main() {
	if domain == "" || domain == "localhost" {
		fmt.Println("Using HTTP only")
		http := gin.Default()
		http.Static("/SUB1", "./SUB1/public")
		http.Static("/SUB2", "./SUB2/public")
		http.Use(gzip.Gzip(gzip.DefaultCompression))
		http.Run(":80")
	} else {
		fmt.Println("Using HTTPS only")
		http := gin.Default()
		https := gin.Default()
		https.Static("/SUB1", "./SUB2/public")
		https.Static("/SUB2", "./SUB2/public")
		http.Use(gzip.Gzip(gzip.DefaultCompression))
		https.Use(gzip.Gzip(gzip.DefaultCompression))
		http.GET("/SUB1", func(c *gin.Context) {
			c.Redirect(302, "https://"+domain+"/SUB1")
		})
		http.GET("/SUB2", func(c *gin.Context) {
			c.Redirect(302, "https://"+domain+"/SUB2")
		})
		go autotls.Run(https, domain)
		http.Run(":80")
	}
}

go.mod: upgrade dependency github.com/gin-contrib/gzip to latest version to avoid vulnerability

We are using the latest version (github.com/gin-contrib/[email protected]) which internally uses the following library

github.com/gin-contrib/[email protected] › github.com/gin-gonic/[email protected]

This has introduced certain snyk vulnerability HTTP Response Splitting and in order to solve this issue following library version has to be upgraded to github.com/gin-gonic/[email protected] or more.

Can you please upgrade it.

Gzip makes the response larger

Hi,
I noticed that Gzip is applied to all requests. In some cases, we better off Gzip. For example, a very shot textual response with Gzip might get twice the size. For example:

Without encoding:

curl -i http://localhost:8000/ping
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Mon, 22 Oct 2018 16:37:12 GMT
Content-Length: 18

{"message":"pong"}

With encoding:

curl -H "Accept-Encoding: gzip" -i http://localhost:8000/ping 2>/dev/null --output -
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Vary: Accept-Encoding
Date: Mon, 22 Oct 2018 16:39:07 GMT
Content-Length: 42

����V�M-.NLOU�R*��KW�����b`k�el

Please advise,
Thanks!

Does this middleware (DefaultDecompressHandle) handle gzip.Close() correctly?

I'm looking at the code here:

func DefaultDecompressHandle(c *gin.Context) {
	if c.Request.Body == nil {
		return
	}
	r, err := gzip.NewReader(c.Request.Body)
	if err != nil {
		c.AbortWithError(http.StatusBadRequest, err)
		return
	}
	c.Request.Header.Del("Content-Encoding")
	c.Request.Header.Del("Content-Length")
	c.Request.Body = r
}

I don't see a close on the gzip.NewReader which the documentation says should be called. Is this handling close correctly?

ambiguous import `github.com/ugorji/go/codec`

Hi. First of all, thanks for your efforts. : D

But, this package seems to make a package dependency crash with gin-gonic.

When I import the both of "github.com/gin-contrib/gzip" and "github.com/gin-contrib/static" and run these commands (go mod vendor -v, go mod tidy, go run main.go ), I got this errors below.

build command-line-arguments: cannot load github.com/ugorji/go/codec: ambiguous import: found github.com/ugorji/go/codec in multiple modules:
        github.com/ugorji/go v1.1.4 (C:\Go\MYGOPATH\pkg\mod\github.com\ugorji\[email protected]\codec)
        github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f (C:\Go\MYGOPATH\pkg\mod\github.com\ugorji\go\[email protected])

As a solution of this problem, I tried to add replace github.com/ugorji/go => github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f.
This solution makes my project works well, but I can't sure this is a good way for such problems.

Is this an error? If it is, what should I do to solve this?

Thanks for reading.

Vulnerability on direct dependency

Hi, there is a vulnerability on the gin-gonic version used in this latest release (0.0.6)

The vulnerability is this.

Can you please upgrade it?

EDIT:
Dedendabot already opened a PR for this, look: PR-75

Event stream detection incorrect

While using the r3labs sse client, i found that this gin extension checks for event streams in the wrong way.
The request header Content-Type is checked. However SSE is Server->Client direction only, so there is no stream sent to the server.
For that reason clients sent "Accept: text/event-stream"
Wrong code is here:

strings.Contains(req.Header.Get("Content-Type"), "text/event-stream") {

See client codes:
https://github.com/r3labs/sse/blob/master/client.go#L288
and
https://github.com/go-rfc/sse/blob/master/eventsource.go#L102

Disable and update options on the fly.

Thank you for the great package.

More of a question really, is there an option to disable Gzip or change the compression level when the server is already running (avoiding restart?).

Many thanks.

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.