diff --git a/.circleci/config.yml b/.circleci/config.yml index aacc8bb..3d41d2a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,3 +34,9 @@ jobs: cd tests/examples/react-app yarn install bazel build ... + - run: + name: Build Dockerized TypeScript Node example + command: | + cd examples/node-typescript-app + bazel build //... + bazel run //services/my-service:image diff --git a/WORKSPACE b/WORKSPACE index 7b8556f..4faa40b 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -9,3 +9,9 @@ git_repository( load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories") node_repositories(package_json = []) + +# See https://github.com/bazelbuild/bazel/issues/2460#issuecomment-362284757 +local_repository( + name = "ignore_examples", + path = "./examples", +) diff --git a/examples/WORKSPACE b/examples/WORKSPACE new file mode 100644 index 0000000..0a9d7ad --- /dev/null +++ b/examples/WORKSPACE @@ -0,0 +1 @@ +# See https://github.com/bazelbuild/bazel/issues/2460#issuecomment-362284757 diff --git a/examples/node-typescript-app/BUILD.bazel b/examples/node-typescript-app/BUILD.bazel new file mode 100644 index 0000000..86be255 --- /dev/null +++ b/examples/node-typescript-app/BUILD.bazel @@ -0,0 +1,11 @@ +package(default_visibility = ["//visibility:public"]) + +exports_files(["tsconfig.json"]) + +load("@bazel_javascript//:defs.bzl", "npm_packages") + +npm_packages( + name = "packages", + package_json = ":package.json", + yarn_lock = ":yarn.lock", +) diff --git a/examples/node-typescript-app/README.md b/examples/node-typescript-app/README.md new file mode 100644 index 0000000..1c9cd9d --- /dev/null +++ b/examples/node-typescript-app/README.md @@ -0,0 +1,12 @@ +# Dockerized Node server in TypeScript + +This directory contains a Docker image with a Node server built from TypeScript with Bazel. + +A few things worth noting: +- `tsconfig.json` must have `allowSyntheticDefaultImports` set to `false` +- We generate source maps and run `node -r source-map-support/register` so error stack traces + match the TypeScript source. +- We don't use any TypeScript aliases, because they will remain as such and confuse Node. This + could be fixed by re-introducing preprocessing which was removed in [d81c2e3](https://github.com/zenclabs/bazel-javascript/commit/d81c2e3f130fe09348952963d58fe560a416e5da). +- We use a symlinked directory to ensure `node_modules` is available to Node. +- `WORKSPACE` needs to be edited to include the remote, not local version of `bazel_javascript`. diff --git a/examples/node-typescript-app/WORKSPACE b/examples/node-typescript-app/WORKSPACE new file mode 100644 index 0000000..04208c3 --- /dev/null +++ b/examples/node-typescript-app/WORKSPACE @@ -0,0 +1,49 @@ +# Note: We use a local version of bazel-javascript rules here. +# +# You should remove this and use the remote version below instead. +local_repository( + name = "bazel_javascript", + path = "../..", +) + +# git_repository( +# name = "bazel_javascript", +# remote = "https://github.com/zenclabs/bazel-javascript.git", +# tag = , +# ) + +git_repository( + name = "build_bazel_rules_nodejs", + remote = "https://github.com/bazelbuild/rules_nodejs.git", + tag = "0.10.0", +) + +load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories") + +node_repositories( + package_json = [], +) + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "io_bazel_rules_docker", + sha256 = "5d64414477ffe87b16e248986c0731aee821ea3d626121cfeeec4ef7096812ca", + strip_prefix = "rules_docker-0.5.0", + urls = ["https://github.com/bazelbuild/rules_docker/archive/v0.5.0.tar.gz"], +) + +load( + "@io_bazel_rules_docker//container:container.bzl", + "container_pull", + container_repositories = "repositories", +) + +container_repositories() + +container_pull( + name = "node_alpine_image", + registry = "index.docker.io", + repository = "library/node", + tag = "8.11.3-alpine", +) diff --git a/examples/node-typescript-app/libs/shared-package/BUILD.bazel b/examples/node-typescript-app/libs/shared-package/BUILD.bazel new file mode 100644 index 0000000..382a702 --- /dev/null +++ b/examples/node-typescript-app/libs/shared-package/BUILD.bazel @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +load("@bazel_javascript//:defs.bzl", "ts_library") + +ts_library( + name = "shared-package", + srcs = glob(["**/*.ts"]), + tsconfig = "//:tsconfig.json", +) diff --git a/examples/node-typescript-app/libs/shared-package/greeter.ts b/examples/node-typescript-app/libs/shared-package/greeter.ts new file mode 100644 index 0000000..ae9dfa6 --- /dev/null +++ b/examples/node-typescript-app/libs/shared-package/greeter.ts @@ -0,0 +1,3 @@ +export function greet(name: string): string { + return `Hello, ${name}`; +} diff --git a/examples/node-typescript-app/package.json b/examples/node-typescript-app/package.json new file mode 100644 index 0000000..91e1512 --- /dev/null +++ b/examples/node-typescript-app/package.json @@ -0,0 +1,10 @@ +{ + "name": "node-typescript-app", + "version": "1.0.0", + "dependencies": { + "@types/koa": "^2.0.46", + "@types/node": "^10.7.1", + "koa": "^2.5.2", + "source-map-support": "^0.5.9" + } +} diff --git a/examples/node-typescript-app/services/base-image/BUILD.bazel b/examples/node-typescript-app/services/base-image/BUILD.bazel new file mode 100644 index 0000000..5a667b5 --- /dev/null +++ b/examples/node-typescript-app/services/base-image/BUILD.bazel @@ -0,0 +1,11 @@ +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") + +## The Backend Base Image +container_image( + name = "service", + base = "@node_alpine_image//image:image", + stamp = True, + workdir = "/app", +) diff --git a/examples/node-typescript-app/services/my-service/BUILD.bazel b/examples/node-typescript-app/services/my-service/BUILD.bazel new file mode 100644 index 0000000..2c464ad --- /dev/null +++ b/examples/node-typescript-app/services/my-service/BUILD.bazel @@ -0,0 +1,37 @@ +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") + +container_image( + name = "image", + base = "//services/base-image:service", + data_path = ".", + directory = "/app", + files = [ + "//:packages", + "//services/my-service/server:server_compiled", + ], + symlinks = { + "/app/node_modules": "/app/packages_installed_dir/node_modules", + }, + cmd = [ + "node", + "-r", + "source-map-support/register", + "server/server_compiled/services/my-service/server/server.js", + ], + ports = [ + "3000", + ], + stamp = True, +) + +container_push( + name = "publish", + format = "Docker", + image = ":image", + registry = "my.repo.com", + repository = "my-service", + stamp = True, + tag = "{BUILD_USER}", +) diff --git a/examples/node-typescript-app/services/my-service/server/BUILD.bazel b/examples/node-typescript-app/services/my-service/server/BUILD.bazel new file mode 100644 index 0000000..d8b69d8 --- /dev/null +++ b/examples/node-typescript-app/services/my-service/server/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +load("@bazel_javascript//:defs.bzl", "ts_library") + +ts_library( + name = "server", + srcs = glob(["**/*.ts"]), + tsconfig = "//:tsconfig.json", + deps = [ + "//:packages", + "//libs/shared-package", + ], +) diff --git a/examples/node-typescript-app/services/my-service/server/server.ts b/examples/node-typescript-app/services/my-service/server/server.ts new file mode 100644 index 0000000..dd5aaff --- /dev/null +++ b/examples/node-typescript-app/services/my-service/server/server.ts @@ -0,0 +1,15 @@ +import * as Koa from "koa"; +import { greet } from "../../../libs/shared-package/greeter"; + +const app = new Koa(); + +app.use(async ctx => { + ctx.body = greet("World"); + // Just for fun, add a small chance of crashing. This allows us to check whether stack + // traces are readable. + if (Math.random() < 0.1) { + throw new Error("Random crash."); + } +}); + +app.listen(3000, () => console.log("Server is ready.")); diff --git a/examples/node-typescript-app/tsconfig.json b/examples/node-typescript-app/tsconfig.json new file mode 100644 index 0000000..c76b808 --- /dev/null +++ b/examples/node-typescript-app/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "es2015", + "module": "commonjs", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "jsx": "react", + "allowSyntheticDefaultImports": false + } +} diff --git a/examples/node-typescript-app/yarn.lock b/examples/node-typescript-app/yarn.lock new file mode 100644 index 0000000..7c1acd9 --- /dev/null +++ b/examples/node-typescript-app/yarn.lock @@ -0,0 +1,335 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/accepts@*": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" + dependencies: + "@types/node" "*" + +"@types/body-parser@*": + version "1.17.0" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c" + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.32" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" + dependencies: + "@types/node" "*" + +"@types/cookies@*": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.1.tgz#f9f204bd6767d389eea3b87609e30c090c77a540" + dependencies: + "@types/connect" "*" + "@types/express" "*" + "@types/keygrip" "*" + "@types/node" "*" + +"@types/events@*": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86" + +"@types/express-serve-static-core@*": + version "4.16.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz#fdfe777594ddc1fe8eb8eccce52e261b496e43e7" + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/range-parser" "*" + +"@types/express@*": + version "4.16.0" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.0.tgz#6d8bc42ccaa6f35cf29a2b7c3333cb47b5a32a19" + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/serve-static" "*" + +"@types/http-assert@*": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.3.0.tgz#5e932606153da28e1d04f9043f4912cf61fd55dd" + +"@types/keygrip@*": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.1.tgz#ff540462d2fb4d0a88441ceaf27d287b01c3d878" + +"@types/koa-compose@*": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.2.tgz#dc106e000bbf92a3ac900f756df47344887ee847" + +"@types/koa@^2.0.46": + version "2.0.46" + resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.0.46.tgz#24bc3cd405d10fcde81f876cd8285b44d4ddc3e9" + dependencies: + "@types/accepts" "*" + "@types/cookies" "*" + "@types/events" "*" + "@types/http-assert" "*" + "@types/keygrip" "*" + "@types/koa-compose" "*" + "@types/node" "*" + +"@types/mime@*": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.0.tgz#5a7306e367c539b9f6543499de8dd519fac37a8b" + +"@types/node@*", "@types/node@^10.7.1": + version "10.7.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.7.1.tgz#b704d7c259aa40ee052eec678758a68d07132a2e" + +"@types/range-parser@*": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.2.tgz#fa8e1ad1d474688a757140c91de6dace6f4abc8d" + +"@types/serve-static@*": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48" + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + +accepts@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + +cache-content-type@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" + dependencies: + mime-types "^2.1.18" + ylru "^1.2.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +content-disposition@~0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +cookies@~0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" + dependencies: + depd "~1.1.1" + keygrip "~1.0.2" + +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@^1.1.2, depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +destroy@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +error-inject@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +fresh@~0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +http-assert@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" + dependencies: + deep-equal "~1.0.1" + http-errors "~1.6.1" + +http-errors@^1.6.3: + version "1.7.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.0.tgz#b6d36492a201c7888bdcb5dd0471140423c4ad2a" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.1: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +is-generator-function@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + +keygrip@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91" + +koa-compose@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + dependencies: + any-promise "^1.1.0" + +koa-compose@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + +koa@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.5.2.tgz#f2bda7f3e70be54924e7e5e9789a249f77256fe3" + dependencies: + accepts "^1.3.5" + cache-content-type "^1.0.0" + content-disposition "~0.5.2" + content-type "^1.0.4" + cookies "~0.7.1" + debug "^3.1.0" + delegates "^1.0.0" + depd "^1.1.2" + destroy "^1.0.4" + error-inject "^1.0.0" + escape-html "^1.0.3" + fresh "~0.5.2" + http-assert "^1.3.0" + http-errors "^1.6.3" + is-generator-function "^1.0.7" + koa-compose "^4.1.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + on-finished "^2.3.0" + only "~0.0.2" + parseurl "^1.3.2" + statuses "^1.5.0" + type-is "^1.6.16" + vary "^1.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + +mime-types@^2.1.18, mime-types@~2.1.18: + version "2.1.19" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + dependencies: + mime-db "~1.35.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +on-finished@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +only@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + +parseurl@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +source-map-support@^0.5.9: + version "0.5.9" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + +type-is@^1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +ylru@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f"