Compare commits
133 Commits
@now/pytho
...
@now/pytho
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
502aad7c2b | ||
|
|
b49afb61a6 | ||
|
|
d380902ad3 | ||
|
|
ffaed62094 | ||
|
|
b0adeb68fe | ||
|
|
2372832654 | ||
|
|
e6a9586b7e | ||
|
|
9687415eed | ||
|
|
49b375ed6a | ||
|
|
906dea096e | ||
|
|
3225a83084 | ||
|
|
87794cfcc5 | ||
|
|
79ad0ce0c4 | ||
|
|
fda5987465 | ||
|
|
5cfdd5a6b2 | ||
|
|
bd6e0f9f93 | ||
|
|
aa8d002309 | ||
|
|
42ce9aca86 | ||
|
|
156f596189 | ||
|
|
8acfd5bf71 | ||
|
|
76c99ebb28 | ||
|
|
5fb119b99c | ||
|
|
99b766d9cb | ||
|
|
c207cf9b40 | ||
|
|
dd00ac4621 | ||
|
|
3d18a067a0 | ||
|
|
c48571a799 | ||
|
|
6eeb6983d9 | ||
|
|
aee33f040d | ||
|
|
b100677b3b | ||
|
|
9241b3ae2f | ||
|
|
1088da6871 | ||
|
|
f7b4dd4458 | ||
|
|
fb85b6b27a | ||
|
|
2e5e9b9a6f | ||
|
|
d3cc306e5b | ||
|
|
d6c6a2a271 | ||
|
|
6171a58ae3 | ||
|
|
5a6d1a135f | ||
|
|
68deab9007 | ||
|
|
d6114e2bef | ||
|
|
5fdc55f3fb | ||
|
|
751b166536 | ||
|
|
6ffc8d97f4 | ||
|
|
67a80d6b83 | ||
|
|
934cf772bc | ||
|
|
b01a24afdb | ||
|
|
0ad75b52bf | ||
|
|
050772e78a | ||
|
|
7c05dc1420 | ||
|
|
bdd25ac727 | ||
|
|
3a27328828 | ||
|
|
c076a5620f | ||
|
|
2bd8ef9eed | ||
|
|
500014f2fc | ||
|
|
17687e9bcd | ||
|
|
90354e9fe7 | ||
|
|
6236631beb | ||
|
|
75aefdddd6 | ||
|
|
566d82e873 | ||
|
|
44ae0b654e | ||
|
|
d8cfaae596 | ||
|
|
a40e0f21ee | ||
|
|
ac1f506c98 | ||
|
|
68d5bdcf3d | ||
|
|
beb51f8c67 | ||
|
|
b881cb7111 | ||
|
|
d83bc59257 | ||
|
|
5be9f297de | ||
|
|
51d440431e | ||
|
|
7cf061122c | ||
|
|
1254368505 | ||
|
|
9d4b830c5f | ||
|
|
37401b4363 | ||
|
|
10fe08e14f | ||
|
|
0ecdb35d50 | ||
|
|
caee8fe9ef | ||
|
|
7d92c27b2d | ||
|
|
701eabbaba | ||
|
|
e74a1b2d1a | ||
|
|
e087b02333 | ||
|
|
eea7f902b5 | ||
|
|
db7583201b | ||
|
|
023001a8b1 | ||
|
|
4ff8ab2435 | ||
|
|
d2cccbfce6 | ||
|
|
970e6c400c | ||
|
|
b4cb7345a1 | ||
|
|
7e75d8c1a3 | ||
|
|
a4ea551160 | ||
|
|
f56ad447a0 | ||
|
|
7656422057 | ||
|
|
afa2231add | ||
|
|
21fe0a2006 | ||
|
|
23acd3cec6 | ||
|
|
7892f88a42 | ||
|
|
aae0e3bec7 | ||
|
|
0f8bf39421 | ||
|
|
36fd96cc6c | ||
|
|
3de08e9f3b | ||
|
|
3e739724b3 | ||
|
|
847e538c69 | ||
|
|
64684dd486 | ||
|
|
a229747249 | ||
|
|
d1b59c3543 | ||
|
|
b241441e37 | ||
|
|
40bfa25b1b | ||
|
|
c5a4386c1d | ||
|
|
b3aa3be4b8 | ||
|
|
528aefcc1e | ||
|
|
620ee2b7e4 | ||
|
|
d55acc246a | ||
|
|
2a59db3029 | ||
|
|
990dec0fec | ||
|
|
162b17b249 | ||
|
|
e0aea30618 | ||
|
|
49cba94178 | ||
|
|
7dd87815f3 | ||
|
|
f6fdde816f | ||
|
|
4c8c6ff236 | ||
|
|
46b615a963 | ||
|
|
8e293dd633 | ||
|
|
e040753b27 | ||
|
|
463aaf094d | ||
|
|
bf867b028d | ||
|
|
6dfefc2fe4 | ||
|
|
9ba8a8454c | ||
|
|
9c72839bfa | ||
|
|
2e24c92799 | ||
|
|
fa98c8aeeb | ||
|
|
f92e3496b1 | ||
|
|
0ceea76aa4 | ||
|
|
897d11a1e1 |
@@ -63,9 +63,6 @@ jobs:
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Installing apt dependencies
|
||||
command: sudo apt install -y rsync
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@@ -343,6 +340,10 @@ jobs:
|
||||
- run:
|
||||
name: Running Unit Tests
|
||||
command: yarn test-unit --clean false
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- packages/now-cli/.nyc_output
|
||||
|
||||
coverage:
|
||||
docker:
|
||||
@@ -352,12 +353,6 @@ jobs:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Compiling `now dev` HTML error templates
|
||||
command: node packages/now-cli/scripts/compile-templates.js
|
||||
- run:
|
||||
name: Run unit tests
|
||||
command: yarn workspace now run test-unit
|
||||
- run:
|
||||
name: Run coverage report
|
||||
command: yarn workspace now run coverage
|
||||
|
||||
@@ -4,6 +4,9 @@ dist
|
||||
# gatsby-plugin-now
|
||||
packages/gatsby-plugin-now/test/fixtures
|
||||
|
||||
# now-build-utils
|
||||
packages/now-build-utils/test/fixtures
|
||||
|
||||
# now-cli
|
||||
packages/now-cli/@types
|
||||
packages/now-cli/download
|
||||
|
||||
2
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
node_modules
|
||||
package-lock.json
|
||||
dist
|
||||
.vscode
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.nyc_output
|
||||
@@ -18,3 +19,4 @@ packages/now-cli/test/dev/fixtures/08-hugo/hugo
|
||||
packages/now-cli/test/dev/fixtures/**/dist
|
||||
packages/now-cli/test/dev/fixtures/**/public
|
||||
packages/now-cli/test/fixtures/integration
|
||||
.DS_Store
|
||||
|
||||
@@ -6,7 +6,7 @@ A Runtime is an npm module that exposes a `build` function and optionally an `an
|
||||
Official Runtimes are published to [npmjs.com](https://npmjs.com) as a package and referenced in the `use` property of the `now.json` configuration file.
|
||||
However, the `use` property will work with any [npm install argument](https://docs.npmjs.com/cli/install) such as a git repo url which is useful for testing your Runtime.
|
||||
|
||||
See the [Runtimes Documentation](https://zeit.co/docs/v2/advanced/runtimes) to view example usage.
|
||||
See the [Runtimes Documentation](https://zeit.co/docs/runtimes) to view example usage.
|
||||
|
||||
## Runtime Exports
|
||||
|
||||
@@ -283,15 +283,15 @@ This is a [JavaScript class](https://developer.mozilla.org/en-US/docs/Web/JavaSc
|
||||
|
||||
This is an abstract enumeration type that is implemented by one of the following possible `String` values:
|
||||
|
||||
- `nodejs12.x`
|
||||
- `nodejs10.x`
|
||||
- `nodejs8.10`
|
||||
- `go1.x`
|
||||
- `java-1.8.0-openjdk`
|
||||
- `java11`
|
||||
- `python3.8`
|
||||
- `python3.6`
|
||||
- `python2.7`
|
||||
- `dotnetcore2.1`
|
||||
- `dotnetcore2.0`
|
||||
- `dotnetcore1.0`
|
||||
- `ruby2.5`
|
||||
- `provided`
|
||||
|
||||
## JavaScript API
|
||||
|
||||
|
||||
28
changelog.js
@@ -12,7 +12,31 @@ if (!commit) {
|
||||
throw new Error('Unable to find last publish commit');
|
||||
}
|
||||
|
||||
const log = execSync(`git log --pretty=format:"- %s [%an]" ${commit}...HEAD`).toString().trim();
|
||||
const log =
|
||||
execSync(`git log --pretty=format:"- %s [%an]" ${commit}...HEAD`)
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(line => !line.startsWith('- Publish Canary '))
|
||||
.join('\n') || 'NO CHANGES DETECTED';
|
||||
|
||||
console.log(`Changes since the last publish commit ${commit}:`);
|
||||
console.log(`Changes since the last Stable release (${commit.slice(0, 7)}):`);
|
||||
console.log(`\n${log}\n`);
|
||||
|
||||
const pkgs =
|
||||
Array.from(
|
||||
new Set(
|
||||
execSync(`git diff --name-only ${commit}...HEAD`)
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(line => line.startsWith('packages/'))
|
||||
.map(line => line.split('/')[1])
|
||||
.map(pkgName => require(`./packages/${pkgName}/package.json`).name)
|
||||
)
|
||||
).join(',') || 'now';
|
||||
|
||||
console.log('To publish a stable release, execute the following:');
|
||||
console.log(
|
||||
`\ngit pull && lerna version --message 'Publish Stable' --exact --force-publish=${pkgs}\n`
|
||||
);
|
||||
|
||||
11
errors/invalid-token-value.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Invalid Token Value
|
||||
|
||||
#### Why This Error Occurred
|
||||
|
||||
The `--token` flag was specified, but its contents are invalid.
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
The `--token` flag must only contain numbers (0-9) and letters from the alphabet (a-z and A-Z). This needs to be the token of the user account as which you'd like to act.
|
||||
|
||||
You can either get the token from the `./now/auth.json` file located in your user directory or [from the dashboard](https://zeit.co/account/tokens).
|
||||
@@ -30,7 +30,7 @@
|
||||
"scripts": {
|
||||
"lerna": "lerna",
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"publish-stable": "git pull && lerna version --message 'Publish Stable' --exact",
|
||||
"publish-stable": "echo 'Run `yarn changelog` for instructions'",
|
||||
"publish-canary": "git pull && lerna version prerelease --preid canary --message 'Publish Canary' --exact",
|
||||
"publish-from-github": "./.circleci/publish.sh",
|
||||
"changelog": "node changelog.js",
|
||||
|
||||
249
packages/frameworks/frameworks.json
Normal file
@@ -0,0 +1,249 @@
|
||||
[
|
||||
{
|
||||
"name": "Next.js",
|
||||
"slug": "nextjs",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/next.svg",
|
||||
"tagline": "Next.js makes you productive with React instantly — whether you want to build static or dynamic sites. ",
|
||||
"website": "https://nextjs.org"
|
||||
},
|
||||
{
|
||||
"name": "Gatsby",
|
||||
"slug": "gatsby",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/gatsby.svg",
|
||||
"tagline": "Gatsby helps developers build blazing fast websites and apps with React.",
|
||||
"website": "https://gatsbyjs.org"
|
||||
},
|
||||
{
|
||||
"name": "Nuxt.js",
|
||||
"slug": "nuxtjs",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/nuxt.svg",
|
||||
"tagline": "Nuxt.js is the web comprehensive framework that lets you dream big with Vue.js.",
|
||||
"website": "https://nuxtjs.org"
|
||||
},
|
||||
{
|
||||
"name": "Create-React-App",
|
||||
"slug": "create-react-app",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/react.svg",
|
||||
"tagline": "Create React App allows you to get going with React in no time.",
|
||||
"website": "https://create-react-app.dev"
|
||||
},
|
||||
{
|
||||
"name": "Svelte",
|
||||
"slug": "svelte",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/svelte.svg",
|
||||
"tagline": "Svelte lets you write high performance reactive apps with significantly less boilerplate. ",
|
||||
"website": "https://svelte.dev"
|
||||
},
|
||||
{
|
||||
"name": "Vue.js",
|
||||
"slug": "vue",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/vue.svg",
|
||||
"tagline": "Vue.js is a versatile JavaScript framework that is as approachable as it is performant.",
|
||||
"website": "https://vuejs.org"
|
||||
},
|
||||
{
|
||||
"name": "Angular",
|
||||
"slug": "angular",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/angular.svg",
|
||||
"tagline": "Angular is a TypeScript-based cross-platform framework from Google.",
|
||||
"website": "https://angular.io"
|
||||
},
|
||||
{
|
||||
"name": "Hugo",
|
||||
"slug": "hugo",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/hugo.svg",
|
||||
"tagline": "Hugo is the world’s fastest framework for building websites, written in Go.",
|
||||
"website": "https://gohugo.io"
|
||||
},
|
||||
{
|
||||
"name": "Sapper",
|
||||
"slug": "sapper",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/svelte.svg",
|
||||
"tagline": "Sapper is a framework for building high-performance universal web apps with Svelte.",
|
||||
"website": "https://sapper.svelte.dev"
|
||||
},
|
||||
{
|
||||
"name": "UmiJS",
|
||||
"slug": "umijs",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/umi.svg",
|
||||
"tagline": "UmiJS is an extensible enterprise-level React application framework.",
|
||||
"website": "https://umijs.org"
|
||||
},
|
||||
{
|
||||
"name": "Vanilla",
|
||||
"slug": "vanilla",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/vanilla.svg",
|
||||
"tagline": "Love the original way of making websites?"
|
||||
},
|
||||
{
|
||||
"name": "Storybook",
|
||||
"slug": "storybook",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/storybook.svg",
|
||||
"tagline": "Storybook is an open source tool for developing UI components in isolation for React, Vue, and Angular.",
|
||||
"website": "https://storybook.js.org"
|
||||
},
|
||||
{
|
||||
"name": "Preact",
|
||||
"slug": "preact",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/preact.svg",
|
||||
"tagline": "Preact is a fast 3kB alternative to React with the same modern API.",
|
||||
"website": "https://preactjs.com"
|
||||
},
|
||||
{
|
||||
"name": "Docz",
|
||||
"slug": "docz",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/docz.svg",
|
||||
"tagline": "Docz makes it easy to write and publish beautiful interactive documentation for your code.",
|
||||
"website": "https://docz.site"
|
||||
},
|
||||
{
|
||||
"name": "mdx-deck",
|
||||
"slug": "mdx-deck",
|
||||
"tagline": "MDX Deck allows you to swiftly create React MDX-based presentation decks.",
|
||||
"website": "https://github.com/jxnblk/mdx-deck"
|
||||
},
|
||||
{
|
||||
"name": "Gridsome",
|
||||
"slug": "gridsome",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/gridsome.svg",
|
||||
"tagline": "Gridsome is a Vue.js-powered framework for building websites & apps that are fast by default."
|
||||
},
|
||||
{
|
||||
"name": "Aurelia",
|
||||
"slug": "aurelia",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/aurelia.svg",
|
||||
"tagline": "Aurelia is an all-in-one framework for building web, desktop, and mobile applications."
|
||||
},
|
||||
{
|
||||
"name": "Ember",
|
||||
"slug": "ember",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/ember.svg",
|
||||
"tagline": "Ember.js helps webapp developers be more productive out of the box."
|
||||
},
|
||||
{
|
||||
"name": "Docusaurus",
|
||||
"slug": "docusaurus",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/docusaurus.svg",
|
||||
"tagline": "Docusaurus makes it easy to maintain Open Source documentation websites."
|
||||
},
|
||||
{
|
||||
"name": "VuePress",
|
||||
"slug": "vuepress",
|
||||
"tagline": "VuePress is the performant way to create static sites with Vue.js."
|
||||
},
|
||||
{
|
||||
"name": "Charge.js",
|
||||
"slug": "charge",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/chargejs.svg",
|
||||
"tagline": "Charge is an opinionated, zero-config static site generator written in JavaScript."
|
||||
},
|
||||
{
|
||||
"name": "Riot.js",
|
||||
"slug": "riot",
|
||||
"tagline": "Riot.js lets you build user interfaces with custom tags using simple and enjoyable syntax."
|
||||
},
|
||||
{
|
||||
"name": "Jekyll",
|
||||
"slug": "jekyll",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/jekyll.svg",
|
||||
"tagline": "Jekyll makes it super easy to transform your plain text into static websites and blogs."
|
||||
},
|
||||
{
|
||||
"name": "Marko.js",
|
||||
"slug": "marko",
|
||||
"tagline": "Marko is a super fast UI library that makes building web apps fun."
|
||||
},
|
||||
{
|
||||
"name": "Hexo",
|
||||
"slug": "hexo",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/hexo.svg",
|
||||
"tagline": "Hexo is a fast, simple & powerful blog framework powered by Node.js."
|
||||
},
|
||||
{
|
||||
"name": "Mithril.js",
|
||||
"slug": "mithril",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/mithriljs.svg",
|
||||
"tagline": "Mithril is a lightweight modern web framework for that makes it easy to build SPAs."
|
||||
},
|
||||
{
|
||||
"name": "Metalsmith",
|
||||
"slug": "metalsmith",
|
||||
"tagline": "Metalsmith is an extremely simple, extendable static site generator."
|
||||
},
|
||||
{
|
||||
"name": "HyperApp",
|
||||
"slug": "hyperapp",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/hyperapp.svg",
|
||||
"tagline": "HyperApp is a low-footprint framework for building web interfaces without a learning curve."
|
||||
},
|
||||
{
|
||||
"name": "Polymer",
|
||||
"slug": "polymer",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/polymer.svg",
|
||||
"tagline": "Polymer is an open-source webapps library from Google, for building using Web Components."
|
||||
},
|
||||
{
|
||||
"name": "Brunch",
|
||||
"slug": "brunch",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/brunch.svg",
|
||||
"tagline": "Brunch is a fast and simple webapp build tool with seamless incremental compilation for rapid development."
|
||||
},
|
||||
{
|
||||
"name": "Saber",
|
||||
"slug": "saber",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/saber.svg",
|
||||
"tagline": "Saber is a framework for building static sites in Vue.js that supports data from any source."
|
||||
},
|
||||
{
|
||||
"name": "Eleventy",
|
||||
"slug": "eleventy",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/eleventy.svg",
|
||||
"tagline": "11ty is a simpler static site generator written in JavaScript, created to be an alternative to Jekyll."
|
||||
},
|
||||
{
|
||||
"name": "Zola",
|
||||
"slug": "zola",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/zola.svg",
|
||||
"tagline": "Zola is a one-stop static site engine for all of your static needs. "
|
||||
},
|
||||
{
|
||||
"name": "Pelican",
|
||||
"slug": "pelican",
|
||||
"tagline": "Pelican is a versatile static site generator, written in Python."
|
||||
},
|
||||
{
|
||||
"name": "MkDocs",
|
||||
"slug": "mkdocs",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/mkdocs.svg",
|
||||
"tagline": "MkDocs is a fast, simple and downright gorgeous static site generator that's geared towards building project documentation."
|
||||
},
|
||||
{
|
||||
"name": "Middleman",
|
||||
"slug": "middleman",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/middleman.svg",
|
||||
"tagline": "Middleman is a static site generator that uses all the shortcuts and tools in modern web development."
|
||||
},
|
||||
{
|
||||
"name": "Assemble",
|
||||
"slug": "assemble",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/assemble.svg",
|
||||
"tagline": "A static site generator for Grunt.js and Yeoman, Assemble makes it dead simple to build modular sites and blogs."
|
||||
},
|
||||
{
|
||||
"name": "Ionic React",
|
||||
"slug": "ionic-react",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/ionic-react.svg",
|
||||
"tagline": "Ionic React allows you to build mobile PWAs with React and the Ionic Framework."
|
||||
},
|
||||
{
|
||||
"name": "Stencil",
|
||||
"slug": "stencil",
|
||||
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/stencil.svg",
|
||||
"tagline": "Stencil is a powerful toolchain for building Progressive Web Apps and Design Systems."
|
||||
},
|
||||
{
|
||||
"name": "Foundation",
|
||||
"slug": "foundation",
|
||||
"tagline": "Foundation is the most advanced responsive front-end framework in the world."
|
||||
}
|
||||
]
|
||||
1
packages/frameworks/logos/angular.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 1L3 8.636l3.203 28.313L24 47l17.797-10.051L45 8.636 24 1z" fill="#DA0B36"/><path d="M24 1v5.106-.023V47l17.797-10.051L45 8.636 24 1z" fill="#C10933"/><path d="M24.022 6L11 36h4.855l2.618-6.713h11.054L32.145 36H37L24.022 6zm3.804 19.15H20.22l3.803-9.403 3.804 9.402z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 374 B |
4
packages/frameworks/logos/assemble.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 52 48">
|
||||
<path fill="#111" stroke="#190000" stroke-linecap="square" stroke-miterlimit="10" stroke-width=".5" d="M22.32 4.48h7.5l16.5 38.97h-8.55l-3.53-8.9H17.71l-3.63 8.75h-8.4L22.33 4.48h0zm3.53 9.68c.05.15 5.45 13.13 5.45 13.13H20.55s5.27-13.24 5.3-13.13z"/>
|
||||
<path fill="#fff" stroke="#190000" stroke-linecap="square" stroke-miterlimit="10" stroke-width=".5" d="M25.77 14l5.44 13.13H20.47S25.73 13.9 25.77 14z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 490 B |
61
packages/frameworks/logos/aurelia.svg
Normal file
@@ -0,0 +1,61 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<path fill="url(#paint0_linear)" d="M31.48 8.75l-4.44 2.99-4.58-6.9 4.44-2.99 4.58 6.9z"/>
|
||||
<path fill="url(#paint1_linear)" d="M35.09 29.48l7.58 11.45L33.64 47l-7.6-11.45-1.31-2 9.03-6.06 1.33 2z"/>
|
||||
<path fill="url(#paint2_linear)" d="M23.7 37.13l1.67 2.52-6.87 4.62-3-4.52 1.5-1 5.38-3.62 1.32 2z"/>
|
||||
<path fill="url(#paint3_linear)" d="M38.84 24.07l1.93-1.3 3 4.52-4.44 2.99-1.67-2.52 2.5-1.7-1.32-1.99zm-1.18 3.69l-1.33-2 2.51-1.69 1.33 2-2.51 1.69z"/>
|
||||
<path fill="url(#paint4_linear)" d="M7.7 24.72l-1.5 1.01-4.57-6.9 6.88-4.62 3.2 4.84-5.37 3.6 5.38-3.6 1.36 2.06-5.37 3.61z"/>
|
||||
<path fill="url(#paint5_linear)" d="M24.47 13.46l-9.04 6.07-1.37-2.06L6.55 6.13 15.58.06 23.1 11.4l1.37 2.06z"/>
|
||||
<path fill="url(#paint6_linear)" d="M29.55 10.05l-2.51 1.69-1.37-2.07-3.2-4.83 4.43-2.99 4.58 6.9-1.93 1.3z"/>
|
||||
<path fill="#714896" d="M18.33 40.74l-1.33-2 5.38-3.6 1.32 1.99-5.37 3.61z"/>
|
||||
<path fill="#6F4795" d="M37.66 27.76l-1.33-2 2.51-1.69 1.33 2-2.51 1.69z"/>
|
||||
<path fill="#88519F" d="M7.7 24.72l-1.36-2.06 5.38-3.61 1.36 2.06-5.37 3.61z"/>
|
||||
<path fill="#85509E" d="M27.04 11.74l-1.37-2.07L28.18 8l1.37 2.06-2.51 1.69z"/>
|
||||
<path fill="#8D166A" d="M35.09 29.48l-9.04 6.07-1.32-2 9.03-6.06 1.33 2z"/>
|
||||
<path fill="#A70D6F" d="M23.1 11.4l1.37 2.06-9.04 6.07-1.37-2.06 9.04-6.07z"/>
|
||||
<path fill="#9E61AD" d="M5.14 9.75l1.71 2.57-2.56 1.72-1.7-2.57 2.55-1.72z"/>
|
||||
<path fill="#8053A3" d="M14.36 40.6l1.7 2.57-2.55 1.72-1.71-2.57 2.56-1.72z"/>
|
||||
<path fill="url(#paint7_linear)" d="M7.63 43.19L.15 31.8l40-26.93 7.84 11.2L7.63 43.19z"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="-12.53" x2="47.68" y1="-9.38" y2="33.11" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#C06FBB"/>
|
||||
<stop offset="1" stop-color="#6E4D9B"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear" x1="37.82" x2="4.33" y1="43" y2="6.94" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#6E4D9B"/>
|
||||
<stop offset=".14" stop-color="#77327A"/>
|
||||
<stop offset=".29" stop-color="#B31777"/>
|
||||
<stop offset=".84" stop-color="#CD0F7E"/>
|
||||
<stop offset="1" stop-color="#ED2C89"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear" x1="-7.42" x2="35.06" y1="-28.24" y2="47.35" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#C06FBB"/>
|
||||
<stop offset="1" stop-color="#6E4D9B"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear" x1="-24.72" x2="44.39" y1="-12.24" y2="43.73" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#C06FBB"/>
|
||||
<stop offset="1" stop-color="#6E4D9B"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear" x1="-14.41" x2="49.9" y1="-12.4" y2="44.01" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#C06FBB"/>
|
||||
<stop offset="1" stop-color="#6E4D9B"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear" x1="40.79" x2="7.22" y1="43.89" y2="7.61" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#6E4D9B"/>
|
||||
<stop offset=".14" stop-color="#77327A"/>
|
||||
<stop offset=".29" stop-color="#B31777"/>
|
||||
<stop offset=".84" stop-color="#CD0F7E"/>
|
||||
<stop offset="1" stop-color="#ED2C89"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint6_linear" x1="-12.52" x2="48.68" y1="-11.86" y2="40.25" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#C06FBB"/>
|
||||
<stop offset="1" stop-color="#6E4D9B"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint7_linear" x1="5.65" x2="34.95" y1="39.23" y2="2.75" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#6E4D9B"/>
|
||||
<stop offset=".14" stop-color="#77327A"/>
|
||||
<stop offset=".53" stop-color="#B31777"/>
|
||||
<stop offset=".79" stop-color="#CD0F7E"/>
|
||||
<stop offset="1" stop-color="#ED2C89"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
3
packages/frameworks/logos/brunch.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="49" height="48" fill="none">
|
||||
<path fill="#3F894A" d="M14.52 35.93a3.39 3.39 0 0 0-1.14-2.41 4.65 4.65 0 0 0-.1-.1l-.02-.01a7.6 7.6 0 0 1-2.14-5.4c0-3.08 1.37-11.87 1.67-11.87.23 0 .23 4.24.08 8.22-.1 2.77.3 3.86.96 3.86.88 0 1.02-2.79 1.11-5.92.08-2.57.3-6.14.48-6.16.28 0 .51 3.55.59 6.13.1 3.2.32 5.87 1.05 5.87.77 0 1-1.23.95-3.97-.07-3.34-.07-8.03.17-8.03.3 0 1.3 3.09 1.54 11.88a7.36 7.36 0 0 1-2.14 5.39h-.01l-.11.1a3.39 3.39 0 0 0-1.14 2.42 62.5 62.5 0 0 0-.13 4.62l6.78 6.78c.1-2.95.08-5.74-.05-7.84-.05-.79-.17-1.7-.3-2.43-.05-.23-.2-.44-.2-.63v-25.6c0-2.18 2.05-3.2 3.93 1.58 1.88 4.8 1.35 21.84 1.35 23.05 0 .26-.22.56-.59.86l-.4.29c-1.12.9-1.28 1.95-1.34 2.88-.14 2.26-.25 5.31-.28 8.51l9.34-9.34c-.02-1.1-.05-2.08-.1-2.9-.02-.32-.1-.64-.16-.98-.16-.95-1.35-1.74-2.03-2.43-1.33-1.33-2.19-3.58-2.19-6.11 0-4.11 2.28-9.32 5.1-9.32 2.8 0 5.08 5.2 5.08 9.32 0 2.53-.85 4.78-2.18 6.11-.69.7-1.87 1.48-2.04 2.43-.06.34-.14.66-.16.98l-.07 1.65 13.05-13.05L24.36 0 0 24.36 14.64 39c-.02-1.16-.06-2.2-.12-3.07z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
15
packages/frameworks/logos/chargejs.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<path fill="url(#paint0_linear)" fill-rule="evenodd" d="M17.1 48l-16-9.4a1.87 1.87 0 0 1-.92-1.61l-.1-25.7A1.89 1.89 0 0 1 1 9.64L17.32.16l7.19 6.76 6.1-6.59 16.2 9.53a1.87 1.87 0 0 1 .93 1.6l.1 25.71a1.89 1.89 0 0 1-.92 1.63l-15.7 9.13-7.52-7.07-6.6 7.13V48z" clip-rule="evenodd" opacity=".9"/>
|
||||
<path fill="url(#paint1_linear)" fill-rule="evenodd" d="M44.44 13.39l.1 21.59a1.89 1.89 0 0 1-.92 1.63L25.27 47.29a1.85 1.85 0 0 1-1.87 0L4.9 36.38a1.87 1.87 0 0 1-.92-1.6l-.11-21.6a1.89 1.89 0 0 1 .93-1.63L23.15.88a1.85 1.85 0 0 1 1.87.01l18.5 10.89a1.87 1.87 0 0 1 .92 1.6v.01z" clip-rule="evenodd"/>
|
||||
<path fill="#fff" d="M32.14 19.09l-7.1 1.92.1-10.96-9.5 19.41 7.09-1.92-.11 10.96 9.52-19.41z"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="23.17" x2="31.2" y1="-3.24" y2="50.11" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FE4386"/>
|
||||
<stop offset="1" stop-color="#FFBB94"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear" x1="24.59" x2="28.79" y1="2.21" y2="47.42" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#F8016B"/>
|
||||
<stop offset="1" stop-color="#FC716A"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
1
packages/frameworks/logos/docusaurus.svg
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
11
packages/frameworks/logos/docz.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="53" height="42" fill="none">
|
||||
<path fill="#E2D9C5" d="M17.92 4.81h31.96A4.3 4.3 0 0 0 45.52.44H13.56a4.3 4.3 0 0 1 4.36 4.37z"/>
|
||||
<path fill="#F2EBDA" d="M41.14 4.76A4.34 4.34 0 0 1 45.5.44H13.55a4.34 4.34 0 0 0-4.36 4.32v35.49h27.6c2.4 0 4.35-1.93 4.35-4.32V4.76z"/>
|
||||
<path fill="#E2D9C5" d="M40.44.44a4.36 4.36 0 0 0-4.37 4.35v31.38c0 2.4-1.96 4.35-4.38 4.35H37a4.36 4.36 0 0 0 4.37-4.35V4.8c0-2.4 1.96-4.35 4.38-4.35h-5.31z"/>
|
||||
<path fill="#E2D9C5" d="M32.53 35.92H.5c.03 2.68 1.97 4.6 4.37 4.6H36.9c-2.4 0-4.34-1.92-4.37-4.6z"/>
|
||||
<path fill="#DDA064" d="M30.19 28c.88-2.74 1.68-5.53 3.56-7.67 4.1-4.66 12.34-6.03 18.31-5.88a53 53 0 0 0-5.38 5.12c-2.12 2.28-6.74 5.3-8.96 5.99-3.46 1.06-5.06 1.24-7.53 2.44z"/>
|
||||
<path fill="#B57947" d="M30.19 28c.88-2.74 15.9-13.71 21.87-13.56a53.02 53.02 0 0 0-5.38 5.12c-2.12 2.28-6.74 5.32-8.96 6-3.46 1.06-5.06 1.23-7.53 2.44z"/>
|
||||
<path fill="#1F2D3D" d="M38.06 8.1c0-.37-.34-.66-.77-.66H20.9c-.42 0-.76.3-.76.65 0 .37.34.66.77.66h16.4c.42 0 .76-.3.76-.66zM13.94 8.75h2.75c.45 0 .81-.3.81-.66 0-.36-.36-.65-.81-.65h-2.75c-.45 0-.81.3-.81.65 0 .37.36.66.81.66zM13.9 31.06c-.43 0-.77.3-.77.66 0 .36.34.66.77.66h8.08c.42 0 .77-.3.77-.66 0-.36-.35-.66-.77-.66H13.9zM26.25 24.72c0-.36-.35-.66-.79-.66H13.91c-.43 0-.78.3-.78.66 0 .36.35.66.78.66h11.55c.44 0 .79-.3.79-.66zM31.94 16.84c0-.36-.36-.65-.8-.65H13.93c-.44 0-.8.3-.8.65 0 .37.36.66.8.66h17.23c.43 0 .79-.3.79-.66z"/>
|
||||
<path fill="#1F2D3D" d="M41.3 26.62a.77.77 0 0 0-.76.78v9.43c0 2-1.6 3.61-3.57 3.61h-.1c-2 0-3.54-1.66-3.56-3.88a.77.77 0 0 0-.77-.77H10.3V5.17c0-2 1.6-3.61 3.57-3.61h28.12l-.06.07-.08.09-.09.1-.07.08-.08.1-.07.1-.07.1-.07.1-.07.1-.06.1-.07.12-.06.1-.05.11-.06.12-.05.1c-.01.05-.03.08-.05.12l-.04.12-.05.12-.04.12-.04.11-.03.13-.04.12-.03.13-.02.12-.03.13-.02.12-.01.15-.02.1-.01.17v.1l-.01.26v6.91c0 .43.34.77.76.77.43 0 .77-.34.77-.77V6.2h7.91c.2 0 .4-.09.55-.23a.78.78 0 0 0 .22-.56C50.72 2.33 48.53 0 45.64 0H13.87a5.14 5.14 0 0 0-5.1 5.17v30.62h-8c-.2 0-.4.09-.55.23a.78.78 0 0 0-.22.56C.03 39.67 2.22 42 5.1 42h31.87c2.81 0 5.1-2.32 5.1-5.17V27.4a.77.77 0 0 0-.77-.78zm.81-21.99l.01-.07.02-.1.02-.07a3.53 3.53 0 0 1 .2-.65l.04-.07.04-.09.03-.06.04-.09.02-.03a3.72 3.72 0 0 1 .32-.48l.02-.02.08-.1.02-.02.1-.1v-.02l.1-.1.02-.01.1-.1h.01a3.46 3.46 0 0 1 1.85-.85v-.01l.16-.02H45.48l.08-.01h.09c1.76 0 3.16 1.28 3.49 3.09H42.1v-.02zm-37 35.81c-1.77 0-3.17-1.28-3.5-3.09h30.22a6 6 0 0 0 .03.24l.02.08a6 6 0 0 0 .03.15l.02.1.03.14.03.1a6.14 6.14 0 0 0 .18.56l.04.1.05.12.04.09.06.12.04.08.08.15.03.05.11.19c0 .02.02.03.03.04l.1.15a4.63 4.63 0 0 0 .13.18l.04.07.08.1.06.07a5.16 5.16 0 0 0 .15.17l.04.04H5.1z"/>
|
||||
<path fill="#1F2D3D" d="M52.94 14.35v-.03a.77.77 0 0 0-.04-.21v-.01-.01a.77.77 0 0 0-.05-.1v-.01a.78.78 0 0 0-.06-.08l-.01-.02a.78.78 0 0 0-.07-.07l-.01-.02a.8.8 0 0 0-.17-.12l-.02-.01a.79.79 0 0 0-.33-.08c-6.56-.17-15.11 1.4-19.44 6.29-1.89 2.14-2.76 4.86-3.6 7.49l-.22.64v.03l-1.33 4.67a.78.78 0 0 0 .76.99c.34 0 .65-.23.75-.57l1.23-4.33c1.5-.7 2.71-1.02 4.34-1.46.85-.23 1.81-.5 2.97-.85 2.52-.76 7.34-3.97 9.55-6.35a53.37 53.37 0 0 1 5.46-5.18.78.78 0 0 0 .15-.16l.02-.02a.77.77 0 0 0 .11-.32v-.08-.02zm-19.02 6.54c1.83-2.06 4.62-3.62 8.31-4.63 1-.27 2.04-.49 3.12-.67a60.73 60.73 0 0 0-6.83 3.95 62.64 62.64 0 0 0-6.81 5.16c.56-1.4 1.23-2.7 2.21-3.8zm12.12-1.82c-2.16 2.32-6.82 5.3-8.86 5.93-1.13.34-2.08.6-2.92.83-.75.2-1.44.38-2.12.6.3-.29.66-.61 1.08-.98 1.7-1.46 3.88-3.1 6.17-4.62 3.95-2.62 7.53-4.46 10.16-5.26a60.6 60.6 0 0 0-3.5 3.5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
1
packages/frameworks/logos/eleventy.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
1
packages/frameworks/logos/ember.svg
Normal file
|
After Width: | Height: | Size: 39 KiB |
1
packages/frameworks/logos/gatsby.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M42.857 24h-12v3.428h8.229c-1.2 5.143-4.972 9.43-9.943 11.143L9.429 18.857c2.057-6 7.885-10.286 14.571-10.286 5.143 0 9.771 2.572 12.686 6.515l2.571-2.229C35.83 8.23 30.343 5.143 24 5.143c-8.914 0-16.457 6.343-18.343 14.743l22.629 22.628c8.228-2.057 14.571-9.6 14.571-18.514zm-37.714.171c0 4.8 1.886 9.429 5.486 13.029 3.6 3.6 8.4 5.486 13.028 5.486L5.143 24.17z" fill="#fff"/><path d="M24 0C10.8 0 0 10.8 0 24s10.8 24 24 24 24-10.8 24-24S37.2 0 24 0zM10.629 37.371c-3.6-3.6-5.486-8.4-5.486-13.028l18.686 18.514c-4.8-.171-9.6-1.886-13.2-5.486zm17.485 4.972L5.657 19.886C7.543 11.486 15.086 5.143 24 5.143c6.343 0 11.829 3.086 15.257 7.714l-2.571 2.229C33.77 11.143 29.143 8.57 24 8.57c-6.686 0-12.343 4.286-14.571 10.286l19.714 19.714c4.971-1.714 8.743-6 9.943-11.142h-8.229V24h12c0 8.914-6.343 16.457-14.743 18.343z" fill="#639"/></svg>
|
||||
|
After Width: | Height: | Size: 921 B |
1
packages/frameworks/logos/gridsome.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M43.395 19.862c2.308-.11 4.35 1.68 4.55 3.99.863 11.174-9.364 23.692-23.775 24.092C12.025 48.244.013 38.521.013 23.82c0-2.317 1.915-4.195 4.225-4.195a4.19 4.19 0 0 1 4.184 4.195c0 9.67 7.776 15.928 15.542 15.737 9.56-.266 15.776-8.544 15.453-15.303a4.19 4.19 0 0 1 3.978-4.392z" fill="url(#paint0_linear)"/><path d="M32.944 24.145c0-2.372 1.935-4.295 4.321-4.295h6.298c2.387 0 4.382 1.923 4.382 4.295s-1.995 4.295-4.382 4.295h-6.298c-2.386 0-4.321-1.923-4.321-4.295zm-13.215.006a4.297 4.297 0 0 1 4.291-4.301 4.297 4.297 0 0 1 4.292 4.301 4.297 4.297 0 0 1-4.292 4.301 4.297 4.297 0 0 1-4.291-4.301z" fill="#00A672"/><path fill-rule="evenodd" clip-rule="evenodd" d="M28.193 4.055a4.19 4.19 0 0 1-4.006 4.365c-9.966.415-16.05 8.248-15.753 15.685.092 2.315-1.668 4.267-3.976 4.36-2.309.092-4.34-1.777-4.431-4.092C-.456 12.253 9.635.273 23.84.037a4.188 4.188 0 0 1 4.353 4.018z" fill="#00A672"/><defs><linearGradient id="paint0_linear" x1="24.005" y1="19.625" x2="24.005" y2="47.951" gradientUnits="userSpaceOnUse"><stop stop-color="#00583E"/><stop offset="1" stop-color="#00835C"/></linearGradient></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
1
packages/frameworks/logos/hexo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M23.829.005l-20.735 12 .002 23.964L23.878 47.92l20.736-12V11.97L23.829.004z" fill="#0E83CD"/><path d="M14.101 34.338l.002-10.362.002-10.363 1.882-1.101 1.804 1.067.019 4.235.02 4.234h12.05l.019-4.231.02-4.232 1.83-1.059 1.857 1.087V23.97l-.002 10.355-1.837 1.027-1.849-1.04-.02-4.21-.019-4.212H17.83l-.019 4.21.006 4.23-1.848 1.085-1.866-1.076z" fill="#fff"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(3)" d="M0 0H41.645V48H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 591 B |
5
packages/frameworks/logos/hugo.svg
Normal file
|
After Width: | Height: | Size: 30 KiB |
4
packages/frameworks/logos/hyperapp.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<rect width="48" height="48" fill="#0080FF" rx="24"/>
|
||||
<path fill="#fff" d="M18.5386 21.6899h7.8153l1.8771 3.8487h-9.6924v9.6902h-3.8481v-9.6902H5v-3.8487h9.6905V12h3.8481v9.6899zm24.1057 13.5389h-4.5342L26.7809 12h4.5341l11.3293 23.2288z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 328 B |
4
packages/frameworks/logos/ionic-react.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
|
||||
<rect width="48" height="48" fill="#4180FC" rx="24"/>
|
||||
<path fill="#fff" fill-rule="evenodd" d="M38.4327 17.0558l.1306.3047C39.5211 19.4721 40 21.6925 40 24c0 8.8163-7.1837 16-16 16S8 32.8163 8 24 15.1837 8 24 8c2.5905 0 5.0503.6095 7.3143 1.7415l.3047.1524-.2612.2177c-.653.5224-1.1537 1.1755-1.4802 1.9374l-.0871.2177-.1959-.0871C27.8313 11.3524 25.9592 10.917 24 10.917c-7.2272 0-13.083 5.8558-13.083 13.083S16.7728 37.083 24 37.083 37.083 31.2054 37.083 24c0-1.7197-.3265-3.4177-1.0014-5.0068l-.087-.2177.2176-.0871c.7619-.283 1.4585-.7619 2.0028-1.3714l.2177-.2612zm-3.962.3048c1.8395 0 3.3307-1.4912 3.3307-3.3306 0-1.8395-1.4912-3.3307-3.3307-3.3307-1.8394 0-3.3306 1.4912-3.3306 3.3307 0 1.8394 1.4912 3.3306 3.3306 3.3306zm-10.4708-.6531c-4.0272 0-7.2925 3.2653-7.2925 7.2926 0 4.0272 3.2653 7.2925 7.2925 7.2925 4.0272 0 7.2925-3.2653 7.2925-7.2925 0-4.0273-3.2653-7.2926-7.2925-7.2926z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1003 B |
19
packages/frameworks/logos/jekyll.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<path fill="#333" d="M0 24a24 24 0 1 0 48 0 24 24 0 0 0-48 0z"/>
|
||||
<path fill="#000" d="M25.22 5.55a.52.52 0 0 0 0 .22s.23 1.56-.03 2.25l-11.35 29.5a4.22 4.22 0 0 0 7.88 3.03l11.35-29.5c.22-.57 1.48-1.7 1.48-1.7.07-.04.12-.1.15-.16v-.01l.02-.04c.3-.76-1.6-2.2-4.21-3.2-2.62-1-4.98-1.2-5.27-.45l-.02.04v.02z" opacity=".3"/>
|
||||
<path fill="url(#paint0_linear)" d="M24.9 5.3a.51.51 0 0 0-.01.22s.23 1.56-.03 2.25L13.5 37.27a4.22 4.22 0 0 0 7.88 3.03l11.35-29.5c.22-.58 1.49-1.7 1.49-1.7.06-.04.1-.1.14-.16v-.01l.03-.04c.29-.76-1.6-2.2-4.22-3.2-2.62-1-4.98-1.2-5.27-.45l-.01.04v.01z"/>
|
||||
<path fill="url(#paint1_linear)" d="M28.45 18.64L20.27 39.9a3.06 3.06 0 0 1-3.91 1.72 3.12 3.12 0 0 1-1.83-3.93l5.23-13.59s.65-1.05 1.93-1.8c1.29-.75 2.34-.6 3.77-1.22 1.42-.64 3-2.45 3-2.45z"/>
|
||||
<path fill="#333" d="M29.33 7.92c1.62.63 3.07.79 3.24.36.16-.43-1.02-1.28-2.65-1.9-1.62-.63-3.08-.8-3.24-.37-.17.43 1.02 1.28 2.65 1.91z"/>
|
||||
<path fill="#fff" d="M24.89 5.52s.23 1.57-.03 2.25L13.5 37.27a4.22 4.22 0 0 0 3.58 5.68 4.22 4.22 0 0 1-1.41-4.85L26.8 9.19s-1.52-1.42-1.91-3.67z" opacity=".3"/>
|
||||
<path fill="#fff" d="M21.24 24.87a.33.33 0 1 0 0-.65.33.33 0 0 0 0 .65zM23.4 27.42a.5.5 0 1 0 0-.99.5.5 0 0 0 0 1zM20.1 30.7a.93.93 0 1 0 0-1.87.93.93 0 0 0 0 1.86zM18.6 31.98a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1zM20.57 35.49a.33.33 0 1 0 0-.66.33.33 0 0 0 0 .66z" opacity=".5"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="18.32" x2="27.81" y1="22.36" y2="26.01" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#919191"/>
|
||||
<stop offset="1" stop-color="#fff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear" x1="18.08" x2="23.83" y1="28.47" y2="30.68" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#900"/>
|
||||
<stop offset="1" stop-color="#E80000"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
9
packages/frameworks/logos/middleman.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
|
||||
<rect width="48" height="48" fill="#FBC547" rx="24"/>
|
||||
<path fill="#000" fill-opacity=".45" d="M6 12.53L23.65 9v2.65L6 14.29v-1.76z"/>
|
||||
<path fill="#fff" d="M23.65 9l17.64 3.53v1.76l-17.64-2.64V9z"/>
|
||||
<path fill="#000" fill-opacity=".45" d="M6 15.88v16.24l3.97.44V22.4l3.97 7.33 4.15-7.33V33.8l4.67.62V13.6l-5.02.7-3.8 7.33-3.8-6.18-4.14.44z"/>
|
||||
<path fill="#fff" d="M41.3 15.88v16.24l-3.98.44V22.4l-3.97 7.33-4.14-7.33V33.8l-4.68.62V13.6l5.03.7 3.8 7.33 3.79-6.18 4.14.44z"/>
|
||||
<path fill="#000" fill-opacity=".45" d="M6 35.47L23.65 39v-2.65L6 33.71v1.76z"/>
|
||||
<path fill="#fff" d="M23.65 39l17.64-3.53v-1.76l-17.64 2.64V39z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 715 B |
4
packages/frameworks/logos/mithriljs.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<rect width="48" height="48" fill="#000" rx="24"/>
|
||||
<path fill="#fff" d="M36.109 17.5974C36.0934 11.1453 30.839 5.9 24.3831 5.9c-6.4659 0-11.7267 5.2609-11.7267 11.7268 0 .0202.0037.0394.0037.0596C9.2734 19.745 7 23.4594 7 27.7033 7 34.1701 12.2599 39.43 18.7267 39.43c2.0816 0 4.0338-.5516 5.7308-1.507 1.697.9554 3.6501 1.507 5.7316 1.507 6.4669 0 11.7268-5.2608 11.7268-11.7267 0-4.3054-2.3386-8.0666-5.8069-10.1059zM24.4575 35.4587c-2.122-1.5722-3.5849-3.9842-3.8731-6.7477 1.1931.4112 2.4679.6443 3.7987.6443 1.3896 0 2.7167-.2551 3.953-.7012-.2735 2.7874-1.742 5.2214-3.8786 6.8046zm-9.6406-16.5782c1.1959-.5314 2.5175-.8343 3.9098-.8343a9.5872 9.5872 0 0 1 3.8126.7875c-1.9403 1.6759-3.3307 3.9695-3.8502 6.5778-2.077-1.5253-3.5225-3.8547-3.8722-6.531zm9.5662 8.4043c-1.3372 0-2.612-.2735-3.7712-.7682.3313-2.6873 1.7704-5.0314 3.8456-6.5687 2.0586 1.5254 3.4895 3.8428 3.8364 6.5026-1.1968.5332-2.5185.8343-3.9108.8343zm1.9926-8.4521a9.6043 9.6043 0 0 1 3.8125-.7874c1.3373 0 2.6121.2735 3.7722.7682-.3267 2.6478-1.7282 4.9598-3.7529 6.4998-.5342-2.5689-1.9154-4.8248-3.8318-6.4806zm-1.9926-10.863c4.9855 0 9.1 3.7969 9.6057 8.6502-1.1931-.4102-2.4679-.6443-3.7997-.6443-2.0815 0-4.0346.5516-5.7316 1.5071-1.6961-.9555-3.6483-1.5071-5.7308-1.5071-1.3895 0-2.7167.2552-3.9529.7003.48-4.8799 4.6055-8.7062 9.6093-8.7062zm-5.6564 29.3916c-5.326 0-9.658-4.332-9.658-9.658 0-3.1371 1.5098-5.9207 3.8337-7.6866.6828 3.2867 2.7525 6.0639 5.5609 7.7169.0101 3.5308 1.5924 6.6935 4.0769 8.8393a9.5766 9.5766 0 0 1-3.8135.7884zm11.4624 0a9.587 9.587 0 0 1-3.8125-.7875c2.4918-2.1522 4.0787-5.3269 4.0787-8.8696 0-.0202-.0037-.0404-.0037-.0596 2.7599-1.6787 4.7809-4.4532 5.4316-7.7243 2.3982 1.7595 3.964 4.5881 3.964 7.783-.001 5.3251-4.333 9.658-9.6581 9.658z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
4
packages/frameworks/logos/mkdocs.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<circle cx="24" cy="24" r="24" fill="#2FA4E7"/>
|
||||
<path fill="#fff" d="M32.55 32.91V16h-3.07L24.1 29.23h-.2L18.52 16h-3.07v16.91h2.43V20.52h.17L23 32.61h2l4.95-12.09h.17v12.39h2.43z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 270 B |
1
packages/frameworks/logos/next.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M22.428.013c-.103.01-.431.042-.727.066C14.883.693 8.497 4.37 4.453 10.024A23.754 23.754 0 0 0 .216 20.51C.023 21.828 0 22.217 0 24.005c0 1.787.023 2.177.216 3.495 1.304 9.012 7.718 16.584 16.417 19.39 1.558.501 3.2.844 5.068 1.05.727.08 3.87.08 4.598 0 3.224-.356 5.954-1.154 8.648-2.529.412-.21.492-.267.436-.314-.038-.028-1.797-2.388-3.909-5.24l-3.838-5.184-4.809-7.117c-2.646-3.913-4.824-7.112-4.842-7.112-.019-.005-.038 3.157-.047 7.018-.014 6.76-.019 7.033-.103 7.192-.122.23-.216.324-.413.427-.15.075-.282.09-.99.09h-.812l-.216-.137a.878.878 0 0 1-.314-.342l-.099-.211.01-9.407.014-9.41.145-.184c.075-.098.235-.225.347-.286.193-.094.268-.103 1.08-.103.957 0 1.116.038 1.365.31.07.075 2.674 3.997 5.79 8.721s7.376 11.175 9.469 14.342l3.8 5.756.192-.127c1.704-1.107 3.505-2.683 4.932-4.325a23.888 23.888 0 0 0 5.65-12.268c.192-1.319.215-1.708.215-3.495 0-1.788-.023-2.177-.216-3.495-1.304-9.013-7.718-16.584-16.417-19.39C29.832.623 28.199.28 26.369.074c-.45-.047-3.551-.099-3.94-.061zm9.825 14.515a.947.947 0 0 1 .474.554c.038.122.047 2.73.038 8.608l-.014 8.436-1.488-2.28-1.492-2.28v-6.132c0-3.964.019-6.193.047-6.3a.957.957 0 0 1 .465-.592c.192-.098.262-.108 1-.108.694 0 .816.01.97.094z" fill="#000"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
5
packages/frameworks/logos/nuxt.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="48" height="38" viewBox="0 0 48 38" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.7599 35.9199L14.6399 35.7999C14.3999 35.3199 14.3999 34.8399 14.3999 34.3599H2.99992L20.0399 4.11988L27.1199 16.9599L29.3999 15.2799L22.3199 2.43988C22.1999 2.19988 21.3599 0.879883 19.9199 0.879883C19.3199 0.879883 18.3599 1.11988 17.6399 2.43988L0.479919 33.0399C0.359919 33.2799 -0.360081 34.7199 0.359919 35.9199C0.599919 36.5199 1.31992 37.1199 2.87992 37.1199H17.2799C15.7199 37.1199 14.9999 36.5199 14.7599 35.9199Z" fill="#00C58E"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M47.3999 33.1598L33.5999 8.31977C33.3599 8.07977 32.6399 6.75977 31.1999 6.75977C30.5999 6.75977 29.7599 6.99977 28.9199 8.31977L27.1199 11.1998V16.9598L31.1999 9.87977L44.8799 34.3598H39.7199C39.7913 34.853 39.7075 35.3563 39.4799 35.7998V35.9198C38.7599 37.1198 37.1999 37.1198 36.9599 37.1198H45.1199C45.3599 37.1198 46.9199 37.1198 47.6399 35.9198C47.8799 35.3198 48.1199 34.3598 47.3999 33.1598Z" fill="#108775"/>
|
||||
<path d="M39.84 35.9199V35.7999L39.96 35.5599C40.08 35.1999 40.2 34.7199 40.08 34.3599L39.6 33.0399L28.8 14.08L27.24 11.2H27.12L25.56 14.08L14.64 33.0399L14.28 34.3599C14.1908 34.8922 14.275 35.4391 14.52 35.9199C14.88 36.5199 15.6 37.1199 17.04 37.1199H37.2C37.56 37.1199 39.12 37.1199 39.84 35.9199ZM27.12 16.96L37.08 34.3599H17.28L27.12 16.96Z" fill="#2F495E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
1
packages/frameworks/logos/polymer.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M28.8 40.371L9.6 7.113H19.2l19.201 33.258h-9.6z" fill="#FF4081"/><path d="M28.8 40.371l4.8-8.314 4.802 8.314H28.8z" fill="#fff" fill-opacity=".2"/><path d="M24 32.057l4.8 8.314 4.8-8.314H24z" fill="#fff" fill-opacity=".1"/><path d="M19.2 23.742l4.8 8.315 4.8-8.315h-9.6z" fill="#000" fill-opacity=".1"/><path d="M19.2 23.742l4.8-8.314 4.8 8.314h-9.6z" fill="#000" fill-opacity=".2"/><path d="M14.4 15.428l4.8 8.314 4.8-8.314h-9.6z" fill="#000" fill-opacity=".3"/><path d="M14.4 15.428l4.8-8.315 4.8 8.315h-9.6z" fill="#000" fill-opacity=".4"/><path d="M9.599 7.113l4.801 8.315 4.8-8.315H9.6z" fill="#000" fill-opacity=".5"/><path d="M9.599 40.371L-.002 23.742l4.8-8.314L19.2 40.37H9.599z" fill="#536DFE"/><path d="M9.599 40.371l4.801-8.314 4.8 8.314H9.6z" fill="#fff" fill-opacity=".2"/><path d="M4.799 32.057l4.8 8.314 4.801-8.314H4.8z" fill="#fff" fill-opacity=".1"/><path d="M-.002 23.742l4.8 8.315 4.8-8.315h-9.6z" fill="#000" fill-opacity=".1"/><path d="M-.002 23.742l4.8-8.314 4.8 8.314h-9.6z" fill="#000" fill-opacity=".2"/><path d="M9.599 23.742l-4.8-8.314 4.8-8.315 4.801 8.315L9.6 23.742z" fill="#303F9F"/><path d="M14.4 15.428L9.6 7.113l-4.8 8.315H14.4z" fill="#000" fill-opacity=".2"/><path d="M38.401 40.371l-4.8-8.314 4.8-8.315 4.8 8.315-4.8 8.314z" fill="#3F51B5"/><path d="M43.201 32.057l-4.8 8.314-4.8-8.314h9.6z" fill="#000" fill-opacity=".2"/><path d="M43.201 32.057L28.8 7.113h9.601l9.602 16.63-4.802 8.314z" fill="#7986CB"/><path d="M38.401 23.742l4.8 8.315 4.801-8.315h-9.6z" fill="#fff" fill-opacity=".2"/><path d="M38.401 23.742l4.8-8.314 4.801 8.314h-9.6z" fill="#fff" fill-opacity=".1"/><path d="M33.6 15.428l4.801-8.315 4.8 8.315h-9.6z" fill="#000" fill-opacity=".1"/><path d="M28.8 7.113l4.8 8.315 4.801-8.315H28.8z" fill="#000" fill-opacity=".2"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(0 7)" d="M0 0H48V33.375H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
1
packages/frameworks/logos/preact.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M23.757 0l20.756 11.984V35.95L23.758 47.935 3 35.951V11.984L23.757 0z" fill="#673AB8"/><path d="M8.654 35.753c2.76 3.532 11.529.84 19.808-5.628S41.474 15.8 38.714 12.267s-11.529-.84-19.808 5.628S5.894 32.22 8.654 35.753zm1.178-.92c-.915-1.172-.515-3.472 1.229-6.366 1.836-3.048 4.952-6.413 8.766-9.393 3.814-2.98 7.833-5.19 11.235-6.234 3.23-.991 5.558-.823 6.473.348.916 1.172.516 3.471-1.228 6.366-1.836 3.048-4.952 6.413-8.766 9.393-3.814 2.98-7.833 5.19-11.235 6.233-3.23.992-5.558.824-6.474-.348z" fill="#fff"/><path d="M38.714 35.753c2.76-3.532-1.973-11.39-10.252-17.858-8.28-6.468-17.049-9.16-19.808-5.628-2.76 3.532 1.973 11.39 10.252 17.858 8.28 6.469 17.049 9.16 19.808 5.628zm-1.178-.92c-.916 1.17-3.244 1.339-6.474.347-3.402-1.044-7.42-3.254-11.235-6.233-3.814-2.98-6.93-6.345-8.766-9.393-1.744-2.895-2.144-5.194-1.229-6.366.916-1.171 3.243-1.34 6.474-.348 3.402 1.044 7.42 3.254 11.235 6.234 3.814 2.98 6.93 6.345 8.766 9.393 1.744 2.894 2.144 5.194 1.228 6.365z" fill="#fff"/><path d="M23.684 27.19a3.179 3.179 0 1 0 0-6.359 3.179 3.179 0 0 0 0 6.358z" fill="#fff"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(3)" d="M0 0H41.514V48H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
packages/frameworks/logos/react.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M24 28.631a4.278 4.278 0 1 0 0-8.556 4.278 4.278 0 0 0 0 8.556z" fill="#61DAFB"/><path d="M24 33.118c12.678 0 22.956-3.924 22.956-8.765 0-4.84-10.278-8.765-22.956-8.765-12.679 0-22.957 3.924-22.957 8.765 0 4.841 10.278 8.765 22.957 8.765z" stroke="#61DAFB"/><path d="M16.409 28.736c6.34 10.98 14.877 17.918 19.07 15.498 4.191-2.42 2.451-13.284-3.888-24.264C25.25 8.99 16.714 2.053 12.52 4.473 8.33 6.892 10.07 17.756 16.41 28.736z" stroke="#61DAFB"/><path d="M16.409 19.97c-6.34 10.98-8.08 21.843-3.887 24.264 4.192 2.42 12.73-4.518 19.069-15.498 6.34-10.98 8.08-21.843 3.887-24.264-4.192-2.42-12.73 4.519-19.069 15.498z" stroke="#61DAFB"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(0 3)" d="M0 0H48V42.706H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 874 B |
1
packages/frameworks/logos/saber.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="50" height="50" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M25 49c13.255 0 24-10.745 24-24S38.255 1 25 1 1 11.745 1 25s10.745 24 24 24z" fill="#00838F" stroke="#00838F" stroke-width=".308"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19.355 28.86l6.064-.508 1.14 2.633-3.913 3.882-3.29 4.626.433 5.617c-3.218-.786-5.361-1.56-6.43-2.324-1.068-.763-2.215-1.861-3.441-3.293l5.745-6.843h2.514l1.178-3.79z" fill="#FBB526"/><path fill-rule="evenodd" clip-rule="evenodd" d="M25.36 7.404a2.993 2.993 0 0 0-1.916 5.292v4.045h3.95v-4.15a2.993 2.993 0 0 0-2.035-5.187zm-1.318 2.992a1.317 1.317 0 1 1 2.634 0 1.317 1.317 0 0 1-2.634 0z" fill="#fff"/><path d="M27.373 37.265l-2.953 2.83 1.16 1.21 2.083-1.997 1.866.978 5.01.68.225-1.661-4.718-.64-2.673-1.4z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M2.736 25C2.736 12.704 12.704 2.736 25 2.736S47.264 12.704 47.264 25 37.296 47.264 25 47.264 2.736 37.296 2.736 25zM25 4.41C13.63 4.411 4.41 13.63 4.41 25a20.51 20.51 0 0 0 5.1 13.565l5.418-7.22h3.086l.255-2.69 3.259-.618v-9.62h-3.352V16.74h14.364v1.675H29.31V30.52l2.17.222 1.761 2.328h1.629l5.653 5.457A20.51 20.51 0 0 0 45.59 25c0-11.37-9.218-20.589-20.59-20.589zm7.43 30.364l-.023-.03h-2.293v-1.676h1.024l-.556-.735-4.404-.45-.974 2.587-2.52 1.545-.875-1.43 2.03-1.243 1.225-3.257.847.086-.694-1.129-5.398 1.024-.63 6.639-2.977 2.581-1.098-1.266 2.47-2.142.271-2.86h-2.088l-5.083 6.777A20.52 20.52 0 0 0 25 45.59a20.52 20.52 0 0 0 14.37-5.846l-5.178-4.998h-1.723l-.04.03zm-7.909-7.306l-1.556.296v-9.349h4.908v11.748l-1.834-2.983-.082.016v-3.993h-1.436v4.265z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
1
packages/frameworks/logos/sendgrid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="24" cy="24" r="24" fill="#2A4660"/><g clip-path="url(#clip0)"><path d="M28.187 28.006h-7.993V36h7.993v-7.994zm-7.993-7.994H12.2v7.994h7.994v-7.994z" fill="#99E1F4"/><path d="M20.194 28.006H12.2V36h7.994v-7.994z" fill="#1A82E2"/><path d="M36.2 20.012h-7.994v7.994H36.2v-7.994zM28.187 12h-7.993v7.994h7.993V12z" fill="#00B2E3"/><path d="M20.194 20.012v7.994h8.012v-7.994h-8.012z" fill="#009DD9"/><path d="M36.2 12h-7.994v7.994H36.2V12z" fill="#1A82E2"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(12 12)" d="M0 0H24V24H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 659 B |
4
packages/frameworks/logos/stencil.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<circle cx="24" cy="24" r="24" fill="#000"/>
|
||||
<path fill="#fff" d="M20.27 29H32l-6.34 7H14l6.27-7zM40 21H15.45L9 27h24.55L40 21zM23.32 12H35l-6.3 7H17l6.32-7z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 248 B |
9
packages/frameworks/logos/storybook.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="39" height="48" fill="none">
|
||||
<mask id="a" width="39" height="48" x="0" y="0" maskUnits="userSpaceOnUse">
|
||||
<path fill="#fff" d="M1.48 43.97L0 4.58A2.4 2.4 0 0 1 2.25 2.1L35.75 0a2.4 2.4 0 0 1 2.55 2.4v42.92a2.4 2.4 0 0 1-2.5 2.4L3.76 46.28a2.4 2.4 0 0 1-2.29-2.3z"/>
|
||||
</mask>
|
||||
<g mask="url(#a)">
|
||||
<path fill="#FF4785" d="M1.47 43.97L-.01 4.58A2.4 2.4 0 0 1 2.24 2.1L35.74 0a2.4 2.4 0 0 1 2.55 2.4v42.92a2.4 2.4 0 0 1-2.5 2.4L3.75 46.28a2.4 2.4 0 0 1-2.3-2.3z"/>
|
||||
<path fill="#fff" d="M28.26 5.87l.23-5.5L33.1 0l.2 5.68a.36.36 0 0 1-.58.29l-1.77-1.4-2.1 1.6a.36.36 0 0 1-.58-.3zm-5.88 12.12c0 .93 6.29.48 7.13-.17 0-6.36-3.41-9.7-9.66-9.7-6.24 0-9.74 3.4-9.74 8.48 0 8.86 11.96 9.03 11.96 13.87 0 1.35-.67 2.16-2.13 2.16-1.9 0-2.66-.97-2.57-4.28 0-.72-7.26-.94-7.48 0-.57 8.01 4.43 10.33 10.14 10.33 5.54 0 9.88-2.96 9.88-8.3 0-9.5-12.14-9.24-12.14-13.95 0-1.9 1.42-2.16 2.26-2.16.89 0 2.48.15 2.35 3.72z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 980 B |
1
packages/frameworks/logos/svelte.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="47" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M39.792 6.09C35.507-.027 27.044-1.84 20.924 2.048L10.177 8.88a12.297 12.297 0 0 0-5.57 8.237 12.922 12.922 0 0 0 1.28 8.315 12.313 12.313 0 0 0-1.844 4.596c-.619 3.47.19 7.043 2.244 9.91 4.287 6.119 12.75 7.931 18.869 4.042l10.747-6.831a12.295 12.295 0 0 0 5.57-8.237 12.927 12.927 0 0 0-1.28-8.315A12.31 12.31 0 0 0 42.037 16c.619-3.47-.19-7.043-2.245-9.91" fill="#FF3E00"/><path d="M19.873 40.52a8.55 8.55 0 0 1-9.165-3.388 7.866 7.866 0 0 1-1.35-5.962c.062-.339.148-.674.257-1.001l.202-.616.55.404a13.881 13.881 0 0 0 4.206 2.095l.4.121-.037.398a2.4 2.4 0 0 0 .433 1.594 2.575 2.575 0 0 0 2.76 1.022 2.37 2.37 0 0 0 .66-.29l10.75-6.833a2.233 2.233 0 0 0 1.011-1.492 2.377 2.377 0 0 0-.407-1.797 2.577 2.577 0 0 0-2.76-1.022 2.37 2.37 0 0 0-.66.289L22.62 26.65c-.675.428-1.411.75-2.183.956a8.55 8.55 0 0 1-9.166-3.388 7.866 7.866 0 0 1-1.35-5.962 7.394 7.394 0 0 1 3.35-4.954l10.75-6.834a7.844 7.844 0 0 1 2.185-.957 8.55 8.55 0 0 1 9.165 3.388 7.866 7.866 0 0 1 1.35 5.962c-.062.34-.148.674-.256 1.001l-.203.616-.55-.403a13.87 13.87 0 0 0-4.206-2.096l-.4-.121.037-.398a2.404 2.404 0 0 0-.433-1.594 2.575 2.575 0 0 0-2.76-1.022 2.37 2.37 0 0 0-.66.29l-10.75 6.833a2.229 2.229 0 0 0-1.01 1.492c-.112.63.034 1.277.406 1.797a2.577 2.577 0 0 0 2.76 1.023c.234-.063.457-.16.661-.29l4.102-2.607a7.834 7.834 0 0 1 2.183-.957 8.55 8.55 0 0 1 9.165 3.388 7.865 7.865 0 0 1 1.35 5.962 7.398 7.398 0 0 1-3.35 4.955l-10.75 6.833a7.842 7.842 0 0 1-2.185.958" fill="#fff"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(3.84)" d="M0 0H38.4V46.08H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
1
packages/frameworks/logos/umi.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="24" cy="24" r="24" fill="#1CA1FA"/><path d="M19.77 16.09h-2.625v11.086c0 3.656 2.613 6.234 6.843 6.234 4.254 0 6.856-2.578 6.856-6.234V16.09h-2.625v10.875c0 2.414-1.535 4.113-4.23 4.113-2.684 0-4.22-1.7-4.22-4.113V16.09z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 328 B |
4
packages/frameworks/logos/vanilla.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 24C0 37.2548 10.7452 48 24 48C37.2548 48 48 37.2548 48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24Z" fill="#F7DF1E"/>
|
||||
<path d="M27.6053 28.7181C28.5722 30.2968 29.8301 31.4571 32.0549 31.4571C33.9238 31.4571 35.1177 30.523 35.1177 29.2324C35.1177 27.6857 33.8911 27.1379 31.8339 26.2381L30.7063 25.7543C27.4514 24.3676 25.2891 22.6305 25.2891 18.9581C25.2891 15.5752 27.8667 13 31.8949 13C34.7627 13 36.8244 13.9981 38.3101 16.6114L34.7977 18.8667C34.0244 17.48 33.1901 16.9337 31.8949 16.9337C30.5737 16.9337 29.7364 17.7718 29.7364 18.8667C29.7364 20.2198 30.5745 20.7676 32.5097 21.6057L33.6373 22.0888C37.4697 23.7322 39.6335 25.4076 39.6335 29.1745C39.6335 33.2354 36.4434 35.4602 32.1592 35.4602C27.9703 35.4602 25.264 33.464 23.9398 30.8476L27.6053 28.7181ZM11.6716 29.109C12.3802 30.3661 13.0248 31.429 14.5745 31.429C16.0564 31.429 16.9912 30.8491 16.9912 28.5947V13.2575H21.5017V28.6556C21.5017 33.3261 18.7634 35.4518 14.7665 35.4518C11.155 35.4518 9.06362 33.5829 8 31.3318L11.6716 29.109Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
packages/frameworks/logos/vue.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M29.54 3L24 12.7 18.456 3H-.001l24 42L47.998 3H29.54z" fill="#41B883"/><path d="M29.54 3L24 12.7 18.456 3H9.599l14.4 25.2L38.398 3H29.54z" fill="#34495E"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(0 3)" d="M0 0H48V42H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 385 B |
4
packages/frameworks/logos/zola.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
|
||||
<circle cx="24" cy="24" r="24" fill="#191919"/>
|
||||
<path fill="#fff" d="M17.65 33h12.7v-2.26H21v-.2l9.14-12.66V16.1h-12.2v2.26h8.9v.2l-9.18 12.66V33z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 237 B |
6
packages/frameworks/package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "@now/frameworks",
|
||||
"version": "0.0.2-canary.0",
|
||||
"main": "frameworks.json",
|
||||
"license": "UNLICENSED"
|
||||
}
|
||||
@@ -6,6 +6,10 @@ const REDIRECT_FILE_NAME = '__now_routes_g4t5bY.json';
|
||||
exports.onPostBuild = async ({ store }) => {
|
||||
const { redirects, program } = store.getState();
|
||||
|
||||
if (!redirects.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const routes = [{ handle: 'filesystem' }];
|
||||
|
||||
for (const redirect of redirects) {
|
||||
@@ -22,30 +26,8 @@ exports.onPostBuild = async ({ store }) => {
|
||||
}
|
||||
}
|
||||
|
||||
// we implement gatsby's recommendations
|
||||
// https://www.gatsbyjs.org/docs/caching/
|
||||
const finalRoutes = [
|
||||
{
|
||||
src: '^/static/(.*)$',
|
||||
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '^/.*\\.(js|css)$',
|
||||
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '^/(sw\\.js|app-data\\.json|.*\\.html|page-data/.*)$',
|
||||
headers: { 'cache-control': 'public,max-age=0,must-revalidate' },
|
||||
continue: true,
|
||||
},
|
||||
...routes,
|
||||
{ src: '.*', status: 404, dest: '/404.html' },
|
||||
];
|
||||
|
||||
await writeFile(
|
||||
path.join(program.directory, 'public', REDIRECT_FILE_NAME),
|
||||
JSON.stringify(finalRoutes)
|
||||
JSON.stringify(routes)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gatsby-plugin-now",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.6-canary.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://zeit.co/guides/deploying-gatsby-with-now",
|
||||
|
||||
@@ -1,7 +1,24 @@
|
||||
# gatsby-plugin-now
|
||||
|
||||
⚠️ The use of this plugin is deprecated. ZEIT Now supports Gatsby Redirects out-of-the-box and does not require the use a plugin.
|
||||
|
||||
---
|
||||
|
||||
This plugin generates [Now Routes](https://zeit.co/docs/v2/advanced/routes) for [redirects](https://www.gatsbyjs.org/docs/actions/#createRedirect) you configured for to your Gatsby project.
|
||||
|
||||
### Usage
|
||||
|
||||
1. Install the plugin:
|
||||
|
||||
```
|
||||
npm install gatsby-plugin-now --save-dev
|
||||
```
|
||||
|
||||
2. Add it to the configuration file:
|
||||
|
||||
```
|
||||
// gatsby-config.js
|
||||
module.exports = {
|
||||
plugins: [
|
||||
'gatsby-plugin-now'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. [Deploy your project to ZEIT Now](https://www.gatsbyjs.org/docs/deploying-to-zeit-now/)
|
||||
|
||||
@@ -2,27 +2,6 @@
|
||||
|
||||
exports[`test generated now routes 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"continue": true,
|
||||
"headers": Object {
|
||||
"cache-control": "public,max-age=31536000,immutable",
|
||||
},
|
||||
"src": "^/static/(.*)$",
|
||||
},
|
||||
Object {
|
||||
"continue": true,
|
||||
"headers": Object {
|
||||
"cache-control": "public,max-age=31536000,immutable",
|
||||
},
|
||||
"src": "^/.*\\\\.(js|css)$",
|
||||
},
|
||||
Object {
|
||||
"continue": true,
|
||||
"headers": Object {
|
||||
"cache-control": "public,max-age=0,must-revalidate",
|
||||
},
|
||||
"src": "^/(sw\\\\.js|app-data\\\\.json|.*\\\\.html|page-data/.*)$",
|
||||
},
|
||||
Object {
|
||||
"headers": Object {
|
||||
"Location": "/",
|
||||
@@ -103,10 +82,5 @@ Array [
|
||||
"src": "/randorect",
|
||||
"status": 302,
|
||||
},
|
||||
Object {
|
||||
"dest": "/404.html",
|
||||
"src": ".*",
|
||||
"status": 404,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
1
packages/now-build-utils/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
?.js
|
||||
dist
|
||||
test/symlinks-out
|
||||
test/symlinks.zip
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
out="dist"
|
||||
|
||||
rm -rf "$out"
|
||||
|
||||
tsc
|
||||
|
||||
rm dist/index.js
|
||||
ncc build src/index.ts -o dist/main
|
||||
mv dist/main/index.js dist/index.js
|
||||
rm -rf dist/main
|
||||
rm "$out/index.js"
|
||||
ncc build "src/index.ts" -o "$out/main"
|
||||
mv "$out/main/index.js" "$out/index.js"
|
||||
rm -rf "$out/main"
|
||||
|
||||
5
packages/now-build-utils/jest.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.tsx?$': 'ts-jest',
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/build-utils",
|
||||
"version": "1.0.0",
|
||||
"version": "1.2.1-canary.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -12,32 +12,39 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "./build.sh",
|
||||
"test-unit": "jest --env node --verbose --runInBand test/unit.test.js",
|
||||
"test-unit": "jest --env node --verbose --runInBand test/unit.*test.*",
|
||||
"test-integration-once": "jest --env node --verbose --runInBand test/integration.test.js",
|
||||
"prepublishOnly": "./build.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iarna/toml": "2.2.3",
|
||||
"@types/async-retry": "^1.2.1",
|
||||
"@types/cross-spawn": "6.0.0",
|
||||
"@types/end-of-stream": "^1.4.0",
|
||||
"@types/fs-extra": "^5.0.5",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/jest": "24.0.22",
|
||||
"@types/js-yaml": "3.12.1",
|
||||
"@types/multistream": "2.1.1",
|
||||
"@types/node-fetch": "^2.1.6",
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/yazl": "^2.4.1",
|
||||
"aggregate-error": "3.0.1",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "2.1.4",
|
||||
"boxen": "4.2.0",
|
||||
"cross-spawn": "6.0.5",
|
||||
"end-of-stream": "1.4.1",
|
||||
"execa": "^1.0.0",
|
||||
"fs-extra": "7.0.0",
|
||||
"glob": "7.1.3",
|
||||
"into-stream": "5.0.0",
|
||||
"jest": "24.9.0",
|
||||
"js-yaml": "3.13.1",
|
||||
"minimatch": "3.0.4",
|
||||
"multistream": "2.1.1",
|
||||
"node-fetch": "2.2.0",
|
||||
"semver": "6.1.1",
|
||||
"ts-jest": "24.1.0",
|
||||
"typescript": "3.5.2",
|
||||
"yazl": "2.4.3"
|
||||
}
|
||||
|
||||
432
packages/now-build-utils/src/detect-builders-legacy.ts
Normal file
@@ -0,0 +1,432 @@
|
||||
import minimatch from 'minimatch';
|
||||
import { valid as validSemver } from 'semver';
|
||||
import { PackageJson, Builder, Config, BuilderFunctions } from './types';
|
||||
|
||||
interface ErrorResponse {
|
||||
code: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface Options {
|
||||
tag?: 'canary' | 'latest' | string;
|
||||
functions?: BuilderFunctions;
|
||||
}
|
||||
|
||||
const src = 'package.json';
|
||||
const config: Config = { zeroConfig: true };
|
||||
|
||||
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
|
||||
code: 'missing_build_script',
|
||||
message:
|
||||
'Your `package.json` file is missing a `build` property inside the `scripts` property.' +
|
||||
'\nMore details: https://zeit.co/docs/v2/platform/frequently-asked-questions#missing-build-script',
|
||||
};
|
||||
|
||||
// Static builders are special cased in `@now/static-build`
|
||||
function getBuilders({ tag }: Options = {}): Map<string, Builder> {
|
||||
const withTag = tag ? `@${tag}` : '';
|
||||
const config = { zeroConfig: true };
|
||||
|
||||
return new Map<string, Builder>([
|
||||
['next', { src, use: `@now/next${withTag}`, config }],
|
||||
]);
|
||||
}
|
||||
|
||||
// Must be a function to ensure that the returned
|
||||
// object won't be a reference
|
||||
function getApiBuilders({ tag }: Pick<Options, 'tag'> = {}): Builder[] {
|
||||
const withTag = tag ? `@${tag}` : '';
|
||||
const config = { zeroConfig: true };
|
||||
|
||||
return [
|
||||
{ src: 'api/**/*.js', use: `@now/node${withTag}`, config },
|
||||
{ src: 'api/**/*.ts', use: `@now/node${withTag}`, config },
|
||||
{ src: 'api/**/*.go', use: `@now/go${withTag}`, config },
|
||||
{ src: 'api/**/*.py', use: `@now/python${withTag}`, config },
|
||||
{ src: 'api/**/*.rb', use: `@now/ruby${withTag}`, config },
|
||||
];
|
||||
}
|
||||
|
||||
function hasPublicDirectory(files: string[]) {
|
||||
return files.some(name => name.startsWith('public/'));
|
||||
}
|
||||
|
||||
function hasBuildScript(pkg: PackageJson | undefined) {
|
||||
const { scripts = {} } = pkg || {};
|
||||
return Boolean(scripts && scripts['build']);
|
||||
}
|
||||
|
||||
function getApiFunctionBuilder(
|
||||
file: string,
|
||||
prevBuilder: Builder | undefined,
|
||||
{ functions = {} }: Pick<Options, 'functions'>
|
||||
) {
|
||||
const key = Object.keys(functions).find(
|
||||
k => file === k || minimatch(file, k)
|
||||
);
|
||||
const fn = key ? functions[key] : undefined;
|
||||
|
||||
if (!fn || (!fn.runtime && !prevBuilder)) {
|
||||
return prevBuilder;
|
||||
}
|
||||
|
||||
const src = (prevBuilder && prevBuilder.src) || file;
|
||||
const use = fn.runtime || (prevBuilder && prevBuilder.use);
|
||||
|
||||
const config: Config = { zeroConfig: true };
|
||||
|
||||
if (key) {
|
||||
Object.assign(config, {
|
||||
functions: {
|
||||
[key]: fn,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const { includeFiles, excludeFiles } = fn;
|
||||
|
||||
if (includeFiles) Object.assign(config, { includeFiles });
|
||||
if (excludeFiles) Object.assign(config, { excludeFiles });
|
||||
|
||||
return use ? { use, src, config } : prevBuilder;
|
||||
}
|
||||
|
||||
async function detectFrontBuilder(
|
||||
pkg: PackageJson,
|
||||
builders: Builder[],
|
||||
options: Options
|
||||
): Promise<Builder> {
|
||||
const { tag } = options;
|
||||
const withTag = tag ? `@${tag}` : '';
|
||||
for (const [dependency, builder] of getBuilders(options)) {
|
||||
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
|
||||
|
||||
// Return the builder when a dependency matches
|
||||
if (deps[dependency]) {
|
||||
if (options.functions) {
|
||||
Object.entries(options.functions).forEach(([key, func]) => {
|
||||
// When the builder is not used yet we'll use it for the frontend
|
||||
if (
|
||||
builders.every(
|
||||
b => !(b.config && b.config.functions && b.config.functions[key])
|
||||
)
|
||||
) {
|
||||
if (!builder.config) builder.config = {};
|
||||
if (!builder.config.functions) builder.config.functions = {};
|
||||
builder.config.functions[key] = { ...func };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
// By default we'll choose the `static-build` builder
|
||||
return { src, use: `@now/static-build${withTag}`, config };
|
||||
}
|
||||
|
||||
// Files that match a specific pattern will get ignored
|
||||
export function getIgnoreApiFilter(optionsOrBuilders: Options | Builder[]) {
|
||||
const possiblePatterns: string[] = getApiBuilders().map(b => b.src);
|
||||
|
||||
if (Array.isArray(optionsOrBuilders)) {
|
||||
optionsOrBuilders.forEach(({ src }) => possiblePatterns.push(src));
|
||||
} else if (optionsOrBuilders.functions) {
|
||||
Object.keys(optionsOrBuilders.functions).forEach(p =>
|
||||
possiblePatterns.push(p)
|
||||
);
|
||||
}
|
||||
|
||||
return (file: string) => {
|
||||
if (!file.startsWith('api/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.includes('/.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.includes('/_')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.endsWith('.d.ts')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (possiblePatterns.every(p => !(file === p || minimatch(file, p)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
// We need to sort the file paths by alphabet to make
|
||||
// sure the routes stay in the same order e.g. for deduping
|
||||
export function sortFiles(fileA: string, fileB: string) {
|
||||
return fileA.localeCompare(fileB);
|
||||
}
|
||||
|
||||
async function detectApiBuilders(
|
||||
files: string[],
|
||||
options: Options
|
||||
): Promise<Builder[]> {
|
||||
const builds = files
|
||||
.sort(sortFiles)
|
||||
.filter(getIgnoreApiFilter(options))
|
||||
.map(file => {
|
||||
const apiBuilders = getApiBuilders(options);
|
||||
const apiBuilder = apiBuilders.find(b => minimatch(file, b.src));
|
||||
const fnBuilder = getApiFunctionBuilder(file, apiBuilder, options);
|
||||
return fnBuilder ? { ...fnBuilder, src: file } : null;
|
||||
});
|
||||
|
||||
return builds.filter(Boolean) as Builder[];
|
||||
}
|
||||
|
||||
// When a package has files that conflict with `/api` routes
|
||||
// e.g. Next.js pages/api we'll check it here and return an error.
|
||||
async function checkConflictingFiles(
|
||||
files: string[],
|
||||
builders: Builder[]
|
||||
): Promise<ErrorResponse | null> {
|
||||
// For Next.js
|
||||
if (builders.some(b => b.use.startsWith('@now/next'))) {
|
||||
const hasApiPages = files.some(file => file.startsWith('pages/api/'));
|
||||
const hasApiBuilders = builders.some(b => b.src.startsWith('api/'));
|
||||
|
||||
if (hasApiPages && hasApiBuilders) {
|
||||
return {
|
||||
code: 'conflicting_files',
|
||||
message:
|
||||
'It is not possible to use `api` and `pages/api` at the same time, please only use one option',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// When e.g. Next.js receives a `functions` property it has to make sure,
|
||||
// that it can handle those files, otherwise there are unused functions.
|
||||
async function checkUnusedFunctionsOnFrontendBuilder(
|
||||
files: string[],
|
||||
builder: Builder
|
||||
): Promise<ErrorResponse | null> {
|
||||
const { config: { functions = undefined } = {} } = builder;
|
||||
|
||||
if (!functions) return null;
|
||||
|
||||
if (builder.use.startsWith('@now/next')) {
|
||||
const matchingFiles = files.filter(file =>
|
||||
Object.keys(functions).some(key => file === key || minimatch(file, key))
|
||||
);
|
||||
|
||||
for (const matchedFile of matchingFiles) {
|
||||
if (
|
||||
!matchedFile.startsWith('src/pages/') &&
|
||||
!matchedFile.startsWith('pages/')
|
||||
) {
|
||||
return {
|
||||
code: 'unused_function',
|
||||
message: `The function for ${matchedFile} can't be handled by any builder`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateFunctions(files: string[], { functions = {} }: Options) {
|
||||
const apiBuilders = getApiBuilders();
|
||||
|
||||
for (const [path, func] of Object.entries(functions)) {
|
||||
if (path.length > 256) {
|
||||
return {
|
||||
code: 'invalid_function_glob',
|
||||
message: 'Function globs must be less than 256 characters long.',
|
||||
};
|
||||
}
|
||||
|
||||
if (!func || typeof func !== 'object') {
|
||||
return {
|
||||
code: 'invalid_function',
|
||||
message: 'Function must be an object.',
|
||||
};
|
||||
}
|
||||
|
||||
if (Object.keys(func).length === 0) {
|
||||
return {
|
||||
code: 'invalid_function',
|
||||
message: 'Function must contain at least one property.',
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
func.maxDuration !== undefined &&
|
||||
(func.maxDuration < 1 ||
|
||||
func.maxDuration > 900 ||
|
||||
!Number.isInteger(func.maxDuration))
|
||||
) {
|
||||
return {
|
||||
code: 'invalid_function_duration',
|
||||
message: 'Functions must have a duration between 1 and 900.',
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
func.memory !== undefined &&
|
||||
(func.memory < 128 || func.memory > 3008 || func.memory % 64 !== 0)
|
||||
) {
|
||||
return {
|
||||
code: 'invalid_function_memory',
|
||||
message:
|
||||
'Functions must have a memory value between 128 and 3008 in steps of 64.',
|
||||
};
|
||||
}
|
||||
|
||||
if (path.startsWith('/')) {
|
||||
return {
|
||||
code: 'invalid_function_source',
|
||||
message: `The function path "${path}" is invalid. The path must be relative to your project root and therefore cannot start with a slash.`,
|
||||
};
|
||||
}
|
||||
|
||||
if (files.some(f => f === path || minimatch(f, path)) === false) {
|
||||
return {
|
||||
code: 'invalid_function_source',
|
||||
message: `No source file matched the function for ${path}.`,
|
||||
};
|
||||
}
|
||||
|
||||
if (func.runtime !== undefined) {
|
||||
const tag = `${func.runtime}`.split('@').pop();
|
||||
|
||||
if (!tag || !validSemver(tag)) {
|
||||
return {
|
||||
code: 'invalid_function_runtime',
|
||||
message:
|
||||
'Function Runtimes must have a valid version, for example `now-php@1.0.0`.',
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
apiBuilders.some(b => func.runtime && func.runtime.startsWith(b.use))
|
||||
) {
|
||||
return {
|
||||
code: 'invalid_function_runtime',
|
||||
message: `The function Runtime ${func.runtime} is not a Community Runtime and must not be specified.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (func.includeFiles !== undefined) {
|
||||
if (typeof func.includeFiles !== 'string') {
|
||||
return {
|
||||
code: 'invalid_function_property',
|
||||
message: `The property \`includeFiles\` must be a string.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (func.excludeFiles !== undefined) {
|
||||
if (typeof func.excludeFiles !== 'string') {
|
||||
return {
|
||||
code: 'invalid_function_property',
|
||||
message: `The property \`excludeFiles\` must be a string.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// When zero config is used we can call this function
|
||||
// to determine what builders to use
|
||||
export async function detectBuildersLegacy(
|
||||
files: string[],
|
||||
pkg?: PackageJson | undefined | null,
|
||||
options: Options = {}
|
||||
): Promise<{
|
||||
builders: Builder[] | null;
|
||||
errors: ErrorResponse[] | null;
|
||||
warnings: ErrorResponse[];
|
||||
}> {
|
||||
const errors: ErrorResponse[] = [];
|
||||
const warnings: ErrorResponse[] = [];
|
||||
|
||||
const functionError = validateFunctions(files, options);
|
||||
|
||||
if (functionError) {
|
||||
return {
|
||||
builders: null,
|
||||
errors: [functionError],
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
|
||||
// Detect all builders for the `api` directory before anything else
|
||||
const builders = await detectApiBuilders(files, options);
|
||||
|
||||
if (pkg && hasBuildScript(pkg)) {
|
||||
const frontendBuilder = await detectFrontBuilder(pkg, builders, options);
|
||||
builders.push(frontendBuilder);
|
||||
|
||||
const conflictError = await checkConflictingFiles(files, builders);
|
||||
|
||||
if (conflictError) {
|
||||
warnings.push(conflictError);
|
||||
}
|
||||
|
||||
const unusedFunctionError = await checkUnusedFunctionsOnFrontendBuilder(
|
||||
files,
|
||||
frontendBuilder
|
||||
);
|
||||
|
||||
if (unusedFunctionError) {
|
||||
return {
|
||||
builders: null,
|
||||
errors: [unusedFunctionError],
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (pkg && builders.length === 0) {
|
||||
// We only show this error when there are no api builders
|
||||
// since the dependencies of the pkg could be used for those
|
||||
errors.push(MISSING_BUILD_SCRIPT_ERROR);
|
||||
return { errors, warnings, builders: null };
|
||||
}
|
||||
|
||||
// We allow a `public` directory
|
||||
// when there are no build steps
|
||||
if (hasPublicDirectory(files)) {
|
||||
builders.push({
|
||||
use: '@now/static',
|
||||
src: 'public/**/*',
|
||||
config,
|
||||
});
|
||||
} else if (
|
||||
builders.length > 0 &&
|
||||
files.some(f => !f.startsWith('api/') && f !== 'package.json')
|
||||
) {
|
||||
// Everything besides the api directory
|
||||
// and package.json can be served as static files
|
||||
builders.push({
|
||||
use: '@now/static',
|
||||
src: '!{api/**,package.json}',
|
||||
config,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
builders: builders.length ? builders : null,
|
||||
errors: errors.length ? errors : null,
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
import minimatch from 'minimatch';
|
||||
import { valid as validSemver } from 'semver';
|
||||
import { PackageJson, Builder, Config, BuilderFunctions } from './types';
|
||||
import {
|
||||
Builder,
|
||||
Config,
|
||||
BuilderFunctions,
|
||||
DetectorResult,
|
||||
DetectorOutput,
|
||||
} from './types';
|
||||
|
||||
interface ErrorResponse {
|
||||
code: string;
|
||||
@@ -12,26 +18,6 @@ interface Options {
|
||||
functions?: BuilderFunctions;
|
||||
}
|
||||
|
||||
const src = 'package.json';
|
||||
const config: Config = { zeroConfig: true };
|
||||
|
||||
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
|
||||
code: 'missing_build_script',
|
||||
message:
|
||||
'Your `package.json` file is missing a `build` property inside the `script` property.' +
|
||||
'\nMore details: https://zeit.co/docs/v2/platform/frequently-asked-questions#missing-build-script',
|
||||
};
|
||||
|
||||
// Static builders are special cased in `@now/static-build`
|
||||
function getBuilders({ tag }: Options = {}): Map<string, Builder> {
|
||||
const withTag = tag ? `@${tag}` : '';
|
||||
const config = { zeroConfig: true };
|
||||
|
||||
return new Map<string, Builder>([
|
||||
['next', { src, use: `@now/next${withTag}`, config }],
|
||||
]);
|
||||
}
|
||||
|
||||
// Must be a function to ensure that the returned
|
||||
// object won't be a reference
|
||||
function getApiBuilders({ tag }: Pick<Options, 'tag'> = {}): Builder[] {
|
||||
@@ -47,13 +33,8 @@ function getApiBuilders({ tag }: Pick<Options, 'tag'> = {}): Builder[] {
|
||||
];
|
||||
}
|
||||
|
||||
function hasPublicDirectory(files: string[]) {
|
||||
return files.some(name => name.startsWith('public/'));
|
||||
}
|
||||
|
||||
function hasBuildScript(pkg: PackageJson | undefined) {
|
||||
const { scripts = {} } = pkg || {};
|
||||
return Boolean(scripts && scripts['build']);
|
||||
function hasDirectory(fileName: string, files: string[]) {
|
||||
return files.some(name => name.startsWith(`${fileName}/`));
|
||||
}
|
||||
|
||||
function getApiFunctionBuilder(
|
||||
@@ -91,37 +72,71 @@ function getApiFunctionBuilder(
|
||||
return use ? { use, src, config } : prevBuilder;
|
||||
}
|
||||
|
||||
async function detectFrontBuilder(
|
||||
pkg: PackageJson,
|
||||
function detectFrontBuilder(
|
||||
detectorResult: Partial<DetectorOutput>,
|
||||
builders: Builder[],
|
||||
files: string[],
|
||||
options: Options
|
||||
): Promise<Builder> {
|
||||
for (const [dependency, builder] of getBuilders(options)) {
|
||||
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
|
||||
): Builder {
|
||||
const { tag } = options;
|
||||
const withTag = tag ? `@${tag}` : '';
|
||||
|
||||
// Return the builder when a dependency matches
|
||||
if (deps[dependency]) {
|
||||
if (options.functions) {
|
||||
Object.entries(options.functions).forEach(([key, func]) => {
|
||||
// When the builder is not used yet we'll use it for the frontend
|
||||
if (
|
||||
builders.every(
|
||||
b => !(b.config && b.config.functions && b.config.functions[key])
|
||||
)
|
||||
) {
|
||||
if (!builder.config) builder.config = {};
|
||||
if (!builder.config.functions) builder.config.functions = {};
|
||||
builder.config.functions[key] = { ...func };
|
||||
}
|
||||
});
|
||||
const {
|
||||
framework,
|
||||
buildCommand,
|
||||
outputDirectory,
|
||||
devCommand,
|
||||
} = detectorResult;
|
||||
|
||||
const frameworkSlug = framework ? framework.slug : null;
|
||||
|
||||
const config: Config = {
|
||||
zeroConfig: true,
|
||||
};
|
||||
|
||||
if (framework) {
|
||||
config.framework = framework;
|
||||
}
|
||||
|
||||
if (devCommand) {
|
||||
config.devCommand = devCommand;
|
||||
}
|
||||
|
||||
if (buildCommand) {
|
||||
config.buildCommand = buildCommand;
|
||||
}
|
||||
|
||||
if (outputDirectory) {
|
||||
config.outputDirectory = outputDirectory;
|
||||
}
|
||||
|
||||
// All unused functions will be used for the frontend
|
||||
if (options.functions) {
|
||||
Object.entries(options.functions).forEach(([key, func]) => {
|
||||
if (
|
||||
builders.every(
|
||||
b => !(b.config && b.config.functions && b.config.functions[key])
|
||||
)
|
||||
) {
|
||||
config.functions = config.functions || {};
|
||||
config.functions[key] = { ...func };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return builder;
|
||||
if (frameworkSlug === 'next') {
|
||||
return { src: 'package.json', use: `@now/next${withTag}`, config };
|
||||
}
|
||||
|
||||
if (frameworkSlug === 'hugo') {
|
||||
const configFiles = new Set(['config.yaml', 'config.toml', 'config.json']);
|
||||
const source = files.find(file => configFiles.has(file));
|
||||
if (source) {
|
||||
return { src: source, use: `@now/static-build${withTag}`, config };
|
||||
}
|
||||
}
|
||||
|
||||
// By default we'll choose the `static-build` builder
|
||||
return { src, use: '@now/static-build', config };
|
||||
return { src: 'package.json', use: `@now/static-build${withTag}`, config };
|
||||
}
|
||||
|
||||
// Files that match a specific pattern will get ignored
|
||||
@@ -137,10 +152,6 @@ export function getIgnoreApiFilter(optionsOrBuilders: Options | Builder[]) {
|
||||
}
|
||||
|
||||
return (file: string) => {
|
||||
if (!file.startsWith('api/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.includes('/.')) {
|
||||
return false;
|
||||
}
|
||||
@@ -167,10 +178,7 @@ export function sortFiles(fileA: string, fileB: string) {
|
||||
return fileA.localeCompare(fileB);
|
||||
}
|
||||
|
||||
async function detectApiBuilders(
|
||||
files: string[],
|
||||
options: Options
|
||||
): Promise<Builder[]> {
|
||||
function detectApiBuilders(files: string[], options: Options): Builder[] {
|
||||
const builds = files
|
||||
.sort(sortFiles)
|
||||
.filter(getIgnoreApiFilter(options))
|
||||
@@ -186,10 +194,10 @@ async function detectApiBuilders(
|
||||
|
||||
// When a package has files that conflict with `/api` routes
|
||||
// e.g. Next.js pages/api we'll check it here and return an error.
|
||||
async function checkConflictingFiles(
|
||||
function checkConflictingFiles(
|
||||
files: string[],
|
||||
builders: Builder[]
|
||||
): Promise<ErrorResponse | null> {
|
||||
): ErrorResponse | null {
|
||||
// For Next.js
|
||||
if (builders.some(b => b.use.startsWith('@now/next'))) {
|
||||
const hasApiPages = files.some(file => file.startsWith('pages/api/'));
|
||||
@@ -209,10 +217,10 @@ async function checkConflictingFiles(
|
||||
|
||||
// When e.g. Next.js receives a `functions` property it has to make sure,
|
||||
// that it can handle those files, otherwise there are unused functions.
|
||||
async function checkUnusedFunctionsOnFrontendBuilder(
|
||||
function checkUnusedFunctionsOnFrontendBuilder(
|
||||
files: string[],
|
||||
builder: Builder
|
||||
): Promise<ErrorResponse | null> {
|
||||
): ErrorResponse | null {
|
||||
const { config: { functions = undefined } = {} } = builder;
|
||||
|
||||
if (!functions) return null;
|
||||
@@ -229,7 +237,9 @@ async function checkUnusedFunctionsOnFrontendBuilder(
|
||||
) {
|
||||
return {
|
||||
code: 'unused_function',
|
||||
message: `The function for ${matchedFile} can't be handled by any builder`,
|
||||
message:
|
||||
`The function for "${matchedFile}" can't be handled by any runtime. ` +
|
||||
`Please provide one with the "runtime" option.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -239,8 +249,6 @@ async function checkUnusedFunctionsOnFrontendBuilder(
|
||||
}
|
||||
|
||||
function validateFunctions(files: string[], { functions = {} }: Options) {
|
||||
const apiBuilders = getApiBuilders();
|
||||
|
||||
for (const [path, func] of Object.entries(functions)) {
|
||||
if (path.length > 256) {
|
||||
return {
|
||||
@@ -286,6 +294,13 @@ function validateFunctions(files: string[], { functions = {} }: Options) {
|
||||
};
|
||||
}
|
||||
|
||||
if (path.startsWith('/')) {
|
||||
return {
|
||||
code: 'invalid_function_source',
|
||||
message: `The function path "${path}" is invalid. The path must be relative to your project root and therefore cannot start with a slash.`,
|
||||
};
|
||||
}
|
||||
|
||||
if (files.some(f => f === path || minimatch(f, path)) === false) {
|
||||
return {
|
||||
code: 'invalid_function_source',
|
||||
@@ -303,22 +318,13 @@ function validateFunctions(files: string[], { functions = {} }: Options) {
|
||||
'Function Runtimes must have a valid version, for example `now-php@1.0.0`.',
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
apiBuilders.some(b => func.runtime && func.runtime.startsWith(b.use))
|
||||
) {
|
||||
return {
|
||||
code: 'invalid_function_runtime',
|
||||
message: `The function Runtime ${func.runtime} is not a Community Runtime and must not be specified.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (func.includeFiles !== undefined) {
|
||||
if (typeof func.includeFiles !== 'string') {
|
||||
return {
|
||||
code: 'invalid_function_property',
|
||||
message: `The property \`includeFiles\` must be a string.`
|
||||
message: `The property \`includeFiles\` must be a string.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -327,7 +333,7 @@ function validateFunctions(files: string[], { functions = {} }: Options) {
|
||||
if (typeof func.excludeFiles !== 'string') {
|
||||
return {
|
||||
code: 'invalid_function_property',
|
||||
message: `The property \`excludeFiles\` must be a string.`
|
||||
message: `The property \`excludeFiles\` must be a string.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -340,7 +346,7 @@ function validateFunctions(files: string[], { functions = {} }: Options) {
|
||||
// to determine what builders to use
|
||||
export async function detectBuilders(
|
||||
files: string[],
|
||||
pkg?: PackageJson | undefined | null,
|
||||
detectorResult: Partial<DetectorResult> | null = null,
|
||||
options: Options = {}
|
||||
): Promise<{
|
||||
builders: Builder[] | null;
|
||||
@@ -361,19 +367,24 @@ export async function detectBuilders(
|
||||
}
|
||||
|
||||
// Detect all builders for the `api` directory before anything else
|
||||
const builders = await detectApiBuilders(files, options);
|
||||
const builders = detectApiBuilders(files, options);
|
||||
|
||||
if (pkg && hasBuildScript(pkg)) {
|
||||
const frontendBuilder = await detectFrontBuilder(pkg, builders, options);
|
||||
if (detectorResult && detectorResult.buildCommand) {
|
||||
const frontendBuilder = detectFrontBuilder(
|
||||
detectorResult,
|
||||
builders,
|
||||
files,
|
||||
options
|
||||
);
|
||||
builders.push(frontendBuilder);
|
||||
|
||||
const conflictError = await checkConflictingFiles(files, builders);
|
||||
const conflictError = checkConflictingFiles(files, builders);
|
||||
|
||||
if (conflictError) {
|
||||
warnings.push(conflictError);
|
||||
}
|
||||
|
||||
const unusedFunctionError = await checkUnusedFunctionsOnFrontendBuilder(
|
||||
const unusedFunctionError = checkUnusedFunctionsOnFrontendBuilder(
|
||||
files,
|
||||
frontendBuilder
|
||||
);
|
||||
@@ -385,34 +396,35 @@ export async function detectBuilders(
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (pkg && builders.length === 0) {
|
||||
// We only show this error when there are no api builders
|
||||
// since the dependencies of the pkg could be used for those
|
||||
errors.push(MISSING_BUILD_SCRIPT_ERROR);
|
||||
return { errors, warnings, builders: null };
|
||||
}
|
||||
|
||||
// We allow a `public` directory
|
||||
// when there are no build steps
|
||||
if (hasPublicDirectory(files)) {
|
||||
builders.push({
|
||||
use: '@now/static',
|
||||
src: 'public/**/*',
|
||||
config,
|
||||
});
|
||||
} else if (
|
||||
builders.length > 0 &&
|
||||
files.some(f => !f.startsWith('api/') && f !== 'package.json')
|
||||
) {
|
||||
// Everything besides the api directory
|
||||
// and package.json can be served as static files
|
||||
builders.push({
|
||||
use: '@now/static',
|
||||
src: '!{api/**,package.json}',
|
||||
config,
|
||||
});
|
||||
}
|
||||
} else if (
|
||||
detectorResult &&
|
||||
detectorResult.outputDirectory &&
|
||||
hasDirectory(detectorResult.outputDirectory, files)
|
||||
) {
|
||||
builders.push({
|
||||
use: '@now/static',
|
||||
src: [...detectorResult.outputDirectory.split('/'), '**', '*']
|
||||
.filter(Boolean)
|
||||
.join('/'),
|
||||
config: { zeroConfig: true },
|
||||
});
|
||||
} else if (hasDirectory('public', files)) {
|
||||
builders.push({
|
||||
use: '@now/static',
|
||||
src: 'public/**/*',
|
||||
config: { zeroConfig: true },
|
||||
});
|
||||
} else if (
|
||||
builders.length > 0 &&
|
||||
files.some(f => !f.startsWith('api/') && f !== 'package.json')
|
||||
) {
|
||||
// Everything besides the api directory
|
||||
// and package.json can be served as static files
|
||||
builders.push({
|
||||
use: '@now/static',
|
||||
src: '!{api/**,package.json}',
|
||||
config: { zeroConfig: true },
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
299
packages/now-build-utils/src/detect-routes-legacy.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
import { parse as parsePath } from 'path';
|
||||
import { Route } from '@now/routing-utils';
|
||||
import { Builder } from './types';
|
||||
import { getIgnoreApiFilter, sortFiles } from './detect-builders-legacy';
|
||||
|
||||
function escapeName(name: string) {
|
||||
const special = '[]^$.|?*+()'.split('');
|
||||
|
||||
for (const char of special) {
|
||||
name = name.replace(new RegExp(`\\${char}`, 'g'), `\\${char}`);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function joinPath(...segments: string[]) {
|
||||
const joinedPath = segments.join('/');
|
||||
return joinedPath.replace(/\/{2,}/g, '/');
|
||||
}
|
||||
|
||||
function concatArrayOfText(texts: string[]): string {
|
||||
if (texts.length <= 2) {
|
||||
return texts.join(' and ');
|
||||
}
|
||||
|
||||
const last = texts.pop();
|
||||
return `${texts.join(', ')}, and ${last}`;
|
||||
}
|
||||
|
||||
// Takes a filename or foldername, strips the extension
|
||||
// gets the part between the "[]" brackets.
|
||||
// It will return `null` if there are no brackets
|
||||
// and therefore no segment.
|
||||
function getSegmentName(segment: string): string | null {
|
||||
const { name } = parsePath(segment);
|
||||
|
||||
if (name.startsWith('[') && name.endsWith(']')) {
|
||||
return name.slice(1, -1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function createRouteFromPath(filePath: string): Route {
|
||||
const parts = filePath.split('/');
|
||||
|
||||
let counter = 1;
|
||||
const query: string[] = [];
|
||||
|
||||
const srcParts = parts.map((segment, index): string => {
|
||||
const name = getSegmentName(segment);
|
||||
const isLast = index === parts.length - 1;
|
||||
|
||||
if (name !== null) {
|
||||
// We can't use `URLSearchParams` because `$` would get escaped
|
||||
query.push(`${name}=$${counter++}`);
|
||||
return `([^\\/]+)`;
|
||||
} else if (isLast) {
|
||||
const { name: fileName, ext } = parsePath(segment);
|
||||
const isIndex = fileName === 'index';
|
||||
const prefix = isIndex ? '\\/' : '';
|
||||
|
||||
const names = [
|
||||
isIndex ? prefix : `${fileName}\\/`,
|
||||
prefix + escapeName(fileName),
|
||||
prefix + escapeName(fileName) + escapeName(ext),
|
||||
].filter(Boolean);
|
||||
|
||||
// Either filename with extension, filename without extension
|
||||
// or nothing when the filename is `index`
|
||||
return `(${names.join('|')})${isIndex ? '?' : ''}`;
|
||||
}
|
||||
|
||||
return segment;
|
||||
});
|
||||
|
||||
const { name: fileName } = parsePath(filePath);
|
||||
const isIndex = fileName === 'index';
|
||||
|
||||
const src = isIndex
|
||||
? `^/${srcParts.slice(0, -1).join('/')}${srcParts.slice(-1)[0]}$`
|
||||
: `^/${srcParts.join('/')}$`;
|
||||
|
||||
const dest = `/${filePath}${query.length ? '?' : ''}${query.join('&')}`;
|
||||
|
||||
return { src, dest };
|
||||
}
|
||||
|
||||
// Check if the path partially matches and has the same
|
||||
// name for the path segment at the same position
|
||||
function partiallyMatches(pathA: string, pathB: string): boolean {
|
||||
const partsA = pathA.split('/');
|
||||
const partsB = pathB.split('/');
|
||||
|
||||
const long = partsA.length > partsB.length ? partsA : partsB;
|
||||
const short = long === partsA ? partsB : partsA;
|
||||
|
||||
let index = 0;
|
||||
|
||||
for (const segmentShort of short) {
|
||||
const segmentLong = long[index];
|
||||
|
||||
const nameLong = getSegmentName(segmentLong);
|
||||
const nameShort = getSegmentName(segmentShort);
|
||||
|
||||
// If there are no segments or the paths differ we
|
||||
// return as they are not matching
|
||||
if (segmentShort !== segmentLong && (!nameLong || !nameShort)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nameLong !== nameShort) {
|
||||
return true;
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Counts how often a path occurs when all placeholders
|
||||
// got resolved, so we can check if they have conflicts
|
||||
function pathOccurrences(filePath: string, files: string[]): string[] {
|
||||
const getAbsolutePath = (unresolvedPath: string): string => {
|
||||
const { dir, name } = parsePath(unresolvedPath);
|
||||
const parts = joinPath(dir, name).split('/');
|
||||
return parts.map(part => part.replace(/\[.*\]/, '1')).join('/');
|
||||
};
|
||||
|
||||
const currentAbsolutePath = getAbsolutePath(filePath);
|
||||
|
||||
return files.reduce((prev: string[], file: string): string[] => {
|
||||
const absolutePath = getAbsolutePath(file);
|
||||
|
||||
if (absolutePath === currentAbsolutePath) {
|
||||
prev.push(file);
|
||||
} else if (partiallyMatches(filePath, file)) {
|
||||
prev.push(file);
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, []);
|
||||
}
|
||||
|
||||
// Checks if a placeholder with the same name is used
|
||||
// multiple times inside the same path
|
||||
function getConflictingSegment(filePath: string): string | null {
|
||||
const segments = new Set<string>();
|
||||
|
||||
for (const segment of filePath.split('/')) {
|
||||
const name = getSegmentName(segment);
|
||||
|
||||
if (name !== null && segments.has(name)) {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
segments.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function sortFilesBySegmentCount(fileA: string, fileB: string): number {
|
||||
const lengthA = fileA.split('/').length;
|
||||
const lengthB = fileB.split('/').length;
|
||||
|
||||
if (lengthA > lengthB) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lengthA < lengthB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Paths that have the same segment length but
|
||||
// less placeholders are preferred
|
||||
const countSegments = (prev: number, segment: string) =>
|
||||
getSegmentName(segment) ? prev + 1 : 0;
|
||||
const segmentLengthA = fileA.split('/').reduce(countSegments, 0);
|
||||
const segmentLengthB = fileB.split('/').reduce(countSegments, 0);
|
||||
|
||||
if (segmentLengthA > segmentLengthB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (segmentLengthA < segmentLengthB) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface RoutesResult {
|
||||
defaultRoutes: Route[] | null;
|
||||
error: { [key: string]: string } | null;
|
||||
}
|
||||
|
||||
async function detectApiRoutes(
|
||||
files: string[],
|
||||
builders: Builder[]
|
||||
): Promise<RoutesResult> {
|
||||
if (!files || files.length === 0) {
|
||||
return { defaultRoutes: null, error: null };
|
||||
}
|
||||
|
||||
// The deepest routes need to be
|
||||
// the first ones to get handled
|
||||
const sortedFiles = files
|
||||
.filter(getIgnoreApiFilter(builders))
|
||||
.sort(sortFiles)
|
||||
.sort(sortFilesBySegmentCount);
|
||||
|
||||
const defaultRoutes: Route[] = [];
|
||||
|
||||
for (const file of sortedFiles) {
|
||||
// We only consider every file in the api directory
|
||||
// as we will strip extensions as well as resolving "[segments]"
|
||||
if (!file.startsWith('api/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const conflictingSegment = getConflictingSegment(file);
|
||||
|
||||
if (conflictingSegment) {
|
||||
return {
|
||||
defaultRoutes: null,
|
||||
error: {
|
||||
code: 'conflicting_path_segment',
|
||||
message:
|
||||
`The segment "${conflictingSegment}" occurs more than ` +
|
||||
`one time in your path "${file}". Please make sure that ` +
|
||||
`every segment in a path is unique`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const occurrences = pathOccurrences(file, sortedFiles).filter(
|
||||
name => name !== file
|
||||
);
|
||||
|
||||
if (occurrences.length > 0) {
|
||||
const messagePaths = concatArrayOfText(
|
||||
occurrences.map(name => `"${name}"`)
|
||||
);
|
||||
|
||||
return {
|
||||
defaultRoutes: null,
|
||||
error: {
|
||||
code: 'conflicting_file_path',
|
||||
message:
|
||||
`Two or more files have conflicting paths or names. ` +
|
||||
`Please make sure path segments and filenames, without their extension, are unique. ` +
|
||||
`The path "${file}" has conflicts with ${messagePaths}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
defaultRoutes.push(createRouteFromPath(file));
|
||||
}
|
||||
|
||||
// 404 Route to disable directory listing
|
||||
if (defaultRoutes.length) {
|
||||
defaultRoutes.push({
|
||||
status: 404,
|
||||
src: '/api(\\/.*)?$',
|
||||
});
|
||||
}
|
||||
|
||||
return { defaultRoutes, error: null };
|
||||
}
|
||||
|
||||
function hasPublicBuilder(builders: Builder[]): boolean {
|
||||
return builders.some(
|
||||
builder =>
|
||||
builder.use === '@now/static' &&
|
||||
builder.src === 'public/**/*' &&
|
||||
builder.config &&
|
||||
builder.config.zeroConfig === true
|
||||
);
|
||||
}
|
||||
|
||||
export async function detectRoutesLegacy(
|
||||
files: string[],
|
||||
builders: Builder[]
|
||||
): Promise<RoutesResult> {
|
||||
const routesResult = await detectApiRoutes(files, builders);
|
||||
|
||||
if (routesResult.defaultRoutes && hasPublicBuilder(builders)) {
|
||||
routesResult.defaultRoutes.push({
|
||||
src: '/(.*)',
|
||||
dest: '/public/$1',
|
||||
});
|
||||
}
|
||||
|
||||
return routesResult;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { parse as parsePath } from 'path';
|
||||
import { Route, Builder } from './types';
|
||||
import { Route } from '@now/routing-utils';
|
||||
import { Builder } from './types';
|
||||
import { getIgnoreApiFilter, sortFiles } from './detect-builders';
|
||||
|
||||
function escapeName(name: string) {
|
||||
@@ -199,7 +200,8 @@ interface RoutesResult {
|
||||
|
||||
async function detectApiRoutes(
|
||||
files: string[],
|
||||
builders: Builder[]
|
||||
builders: Builder[],
|
||||
featHandleMiss: boolean
|
||||
): Promise<RoutesResult> {
|
||||
if (!files || files.length === 0) {
|
||||
return { defaultRoutes: null, error: null };
|
||||
@@ -212,12 +214,15 @@ async function detectApiRoutes(
|
||||
.sort(sortFiles)
|
||||
.sort(sortFilesBySegmentCount);
|
||||
|
||||
const defaultRoutes: Route[] = [];
|
||||
let defaultRoutes: Route[] = [];
|
||||
|
||||
for (const file of sortedFiles) {
|
||||
// We only consider every file in the api directory
|
||||
// as we will strip extensions as well as resolving "[segments]"
|
||||
if (!file.startsWith('api/')) {
|
||||
if (
|
||||
!file.startsWith('api/') &&
|
||||
!builders.some(b => b.src === file && b.config!.functions)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -261,36 +266,63 @@ async function detectApiRoutes(
|
||||
}
|
||||
|
||||
// 404 Route to disable directory listing
|
||||
if (defaultRoutes.length) {
|
||||
defaultRoutes.push({
|
||||
status: 404,
|
||||
src: '/api(\\/.*)?$',
|
||||
});
|
||||
if (defaultRoutes.length > 0) {
|
||||
if (featHandleMiss) {
|
||||
defaultRoutes = [
|
||||
{ handle: 'miss' },
|
||||
{
|
||||
src: '/api/(.+)\\.\\w+',
|
||||
dest: '/api/$1',
|
||||
check: true,
|
||||
},
|
||||
{
|
||||
status: 404,
|
||||
src: '/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
defaultRoutes.push({
|
||||
status: 404,
|
||||
src: '/api(/.*)?$',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { defaultRoutes, error: null };
|
||||
}
|
||||
|
||||
function hasPublicBuilder(builders: Builder[]): boolean {
|
||||
return builders.some(
|
||||
function getPublicBuilder(builders: Builder[]): Builder | null {
|
||||
const builder = builders.find(
|
||||
builder =>
|
||||
builder.use === '@now/static' &&
|
||||
builder.src === 'public/**/*' &&
|
||||
/^.*\/\*\*\/\*$/.test(builder.src) &&
|
||||
builder.config &&
|
||||
builder.config.zeroConfig === true
|
||||
);
|
||||
|
||||
return builder || null;
|
||||
}
|
||||
|
||||
export function detectOutputDirectory(builders: Builder[]): string | null {
|
||||
// TODO: We eventually want to save the output directory to
|
||||
// builder.config.outputDirectory so it is only detected once
|
||||
const publicBuilder = getPublicBuilder(builders);
|
||||
return publicBuilder ? publicBuilder.src.replace('/**/*', '') : null;
|
||||
}
|
||||
|
||||
export async function detectRoutes(
|
||||
files: string[],
|
||||
builders: Builder[]
|
||||
builders: Builder[],
|
||||
featHandleMiss = false
|
||||
): Promise<RoutesResult> {
|
||||
const routesResult = await detectApiRoutes(files, builders);
|
||||
const routesResult = await detectApiRoutes(files, builders, featHandleMiss);
|
||||
const directory = detectOutputDirectory(builders);
|
||||
|
||||
if (routesResult.defaultRoutes && hasPublicBuilder(builders)) {
|
||||
if (routesResult.defaultRoutes && directory && !featHandleMiss) {
|
||||
routesResult.defaultRoutes.push({
|
||||
src: '/(.*)',
|
||||
dest: '/public/$1',
|
||||
dest: `/${directory}/$1`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
27
packages/now-build-utils/src/detectors/angular.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectAngular({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('@angular/cli');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'ng build',
|
||||
outputDirectory: 'dist',
|
||||
devCommand: 'ng serve --port $PORT',
|
||||
framework: {
|
||||
slug: '@angular/cli',
|
||||
version,
|
||||
},
|
||||
minNodeRange: '10.x',
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
22
packages/now-build-utils/src/detectors/brunch.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectBrunch({
|
||||
fs: { exists, getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('brunch');
|
||||
if (!version) return false;
|
||||
|
||||
const hasConfig = await exists('brunch-config.js');
|
||||
if (!hasConfig) return false;
|
||||
|
||||
return {
|
||||
buildCommand:
|
||||
(await getPackageJsonBuildCommand()) || 'brunch build --production',
|
||||
outputDirectory: 'public',
|
||||
devCommand: 'brunch watch --server --port $PORT',
|
||||
framework: {
|
||||
slug: 'brunch',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectCreateReactAppEjected({
|
||||
fs: { getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('react-dev-utils');
|
||||
if (!version) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: 'node scripts/build.js',
|
||||
outputDirectory: 'build',
|
||||
devCommand: 'node scripts/start.js',
|
||||
framework: {
|
||||
slug: 'react-dev-utils',
|
||||
version,
|
||||
},
|
||||
devVariables: { BROWSER: 'none' },
|
||||
routes: [
|
||||
{
|
||||
src: '/static/(.*)',
|
||||
headers: { 'cache-control': 's-maxage=31536000, immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '/service-worker.js',
|
||||
headers: { 'cache-control': 's-maxage=0' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '/sockjs-node/(.*)',
|
||||
dest: '/sockjs-node/$1',
|
||||
},
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
headers: { 'cache-control': 's-maxage=0' },
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
44
packages/now-build-utils/src/detectors/create-react-app.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectCreateReactApp({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('react-scripts');
|
||||
if (!version) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'react-scripts build',
|
||||
outputDirectory: 'build',
|
||||
devCommand: 'react-scripts start',
|
||||
devVariables: { BROWSER: 'none' },
|
||||
framework: {
|
||||
slug: 'react-scripts',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
src: '/static/(.*)',
|
||||
headers: { 'cache-control': 's-maxage=31536000, immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '/service-worker.js',
|
||||
headers: { 'cache-control': 's-maxage=0' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '/sockjs-node/(.*)',
|
||||
dest: '/sockjs-node/$1',
|
||||
},
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
headers: { 'cache-control': 's-maxage=0' },
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
17
packages/now-build-utils/src/detectors/docusaurus.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectDocusaurus({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('docusaurus');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'docusaurus-build',
|
||||
outputDirectory: 'build',
|
||||
devCommand: 'docusaurus-start --port $PORT',
|
||||
framework: {
|
||||
slug: 'docusaurus',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
17
packages/now-build-utils/src/detectors/eleventy.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectEleventy({
|
||||
fs: { getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('@11ty/eleventy');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: 'npx @11ty/eleventy',
|
||||
outputDirectory: '_site',
|
||||
devCommand: 'npx @11ty/eleventy --serve --watch --port $PORT',
|
||||
framework: {
|
||||
slug: '@11ty/eleventy',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
26
packages/now-build-utils/src/detectors/ember.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectEmber({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('ember-cli');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'ember build',
|
||||
outputDirectory: 'dist',
|
||||
devCommand: 'ember serve --port $PORT',
|
||||
framework: {
|
||||
slug: 'ember-cli',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
141
packages/now-build-utils/src/detectors/filesystem.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import yaml from 'js-yaml';
|
||||
import toml from '@iarna/toml';
|
||||
import { PackageJson } from '../types';
|
||||
|
||||
/**
|
||||
* `DetectorFilesystem` is an abstract class that represents a virtual filesystem
|
||||
* to perform read-only operations on in order to detect which framework is being
|
||||
* used.
|
||||
*
|
||||
* Its abstract methods must be implemented by a subclass that perform the actual
|
||||
* FS operations. Example subclasses could be implemented as:
|
||||
*
|
||||
* - Local filesystem, which proxies the FS operations to the equivalent `fs`
|
||||
* module functions.
|
||||
* - HTTP filesystem, which implements the FS operations over an HTTP server
|
||||
* and does not require a local copy of the files.
|
||||
* - `Files` filesystem, which operates on a virtual `Files` object (i.e. from
|
||||
* the `glob()` function) which could include `FileFsRef`, `FileBlob`, etc.
|
||||
*
|
||||
* This base class implements various helper functions for common tasks (i.e.
|
||||
* read and parse a JSON file). It also includes caching for all FS operations
|
||||
* so that multiple detector functions de-dup read operations on the same file
|
||||
* to reduce network/filesystem overhead.
|
||||
*
|
||||
* **NOTE:** It's important that all instance methods in this base class are
|
||||
* bound to `this` so that the `fs` object may be destructured in the detector
|
||||
* functions. The easiest way to do this is to use the `=` syntax when defining
|
||||
* methods in this class definition.
|
||||
*/
|
||||
export default abstract class DetectorFilesystem {
|
||||
protected abstract _readFile(name: string): Promise<Buffer>;
|
||||
protected abstract _exists(name: string): Promise<boolean>;
|
||||
|
||||
private existsCache: Map<string, Promise<boolean>>;
|
||||
private readFileCache: Map<string, Promise<Buffer>>;
|
||||
private readJsonCache: Map<string, Promise<any>>;
|
||||
|
||||
constructor() {
|
||||
this.existsCache = new Map();
|
||||
this.readFileCache = new Map();
|
||||
this.readJsonCache = new Map();
|
||||
}
|
||||
|
||||
public exists = async (name: string): Promise<boolean> => {
|
||||
let p = this.existsCache.get(name);
|
||||
if (!p) {
|
||||
p = this._exists(name);
|
||||
this.existsCache.set(name, p);
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
public readFile = async (name: string): Promise<Buffer> => {
|
||||
let p = this.readFileCache.get(name);
|
||||
if (!p) {
|
||||
p = this._readFile(name);
|
||||
this.readFileCache.set(name, p);
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
public readJson = async <T>(name: string): Promise<T> => {
|
||||
let p = this.readJsonCache.get(name);
|
||||
if (!p) {
|
||||
p = this.readFile(name).then(d => JSON.parse(d.toString('utf8')));
|
||||
this.readJsonCache.set(name, p);
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
public readFileOrNull = async (name: string): Promise<Buffer | null> => {
|
||||
return nullEnoent(this.readFile(name));
|
||||
};
|
||||
|
||||
public readJsonOrNull = async <T>(name: string): Promise<T | null> => {
|
||||
return nullEnoent(this.readJson<T>(name));
|
||||
};
|
||||
|
||||
public readPackageJson = async (): Promise<PackageJson | null> => {
|
||||
return await this.readJsonOrNull<PackageJson>('package.json');
|
||||
};
|
||||
|
||||
public readConfigFile = async <T>(...names: string[]): Promise<T | null> => {
|
||||
for (const name of names) {
|
||||
const data = await this.readFileOrNull(name);
|
||||
if (data) {
|
||||
const str = data.toString('utf8');
|
||||
if (name.endsWith('.json')) {
|
||||
return JSON.parse(str);
|
||||
} else if (name.endsWith('.toml')) {
|
||||
return (toml.parse(str) as unknown) as T;
|
||||
} else if (name.endsWith('.yaml') || name.endsWith('.yml')) {
|
||||
return yaml.safeLoad(str, { filename: name });
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
public hasDependency = async (name: string): Promise<boolean> => {
|
||||
const pkg = await this.readPackageJson();
|
||||
const { dependencies = {}, devDependencies = {} } = pkg || {};
|
||||
return name in dependencies || name in devDependencies;
|
||||
};
|
||||
|
||||
public isNpm = async (): Promise<boolean> => {
|
||||
return this.exists('package-lock.json');
|
||||
};
|
||||
|
||||
public getPackageJsonCommand = async (
|
||||
name: string
|
||||
): Promise<string | null> => {
|
||||
const pkg = await this.readPackageJson();
|
||||
const { scripts = {} } = pkg || {};
|
||||
return scripts[name] || null;
|
||||
};
|
||||
|
||||
public getPackageJsonBuildCommand = async (): Promise<string | null> => {
|
||||
const buildCommand = (await this.isNpm())
|
||||
? 'npm run build'
|
||||
: 'yarn run build';
|
||||
return (await this.getPackageJsonCommand('build')) ? buildCommand : null;
|
||||
};
|
||||
|
||||
public getDependencyVersion = async (name: string): Promise<string> => {
|
||||
const pkg = await this.readPackageJson();
|
||||
const { dependencies = {}, devDependencies = {} } = pkg || {};
|
||||
return dependencies[name] || devDependencies[name];
|
||||
};
|
||||
}
|
||||
|
||||
async function nullEnoent<T>(p: Promise<T>): Promise<T | null> {
|
||||
try {
|
||||
return await p;
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
20
packages/now-build-utils/src/detectors/gatsby.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectGatsby({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('gatsby');
|
||||
if (!version) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'gatsby build',
|
||||
outputDirectory: 'public',
|
||||
devCommand: 'gatsby develop -p $PORT',
|
||||
framework: {
|
||||
slug: 'gatsby',
|
||||
version,
|
||||
},
|
||||
cachePattern: '.cache/**',
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectGenericNodeProject({
|
||||
fs: { isNpm, getPackageJsonCommand },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const useNpm = await isNpm();
|
||||
const devCommand = await getPackageJsonCommand('dev');
|
||||
const buildCommand = await getPackageJsonCommand('build');
|
||||
|
||||
if (!buildCommand) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
buildCommand: `${useNpm ? 'npm' : 'yarn'} run build`,
|
||||
devCommand: useNpm && devCommand ? `yarn run ${devCommand}` : undefined,
|
||||
outputDirectory: 'public',
|
||||
};
|
||||
}
|
||||
19
packages/now-build-utils/src/detectors/gridsome.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectGridsome({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('gridsome');
|
||||
if (!version) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'gridsome build',
|
||||
outputDirectory: 'dist',
|
||||
devCommand: 'gridsome develop -p $PORT',
|
||||
framework: {
|
||||
slug: 'gridsom',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
17
packages/now-build-utils/src/detectors/hexo.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectHexo({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('hexo');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'hexo generate',
|
||||
outputDirectory: 'public',
|
||||
devCommand: 'hexo server --port $PORT',
|
||||
framework: {
|
||||
slug: 'hexo',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
30
packages/now-build-utils/src/detectors/hugo.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
/**
|
||||
* https://gohugo.io/getting-started/configuration/#configuration-file
|
||||
*/
|
||||
interface HugoConfig {
|
||||
publishDir?: string;
|
||||
}
|
||||
|
||||
export default async function detectHugo({
|
||||
fs: { readConfigFile },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const config = await readConfigFile<HugoConfig>(
|
||||
'config.toml',
|
||||
'config.yaml',
|
||||
'config.json'
|
||||
);
|
||||
if (!config) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: 'hugo',
|
||||
outputDirectory: config.publishDir || 'public',
|
||||
devCommand: 'hugo server -D -w -p $PORT',
|
||||
framework: {
|
||||
slug: 'hugo',
|
||||
version: 'latest',
|
||||
},
|
||||
};
|
||||
}
|
||||
89
packages/now-build-utils/src/detectors/index.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import AggregateError from 'aggregate-error';
|
||||
import { Detector, DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
import angular from './angular';
|
||||
import brunch from './brunch';
|
||||
import createReactApp from './create-react-app';
|
||||
import createReactAppEjected from './create-react-app-ejected';
|
||||
import docusaurus from './docusaurus';
|
||||
import eleventy from './eleventy';
|
||||
import ember from './ember';
|
||||
import gatsby from './gatsby';
|
||||
import genericNodeProject from './generic-node-project';
|
||||
import gridsome from './gridsome';
|
||||
import hexo from './hexo';
|
||||
import hugo from './hugo';
|
||||
import jekyll from './jekyll';
|
||||
import middleman from './middleman';
|
||||
import next from './next';
|
||||
import polymer from './polymer';
|
||||
import preact from './preact';
|
||||
import saber from './saber';
|
||||
import sapper from './sapper';
|
||||
import stencil from './stencil';
|
||||
import svelte from './svelte';
|
||||
import umi from './umi';
|
||||
import vue from './vue';
|
||||
|
||||
export const pkgDetectors: Detector[] = [
|
||||
angular,
|
||||
brunch,
|
||||
createReactApp,
|
||||
createReactAppEjected,
|
||||
docusaurus,
|
||||
eleventy,
|
||||
ember,
|
||||
gatsby,
|
||||
gridsome,
|
||||
hexo,
|
||||
next,
|
||||
polymer,
|
||||
preact,
|
||||
saber,
|
||||
sapper,
|
||||
stencil,
|
||||
svelte,
|
||||
umi,
|
||||
vue,
|
||||
];
|
||||
|
||||
export const detectors: Detector[] = [hugo, jekyll, middleman];
|
||||
|
||||
export function firstTruthy<T>(promises: Promise<T>[]) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
const errors: Array<Error> = [];
|
||||
let unresolved = promises.length;
|
||||
for (const p of promises) {
|
||||
p.then(v => {
|
||||
if (v || --unresolved === 0) {
|
||||
resolve(v);
|
||||
}
|
||||
}).catch(err => {
|
||||
errors.push(err);
|
||||
if (--unresolved === 0) {
|
||||
reject(new AggregateError(errors));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function detectDefaults(
|
||||
params: DetectorParameters
|
||||
): Promise<DetectorResult> {
|
||||
// The `package.json` detectors are run first, since they share the common
|
||||
// file read of `package.json` and are the most popular frameworks
|
||||
let d: Detector[] = params.pkgDetectors || pkgDetectors;
|
||||
let result: DetectorResult = await firstTruthy(
|
||||
d.map(detector => detector(params))
|
||||
);
|
||||
if (!result) {
|
||||
// If no `package.json` framework was detected then check the non-pkg ones
|
||||
d = params.detectors || detectors;
|
||||
result = await firstTruthy(d.map(detector => detector(params)));
|
||||
}
|
||||
if (!result) {
|
||||
result = await genericNodeProject(params);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
26
packages/now-build-utils/src/detectors/jekyll.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
/**
|
||||
* https://jekyllrb.com/docs/configuration/options/
|
||||
*/
|
||||
interface JekyllConfig {
|
||||
destination?: string;
|
||||
}
|
||||
|
||||
export default async function detectJekyll({
|
||||
fs: { readConfigFile },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const config = await readConfigFile<JekyllConfig>('_config.yml');
|
||||
if (!config) {
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: 'jekyll build',
|
||||
outputDirectory: config.destination || '_site',
|
||||
devCommand: 'bundle exec jekyll serve --watch --port $PORT',
|
||||
framework: {
|
||||
slug: 'jekyll',
|
||||
version: 'latest',
|
||||
},
|
||||
};
|
||||
}
|
||||
18
packages/now-build-utils/src/detectors/middleman.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectMiddleman({
|
||||
fs: { exists },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const hasConfig = await exists('config.rb');
|
||||
if (!hasConfig) return false;
|
||||
|
||||
return {
|
||||
buildCommand: 'bundle exec middleman build',
|
||||
outputDirectory: 'build',
|
||||
devCommand: 'bundle exec middleman server -p $PORT',
|
||||
framework: {
|
||||
slug: 'middleman',
|
||||
version: 'latest',
|
||||
},
|
||||
};
|
||||
}
|
||||
17
packages/now-build-utils/src/detectors/next.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectNext({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('next');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'next build',
|
||||
outputDirectory: '.next/static',
|
||||
devCommand: 'next -p $PORT',
|
||||
framework: {
|
||||
slug: 'next',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
26
packages/now-build-utils/src/detectors/polymer.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectPolymer({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('polymer-cli');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'polymer build',
|
||||
outputDirectory: 'build',
|
||||
devCommand: 'polymer serve --port $PORT',
|
||||
framework: {
|
||||
slug: 'polymer-cli',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
26
packages/now-build-utils/src/detectors/preact.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectPreact({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('preact-cli');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'preact build',
|
||||
outputDirectory: 'build',
|
||||
devCommand: 'preact watch --port $PORT',
|
||||
framework: {
|
||||
slug: 'preact-cli',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
31
packages/now-build-utils/src/detectors/saber.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectSaber({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('saber');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'saber build',
|
||||
outputDirectory: 'public',
|
||||
devCommand: 'saber --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
src: '/_saber/.*',
|
||||
headers: { 'cache-control': 'max-age=31536000, immutable' },
|
||||
},
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '.*',
|
||||
status: 404,
|
||||
dest: '404.html',
|
||||
},
|
||||
],
|
||||
framework: {
|
||||
slug: 'saber',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
17
packages/now-build-utils/src/detectors/sapper.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectSapper({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('sapper');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'sapper export',
|
||||
outputDirectory: '__sapper__/export',
|
||||
devCommand: 'sapper dev --port $PORT',
|
||||
framework: {
|
||||
slug: 'sapper',
|
||||
version,
|
||||
},
|
||||
};
|
||||
}
|
||||
26
packages/now-build-utils/src/detectors/stencil.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectStencil({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('@stencil/core');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'stencil build',
|
||||
outputDirectory: 'www',
|
||||
devCommand: 'stencil build --dev --watch --serve --port $PORT',
|
||||
framework: {
|
||||
slug: '@stencil/core',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
26
packages/now-build-utils/src/detectors/svelte.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectSvelte({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('sirv-cli');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'rollup -c',
|
||||
outputDirectory: 'public',
|
||||
devCommand: 'sirv public --single --dev --port $PORT',
|
||||
framework: {
|
||||
slug: 'sirv-cli',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
26
packages/now-build-utils/src/detectors/umi.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectUmiJS({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('umi');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand: (await getPackageJsonBuildCommand()) || 'umi build',
|
||||
outputDirectory: 'dist',
|
||||
devCommand: 'umi dev --port $PORT',
|
||||
framework: {
|
||||
slug: 'umi',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
37
packages/now-build-utils/src/detectors/vue.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { DetectorParameters, DetectorResult } from '../types';
|
||||
|
||||
export default async function detectVue({
|
||||
fs: { getPackageJsonBuildCommand, getDependencyVersion },
|
||||
}: DetectorParameters): Promise<DetectorResult> {
|
||||
const version = await getDependencyVersion('@vue/cli-service');
|
||||
if (!version) return false;
|
||||
return {
|
||||
buildCommand:
|
||||
(await getPackageJsonBuildCommand()) || 'vue-cli-service build',
|
||||
outputDirectory: 'dist',
|
||||
devCommand: 'vue-cli-service serve --port $PORT',
|
||||
framework: {
|
||||
slug: '@vue/cli-service',
|
||||
version,
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
src: '^/[^/]*\\.(js|txt|ico|json)',
|
||||
headers: { 'cache-control': 'max-age=300' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '^/(img|js|css|fonts|media)/.*',
|
||||
headers: { 'cache-control': 'max-age=31536000, immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '^.*',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import path from 'path';
|
||||
import debug from '../debug';
|
||||
import FileFsRef from '../file-fs-ref';
|
||||
import { File, Files, Meta } from '../types';
|
||||
import { remove, mkdirp, readlink, symlink } from 'fs-extra';
|
||||
@@ -39,8 +40,12 @@ export default async function download(
|
||||
basePath: string,
|
||||
meta?: Meta
|
||||
): Promise<DownloadedFiles> {
|
||||
const { isDev = false, skipDownload = false, filesChanged = null, filesRemoved = null } =
|
||||
meta || {};
|
||||
const {
|
||||
isDev = false,
|
||||
skipDownload = false,
|
||||
filesChanged = null,
|
||||
filesRemoved = null,
|
||||
} = meta || {};
|
||||
|
||||
if (isDev || skipDownload) {
|
||||
// In `now dev`, the `download()` function is a no-op because
|
||||
@@ -48,11 +53,14 @@ export default async function download(
|
||||
// source files are already available.
|
||||
return files as DownloadedFiles;
|
||||
}
|
||||
debug('Downloading deployment source files...');
|
||||
|
||||
const start = Date.now();
|
||||
const files2: DownloadedFiles = {};
|
||||
const filenames = Object.keys(files);
|
||||
|
||||
await Promise.all(
|
||||
Object.keys(files).map(async name => {
|
||||
filenames.map(async name => {
|
||||
// If the file does not exist anymore, remove it.
|
||||
if (Array.isArray(filesRemoved) && filesRemoved.includes(name)) {
|
||||
await removeFile(basePath, name);
|
||||
@@ -71,5 +79,8 @@ export default async function download(
|
||||
})
|
||||
);
|
||||
|
||||
const duration = Date.now() - start;
|
||||
debug(`Downloaded ${filenames.length} source files: ${duration}ms`);
|
||||
|
||||
return files2;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
import { intersects } from 'semver';
|
||||
import boxen from 'boxen';
|
||||
import { NodeVersion } from '../types';
|
||||
import debug from '../debug';
|
||||
|
||||
const supportedOptions: NodeVersion[] = [
|
||||
const allOptions: NodeVersion[] = [
|
||||
{ major: 12, range: '12.x', runtime: 'nodejs12.x' },
|
||||
{ major: 10, range: '10.x', runtime: 'nodejs10.x' },
|
||||
{ major: 8, range: '8.10.x', runtime: 'nodejs8.10' },
|
||||
{
|
||||
major: 8,
|
||||
range: '8.10.x',
|
||||
runtime: 'nodejs8.10',
|
||||
discontinueDate: new Date('2020-01-06'),
|
||||
},
|
||||
];
|
||||
|
||||
const supportedOptions = allOptions.filter(o => !isDiscontinued(o));
|
||||
|
||||
// This version should match Fargate's default in the PATH
|
||||
// Today that is Node 8
|
||||
export const defaultSelection = supportedOptions.find(
|
||||
@@ -22,18 +31,19 @@ export async function getSupportedNodeVersion(
|
||||
if (!engineRange) {
|
||||
if (!silent) {
|
||||
debug(
|
||||
'missing `engines` in `package.json`, using default range: ' +
|
||||
'Missing `engines` in `package.json`, using default range: ' +
|
||||
selection.range
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const found = supportedOptions.some(o => {
|
||||
const found = allOptions.some(o => {
|
||||
// the array is already in order so return the first
|
||||
// match which will be the newest version of node
|
||||
selection = o;
|
||||
return intersects(o.range, engineRange);
|
||||
});
|
||||
if (found) {
|
||||
const discontinued = isDiscontinued(selection);
|
||||
if (found && !discontinued) {
|
||||
if (!silent) {
|
||||
debug(
|
||||
'Found `engines` in `package.json`, selecting range: ' +
|
||||
@@ -41,14 +51,50 @@ export async function getSupportedNodeVersion(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!silent) {
|
||||
throw new Error(
|
||||
'found `engines` in `package.json` with an unsupported node range: ' +
|
||||
engineRange +
|
||||
'\nplease use `10.x` or `8.10.x` instead'
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
'Found `engines` in `package.json` with an unsupported Node.js version range: ' +
|
||||
engineRange +
|
||||
'\nPlease use one of the following supported ranges: ' +
|
||||
JSON.stringify(supportedOptions.map(o => o.range)) +
|
||||
(discontinued
|
||||
? '\nThis change is the result of a decision made by an upstream infrastructure provider (AWS).' +
|
||||
'\nRead more: https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html'
|
||||
: '')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { range, discontinueDate } = selection;
|
||||
if (discontinueDate && !isDiscontinued(selection)) {
|
||||
const d = discontinueDate.toISOString().split('T')[0];
|
||||
const validRanges = supportedOptions
|
||||
.filter(o => !o.discontinueDate)
|
||||
.map(o => o.range);
|
||||
const prevTerm = process.env.TERM;
|
||||
if (!prevTerm) {
|
||||
// workaround for https://github.com/sindresorhus/term-size/issues/13
|
||||
process.env.TERM = 'xterm';
|
||||
}
|
||||
console.warn(
|
||||
boxen(
|
||||
'NOTICE' +
|
||||
'\n' +
|
||||
`\nNode.js version ${range} has reached end-of-life.` +
|
||||
`\nAs a result, deployments created on or after ${d} will fail to build.` +
|
||||
'\nPlease use one of the following supported `engines` in `package.json`: ' +
|
||||
JSON.stringify(validRanges) +
|
||||
'\nThis change is the result of a decision made by an upstream infrastructure provider (AWS).' +
|
||||
'\nRead more: https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html',
|
||||
{ padding: 1 }
|
||||
)
|
||||
);
|
||||
process.env.TERM = prevTerm;
|
||||
}
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
function isDiscontinued({ discontinueDate }: NodeVersion): boolean {
|
||||
const today = new Date();
|
||||
return discontinueDate !== undefined && discontinueDate <= today;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,66 @@ export function spawnAsync(
|
||||
});
|
||||
}
|
||||
|
||||
export function execAsync(
|
||||
command: string,
|
||||
args: string[],
|
||||
opts: SpawnOptions = {}
|
||||
) {
|
||||
return new Promise<{ stdout: string; stderr: string; code: number }>(
|
||||
(resolve, reject) => {
|
||||
opts.stdio = 'pipe';
|
||||
|
||||
const stdoutList: Buffer[] = [];
|
||||
const stderrList: Buffer[] = [];
|
||||
|
||||
const child = spawn(command, args, opts);
|
||||
|
||||
child.stderr!.on('data', data => {
|
||||
stderrList.push(data);
|
||||
});
|
||||
|
||||
child.stdout!.on('data', data => {
|
||||
stdoutList.push(data);
|
||||
});
|
||||
|
||||
child.on('error', reject);
|
||||
child.on('close', (code, signal) => {
|
||||
if (code !== 0) {
|
||||
return reject(
|
||||
new Error(
|
||||
`Program "${command}" exited with non-zero exit code ${code} ${signal}.`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return resolve({
|
||||
code,
|
||||
stdout: Buffer.concat(stdoutList).toString(),
|
||||
stderr: Buffer.concat(stderrList).toString(),
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function spawnCommand(command: string, options: SpawnOptions = {}) {
|
||||
if (process.platform === 'win32') {
|
||||
return spawn('cmd.exe', ['/C', command], options);
|
||||
}
|
||||
|
||||
return spawn('sh', ['-c', command], options);
|
||||
}
|
||||
|
||||
export async function execCommand(command: string, options: SpawnOptions = {}) {
|
||||
if (process.platform === 'win32') {
|
||||
await spawnAsync('cmd.exe', ['/C', command], options);
|
||||
} else {
|
||||
await spawnAsync('sh', ['-c', command], options);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function chmodPlusX(fsPath: string) {
|
||||
const s = await fs.stat(fsPath);
|
||||
const newMode = s.mode | 64 | 8 | 1; // eslint-disable-line no-bitwise
|
||||
@@ -155,7 +215,7 @@ export async function runNpmInstall(
|
||||
commandArgs = args.filter(a => a !== '--prefer-offline');
|
||||
await spawnAsync(
|
||||
'npm',
|
||||
commandArgs.concat(['install', '--unsafe-perm']),
|
||||
commandArgs.concat(['install', '--no-audit', '--unsafe-perm']),
|
||||
opts
|
||||
);
|
||||
} else {
|
||||
@@ -247,7 +307,11 @@ export async function runPackageJsonScript(
|
||||
await spawnAsync('npm', ['run', scriptName], opts);
|
||||
} else {
|
||||
console.log(`Running "yarn run ${scriptName}"`);
|
||||
await spawnAsync('yarn', ['--cwd', destPath, 'run', scriptName], opts);
|
||||
await spawnAsync(
|
||||
'yarn',
|
||||
['--ignore-engines', '--cwd', destPath, 'run', scriptName],
|
||||
opts
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -3,12 +3,15 @@ import FileFsRef from './file-fs-ref';
|
||||
import FileRef from './file-ref';
|
||||
import { Lambda, createLambda, getLambdaOptionsFromFunction } from './lambda';
|
||||
import { Prerender } from './prerender';
|
||||
import download, { DownloadedFiles } from './fs/download';
|
||||
import download, { DownloadedFiles, isSymbolicLink } from './fs/download';
|
||||
import getWriteableDirectory from './fs/get-writable-directory';
|
||||
import glob from './fs/glob';
|
||||
import rename from './fs/rename';
|
||||
import {
|
||||
execAsync,
|
||||
spawnAsync,
|
||||
execCommand,
|
||||
spawnCommand,
|
||||
installDependencies,
|
||||
runPackageJsonScript,
|
||||
runNpmInstall,
|
||||
@@ -21,7 +24,8 @@ import {
|
||||
import streamToBuffer from './fs/stream-to-buffer';
|
||||
import shouldServe from './should-serve';
|
||||
import { detectBuilders } from './detect-builders';
|
||||
import { detectRoutes } from './detect-routes';
|
||||
import { detectRoutes, detectOutputDirectory } from './detect-routes';
|
||||
import DetectorFilesystem from './detectors/filesystem';
|
||||
import debug from './debug';
|
||||
|
||||
export {
|
||||
@@ -29,6 +33,7 @@ export {
|
||||
FileFsRef,
|
||||
FileRef,
|
||||
Lambda,
|
||||
DetectorFilesystem,
|
||||
createLambda,
|
||||
Prerender,
|
||||
download,
|
||||
@@ -36,9 +41,12 @@ export {
|
||||
getWriteableDirectory,
|
||||
glob,
|
||||
rename,
|
||||
execAsync,
|
||||
spawnAsync,
|
||||
installDependencies,
|
||||
runPackageJsonScript,
|
||||
execCommand,
|
||||
spawnCommand,
|
||||
runNpmInstall,
|
||||
runBundleInstall,
|
||||
runPipInstall,
|
||||
@@ -49,8 +57,15 @@ export {
|
||||
shouldServe,
|
||||
detectBuilders,
|
||||
detectRoutes,
|
||||
detectOutputDirectory,
|
||||
debug,
|
||||
isSymbolicLink,
|
||||
getLambdaOptionsFromFunction,
|
||||
};
|
||||
|
||||
export { detectBuildersLegacy } from './detect-builders-legacy';
|
||||
export { detectRoutesLegacy } from './detect-routes-legacy';
|
||||
|
||||
export { detectDefaults } from './detectors';
|
||||
export * from './schemas';
|
||||
export * from './types';
|
||||
|
||||
61
packages/now-build-utils/src/schemas.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export const functionsSchema = {
|
||||
type: 'object',
|
||||
minProperties: 1,
|
||||
maxProperties: 50,
|
||||
additionalProperties: false,
|
||||
patternProperties: {
|
||||
'^.{1,256}$': {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
runtime: {
|
||||
type: 'string',
|
||||
maxLength: 256,
|
||||
},
|
||||
memory: {
|
||||
// Number between 128 and 3008 in steps of 64
|
||||
enum: Object.keys(Array.from({ length: 50 }))
|
||||
.slice(2, 48)
|
||||
.map(x => Number(x) * 64),
|
||||
},
|
||||
maxDuration: {
|
||||
type: 'number',
|
||||
minimum: 1,
|
||||
maximum: 900,
|
||||
},
|
||||
includeFiles: {
|
||||
type: 'string',
|
||||
maxLength: 256,
|
||||
},
|
||||
excludeFiles: {
|
||||
type: 'string',
|
||||
maxLength: 256,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const buildsSchema = {
|
||||
type: 'array',
|
||||
minItems: 0,
|
||||
maxItems: 128,
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['use'],
|
||||
properties: {
|
||||
src: {
|
||||
type: 'string',
|
||||
minLength: 1,
|
||||
maxLength: 4096,
|
||||
},
|
||||
use: {
|
||||
type: 'string',
|
||||
minLength: 3,
|
||||
maxLength: 256,
|
||||
},
|
||||
config: { type: 'object' },
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
import FileRef from './file-ref';
|
||||
import FileFsRef from './file-fs-ref';
|
||||
import DetectorFilesystem from './detectors/filesystem';
|
||||
import { Route } from '@now/routing-utils';
|
||||
|
||||
export interface Env {
|
||||
[name: string]: string | undefined;
|
||||
@@ -20,18 +22,6 @@ export interface Files {
|
||||
[filePath: string]: File;
|
||||
}
|
||||
|
||||
export interface Route {
|
||||
src?: string;
|
||||
dest?: string;
|
||||
handle?: string;
|
||||
type?: string;
|
||||
headers?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
continue?: boolean;
|
||||
status?: number;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
[key: string]:
|
||||
| string
|
||||
@@ -51,6 +41,13 @@ export interface Config {
|
||||
zeroConfig?: boolean;
|
||||
import?: { [key: string]: string };
|
||||
functions?: BuilderFunctions;
|
||||
outputDirectory?: string;
|
||||
buildCommand?: string;
|
||||
devCommand?: string;
|
||||
framework?: {
|
||||
slug: string;
|
||||
version: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Meta {
|
||||
@@ -303,6 +300,7 @@ export interface NodeVersion {
|
||||
major: number;
|
||||
range: string;
|
||||
runtime: string;
|
||||
discontinueDate?: Date;
|
||||
}
|
||||
|
||||
export interface Builder {
|
||||
@@ -320,3 +318,54 @@ export interface BuilderFunctions {
|
||||
excludeFiles?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface NowRewrite {
|
||||
source: string;
|
||||
destination: string;
|
||||
}
|
||||
|
||||
export interface NowRedirect {
|
||||
source: string;
|
||||
destination: string;
|
||||
statusCode?: number;
|
||||
}
|
||||
|
||||
export interface NowHeader {
|
||||
source: string;
|
||||
headers: NowHeaderKeyValue[];
|
||||
}
|
||||
|
||||
export interface NowHeaderKeyValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type Detector = (params: DetectorParameters) => Promise<DetectorResult>;
|
||||
|
||||
export interface DetectorParameters {
|
||||
fs: DetectorFilesystem;
|
||||
detectors?: Detector[];
|
||||
pkgDetectors?: Detector[];
|
||||
}
|
||||
|
||||
export interface DetectorOutput {
|
||||
buildCommand: string;
|
||||
outputDirectory: string;
|
||||
buildVariables?: Env;
|
||||
devCommand?: string;
|
||||
devVariables?: Env;
|
||||
minNodeRange?: string;
|
||||
cachePattern?: string;
|
||||
routes?: Route[];
|
||||
cleanUrls?: boolean;
|
||||
rewrites?: NowRewrite[];
|
||||
redirects?: NowRedirect[];
|
||||
headers?: NowHeader[];
|
||||
trailingSlash?: boolean;
|
||||
framework?: {
|
||||
slug: string;
|
||||
version: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type DetectorResult = DetectorOutput | false;
|
||||
|
||||
13
packages/now-build-utils/test/fixtures/03-zero-config-angular/.editorconfig
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
46
packages/now-build-utils/test/fixtures/03-zero-config-angular/.gitignore
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
speed-measure-plugin*.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
27
packages/now-build-utils/test/fixtures/03-zero-config-angular/README.md
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Angular
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.17.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
114
packages/now-build-utils/test/fixtures/03-zero-config-angular/angular.json
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"angular": {
|
||||
"projectType": "application",
|
||||
"schematics": {},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/angular",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": false,
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.css"],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb",
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "angular:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "angular:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "angular:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.css"],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"e2e/tsconfig.json"
|
||||
],
|
||||
"exclude": ["**/node_modules/**"]
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "angular:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "angular:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "angular"
|
||||
}
|
||||
12
packages/now-build-utils/test/fixtures/03-zero-config-angular/browserslist
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
32
packages/now-build-utils/test/fixtures/03-zero-config-angular/e2e/protractor.conf.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: ['./src/**/*.e2e-spec.ts'],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {},
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json'),
|
||||
});
|
||||
jasmine
|
||||
.getEnv()
|
||||
.addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
},
|
||||
};
|
||||
28
packages/now-build-utils/test/fixtures/03-zero-config-angular/e2e/src/app.e2e-spec.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('angular app is running!');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser
|
||||
.manage()
|
||||
.logs()
|
||||
.get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(
|
||||
jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry)
|
||||
);
|
||||
});
|
||||
});
|
||||
13
packages/now-build-utils/test/fixtures/03-zero-config-angular/e2e/src/app.po.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get(browser.baseUrl) as Promise<any>;
|
||||
}
|
||||
|
||||
getTitleText() {
|
||||
return element(by.css('app-root .content span')).getText() as Promise<
|
||||
string
|
||||
>;
|
||||
}
|
||||
}
|
||||
9
packages/now-build-utils/test/fixtures/03-zero-config-angular/e2e/tsconfig.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": ["jasmine", "jasminewd2", "node"]
|
||||
}
|
||||
}
|
||||
32
packages/now-build-utils/test/fixtures/03-zero-config-angular/karma.conf.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/angular'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
47
packages/now-build-utils/test/fixtures/03-zero-config-angular/package.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "angular",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~8.2.13",
|
||||
"@angular/common": "~8.2.13",
|
||||
"@angular/compiler": "~8.2.13",
|
||||
"@angular/core": "~8.2.13",
|
||||
"@angular/forms": "~8.2.13",
|
||||
"@angular/platform-browser": "~8.2.13",
|
||||
"@angular/platform-browser-dynamic": "~8.2.13",
|
||||
"@angular/router": "~8.2.13",
|
||||
"rxjs": "~6.4.0",
|
||||
"tslib": "^1.10.0",
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.803.17",
|
||||
"@angular/cli": "~8.3.17",
|
||||
"@angular/compiler-cli": "~8.2.13",
|
||||
"@angular/language-service": "~8.2.13",
|
||||
"@types/node": "~8.9.4",
|
||||
"@types/jasmine": "~3.3.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"codelyzer": "^5.0.0",
|
||||
"jasmine-core": "~3.4.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~4.1.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||
"karma-jasmine": "~2.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.4.0",
|
||||
"protractor": "~5.4.0",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~5.15.0",
|
||||
"typescript": "~3.5.3"
|
||||
}
|
||||
}
|
||||
0
packages/now-build-utils/test/fixtures/03-zero-config-angular/src/app/app.component.css
vendored
Normal file
536
packages/now-build-utils/test/fixtures/03-zero-config-angular/src/app/app.component.html
vendored
Normal file
@@ -0,0 +1,536 @@
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * Delete the template below * * * * * * * * * * -->
|
||||
<!-- * * * * * * * to get started with your project! * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
|
||||
<style>
|
||||
:host {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
height: 60px;
|
||||
margin: -8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #1976d2;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.toolbar img {
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
.toolbar #twitter-logo {
|
||||
height: 40px;
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
.toolbar #twitter-logo:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
margin: 32px auto;
|
||||
padding: 0 16px;
|
||||
max-width: 960px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
svg.material-icons {
|
||||
height: 24px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
svg.material-icons:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.card svg.material-icons path {
|
||||
fill: #888;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #eee;
|
||||
background-color: #fafafa;
|
||||
height: 40px;
|
||||
width: 200px;
|
||||
margin: 0 8px 16px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: all 0.2s ease-in-out;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.card-container .card:not(:last-child) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.card.card-small {
|
||||
height: 16px;
|
||||
width: 168px;
|
||||
}
|
||||
|
||||
.card-container .card:not(.highlight-card) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-container .card:not(.highlight-card):hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 4px 17px rgba(black, 0.35);
|
||||
}
|
||||
|
||||
.card-container .card:not(.highlight-card):hover .material-icons path {
|
||||
fill: rgb(105, 103, 103);
|
||||
}
|
||||
|
||||
.card.highlight-card {
|
||||
background-color: #1976d2;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
width: auto;
|
||||
min-width: 30%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card.card.highlight-card span {
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
svg#rocket {
|
||||
width: 80px;
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
top: -24px;
|
||||
}
|
||||
|
||||
svg#rocket-smoke {
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 180px;
|
||||
z-index: -10;
|
||||
}
|
||||
|
||||
a,
|
||||
a:visited,
|
||||
a:hover {
|
||||
color: #1976d2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #125699;
|
||||
}
|
||||
|
||||
.terminal {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
max-width: 600px;
|
||||
border-radius: 6px;
|
||||
padding-top: 45px;
|
||||
margin-top: 8px;
|
||||
overflow: hidden;
|
||||
background-color: rgb(15, 15, 16);
|
||||
}
|
||||
|
||||
.terminal::before {
|
||||
content: "\2022 \2022 \2022";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 4px;
|
||||
background: rgb(58, 58, 58);
|
||||
color: #c2c3c4;
|
||||
width: 100%;
|
||||
font-size: 2rem;
|
||||
line-height: 0;
|
||||
padding: 14px 0;
|
||||
text-indent: 4px;
|
||||
}
|
||||
|
||||
.terminal pre {
|
||||
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
|
||||
color: white;
|
||||
padding: 0 1rem 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.circle-link {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 40px;
|
||||
margin: 8px;
|
||||
background-color: white;
|
||||
border: 1px solid #eeeeee;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
|
||||
transition: 1s ease-out;
|
||||
}
|
||||
|
||||
.circle-link:hover {
|
||||
transform: translateY(-0.25rem);
|
||||
box-shadow: 0px 3px 15px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
footer a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.github-star-badge {
|
||||
color: #24292e;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
padding: 3px 10px;
|
||||
border: 1px solid rgba(27,31,35,.2);
|
||||
border-radius: 3px;
|
||||
background-image: linear-gradient(-180deg,#fafbfc,#eff3f6 90%);
|
||||
margin-left: 4px;
|
||||
font-weight: 600;
|
||||
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
|
||||
}
|
||||
|
||||
.github-star-badge:hover {
|
||||
background-image: linear-gradient(-180deg,#f0f3f6,#e6ebf1 90%);
|
||||
border-color: rgba(27,31,35,.35);
|
||||
background-position: -.5em;
|
||||
}
|
||||
|
||||
.github-star-badge .material-icons {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
svg#clouds {
|
||||
position: fixed;
|
||||
bottom: -160px;
|
||||
left: -230px;
|
||||
z-index: -10;
|
||||
width: 1920px;
|
||||
}
|
||||
|
||||
|
||||
/* Responsive Styles */
|
||||
@media screen and (max-width: 767px) {
|
||||
|
||||
.card-container > *:not(.circle-link) ,
|
||||
.terminal {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card:not(.highlight-card) {
|
||||
height: 16px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.card.highlight-card span {
|
||||
margin-left: 72px;
|
||||
}
|
||||
|
||||
svg#rocket-smoke {
|
||||
right: 120px;
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 575px) {
|
||||
svg#rocket-smoke {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<div class="toolbar" role="banner">
|
||||
<img
|
||||
width="40"
|
||||
alt="Angular Logo"
|
||||
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
|
||||
/>
|
||||
<span>Welcome</span>
|
||||
<div class="spacer"></div>
|
||||
<a aria-label="Angular on twitter" target="_blank" rel="noopener" href="https://twitter.com/angular" title="Twitter">
|
||||
|
||||
<svg id="twitter-logo" height="24" data-name="Logo — FIXED" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: #ffffff;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" width="400" height="400" />
|
||||
<path class="cls-2" d="M153.62,301.59c94.34,0,145.94-78.16,145.94-145.94,0-2.22,0-4.43-.15-6.63A104.36,104.36,0,0,0,325,122.47a102.38,102.38,0,0,1-29.46,8.07,51.47,51.47,0,0,0,22.55-28.37,102.79,102.79,0,0,1-32.57,12.45,51.34,51.34,0,0,0-87.41,46.78A145.62,145.62,0,0,1,92.4,107.81a51.33,51.33,0,0,0,15.88,68.47A50.91,50.91,0,0,1,85,169.86c0,.21,0,.43,0,.65a51.31,51.31,0,0,0,41.15,50.28,51.21,51.21,0,0,1-23.16.88,51.35,51.35,0,0,0,47.92,35.62,102.92,102.92,0,0,1-63.7,22A104.41,104.41,0,0,1,75,278.55a145.21,145.21,0,0,0,78.62,23"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="content" role="main">
|
||||
|
||||
<!-- Highlight Card -->
|
||||
<div class="card highlight-card card-small">
|
||||
|
||||
<svg id="rocket" alt="Rocket Ship" xmlns="http://www.w3.org/2000/svg" width="101.678" height="101.678" viewBox="0 0 101.678 101.678">
|
||||
<g id="Group_83" data-name="Group 83" transform="translate(-141 -696)">
|
||||
<circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="#dd0031"/>
|
||||
<g id="Group_47" data-name="Group 47" transform="translate(165.185 720.185)">
|
||||
<path id="Path_33" data-name="Path 33" d="M3.4,42.615a3.084,3.084,0,0,0,3.553,3.553,21.419,21.419,0,0,0,12.215-6.107L9.511,30.4A21.419,21.419,0,0,0,3.4,42.615Z" transform="translate(0.371 3.363)" fill="#fff"/>
|
||||
<path id="Path_34" data-name="Path 34" d="M53.3,3.221A3.09,3.09,0,0,0,50.081,0,48.227,48.227,0,0,0,18.322,13.437c-6-1.666-14.991-1.221-18.322,7.218A33.892,33.892,0,0,1,9.439,25.1l-.333.666a3.013,3.013,0,0,0,.555,3.553L23.985,43.641a2.9,2.9,0,0,0,3.553.555l.666-.333A33.892,33.892,0,0,1,32.647,53.3c8.55-3.664,8.884-12.326,7.218-18.322A48.227,48.227,0,0,0,53.3,3.221ZM34.424,9.772a6.439,6.439,0,1,1,9.106,9.106,6.368,6.368,0,0,1-9.106,0A6.467,6.467,0,0,1,34.424,9.772Z" transform="translate(0 0.005)" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<span>{{ title }} app is running!</span>
|
||||
|
||||
<svg id="rocket-smoke" alt="Rocket Ship Smoke" xmlns="http://www.w3.org/2000/svg" width="516.119" height="1083.632" viewBox="0 0 516.119 1083.632">
|
||||
<path id="Path_40" data-name="Path 40" d="M644.6,141S143.02,215.537,147.049,870.207s342.774,201.755,342.774,201.755S404.659,847.213,388.815,762.2c-27.116-145.51-11.551-384.124,271.9-609.1C671.15,139.365,644.6,141,644.6,141Z" transform="translate(-147.025 -140.939)" fill="#f5f5f5"/>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Resources -->
|
||||
<h2>Resources</h2>
|
||||
<p>Here are some links to help you get started:</p>
|
||||
|
||||
<div class="card-container">
|
||||
<a class="card" target="_blank" rel="noopener" href="https://angular.io/tutorial">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M5 13.18v4L12 21l7-3.82v-4L12 17l-7-3.82zM12 3L1 9l11 6 9-4.91V17h2V9L12 3z"/></svg>
|
||||
|
||||
<span>Learn Angular</span>
|
||||
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg> </a>
|
||||
|
||||
<a class="card" target="_blank" rel="noopener" href="https://angular.io/cli">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg>
|
||||
|
||||
<span>CLI Documentation</span>
|
||||
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
|
||||
</a>
|
||||
|
||||
<a class="card" target="_blank" rel="noopener" href="https://blog.angular.io/">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M13.5.67s.74 2.65.74 4.8c0 2.06-1.35 3.73-3.41 3.73-2.07 0-3.63-1.67-3.63-3.73l.03-.36C5.21 7.51 4 10.62 4 14c0 4.42 3.58 8 8 8s8-3.58 8-8C20 8.61 17.41 3.8 13.5.67zM11.71 19c-1.78 0-3.22-1.4-3.22-3.14 0-1.62 1.05-2.76 2.81-3.12 1.77-.36 3.6-1.21 4.62-2.58.39 1.29.59 2.65.59 4.04 0 2.65-2.15 4.8-4.8 4.8z"/></svg>
|
||||
|
||||
<span>Angular Blog</span>
|
||||
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Next Steps -->
|
||||
<h2>Next Steps</h2>
|
||||
<p>What do you want to do next with your app?</p>
|
||||
|
||||
<input type="hidden" #selection>
|
||||
|
||||
<div class="card-container">
|
||||
<div class="card card-small" (click)="selection.value = 'component'" tabindex="0">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||
|
||||
<span>New Component</span>
|
||||
</div>
|
||||
|
||||
<div class="card card-small" (click)="selection.value = 'material'" tabindex="0">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||
|
||||
<span>Angular Material</span>
|
||||
</div>
|
||||
|
||||
<div class="card card-small" (click)="selection.value = 'dependency'" tabindex="0">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||
|
||||
<span>Add Dependency</span>
|
||||
</div>
|
||||
|
||||
<div class="card card-small" (click)="selection.value = 'test'" tabindex="0">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||
|
||||
<span>Run and Watch Tests</span>
|
||||
</div>
|
||||
|
||||
<div class="card card-small" (click)="selection.value = 'build'" tabindex="0">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||
|
||||
<span>Build for Production</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Terminal -->
|
||||
<div class="terminal" [ngSwitch]="selection.value">
|
||||
<pre *ngSwitchDefault>ng generate component xyz</pre>
|
||||
<pre *ngSwitchCase="'material'">ng add @angular/material</pre>
|
||||
<pre *ngSwitchCase="'dependency'">ng add _____</pre>
|
||||
<pre *ngSwitchCase="'test'">ng test</pre>
|
||||
<pre *ngSwitchCase="'build'">ng build --prod</pre>
|
||||
</div>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="card-container">
|
||||
<a class="circle-link" title="Animations" href="https://angular.io/guide/animations" target="_blank" rel="noopener">
|
||||
<svg id="Group_20" data-name="Group 20" xmlns="http://www.w3.org/2000/svg" width="21.813" height="23.453" viewBox="0 0 21.813 23.453">
|
||||
<path id="Path_15" data-name="Path 15" d="M4099.584,972.736h0l-10.882,3.9,1.637,14.4,9.245,5.153,9.245-5.153,1.686-14.4Z" transform="translate(-4088.702 -972.736)" fill="#ffa726"/>
|
||||
<path id="Path_16" data-name="Path 16" d="M4181.516,972.736v23.453l9.245-5.153,1.686-14.4Z" transform="translate(-4170.633 -972.736)" fill="#fb8c00"/>
|
||||
<path id="Path_17" data-name="Path 17" d="M4137.529,1076.127l-7.7-3.723,4.417-2.721,7.753,3.723Z" transform="translate(-4125.003 -1058.315)" fill="#ffe0b2"/>
|
||||
<path id="Path_18" data-name="Path 18" d="M4137.529,1051.705l-7.7-3.723,4.417-2.721,7.753,3.723Z" transform="translate(-4125.003 -1036.757)" fill="#fff3e0"/>
|
||||
<path id="Path_19" data-name="Path 19" d="M4137.529,1027.283l-7.7-3.723,4.417-2.721,7.753,3.723Z" transform="translate(-4125.003 -1015.199)" fill="#fff"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a class="circle-link" title="CLI" href="https://cli.angular.io/" target="_blank" rel="noopener">
|
||||
<svg alt="Angular CLI Logo" xmlns="http://www.w3.org/2000/svg" width="21.762" height="23.447" viewBox="0 0 21.762 23.447">
|
||||
<g id="Group_21" data-name="Group 21" transform="translate(0)">
|
||||
<path id="Path_20" data-name="Path 20" d="M2660.313,313.618h0l-10.833,3.9,1.637,14.4,9.2,5.152,9.244-5.152,1.685-14.4Z" transform="translate(-2649.48 -313.618)" fill="#37474f"/>
|
||||
<path id="Path_21" data-name="Path 21" d="M2741.883,313.618v23.447l9.244-5.152,1.685-14.4Z" transform="translate(-2731.05 -313.618)" fill="#263238"/>
|
||||
<path id="Path_22" data-name="Path 22" d="M2692.293,379.169h11.724V368.618h-11.724Zm11.159-.6h-10.608v-9.345h10.621v9.345Z" transform="translate(-2687.274 -362.17)" fill="#fff"/>
|
||||
<path id="Path_23" data-name="Path 23" d="M2709.331,393.688l.4.416,2.265-2.28-2.294-2.294-.4.4,1.893,1.893Z" transform="translate(-2702.289 -380.631)" fill="#fff"/>
|
||||
<rect id="Rectangle_12" data-name="Rectangle 12" width="3.517" height="0.469" transform="translate(9.709 13.744)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a class="circle-link" title="Augury" href="https://augury.rangle.io/" target="_blank" rel="noopener">
|
||||
<svg alt="Angular Augury Logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="21.81" height="23.447" viewBox="0 0 21.81 23.447">
|
||||
<defs>
|
||||
<clipPath id="clip-path">
|
||||
<rect id="Rectangle_13" data-name="Rectangle 13" width="10.338" height="10.27" fill="none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="Group_25" data-name="Group 25" transform="translate(0)">
|
||||
<path id="Path_24" data-name="Path 24" d="M3780.155,311.417h0l-10.881,3.9,1.637,14.4,9.244,5.152,9.244-5.152,1.685-14.4Z" transform="translate(-3769.274 -311.417)" fill="#4a3493"/>
|
||||
<path id="Path_25" data-name="Path 25" d="M3862.088,311.417v23.447l9.244-5.152,1.685-14.4Z" transform="translate(-3851.207 -311.417)" fill="#311b92"/>
|
||||
<g id="Group_24" data-name="Group 24" transform="translate(6.194 6.73)" opacity="0.5">
|
||||
<g id="Group_23" data-name="Group 23" transform="translate(0 0)">
|
||||
<g id="Group_22" data-name="Group 22" clip-path="url(#clip-path)">
|
||||
<path id="Path_26" data-name="Path 26" d="M3832.4,373.252a5.168,5.168,0,1,1-5.828-4.383,5.216,5.216,0,0,1,2.574.3,3.017,3.017,0,1,0,3.252,4.086Z" transform="translate(-3822.107 -368.821)" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path id="Path_27" data-name="Path 27" d="M3830.582,370.848a5.162,5.162,0,1,1-3.254-4.086,3.017,3.017,0,1,0,3.252,4.086Z" transform="translate(-3814.311 -359.969)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a class="circle-link" title="Protractor" href="https://www.protractortest.org/" target="_blank" rel="noopener">
|
||||
<svg alt="Angular Protractor Logo" xmlns="http://www.w3.org/2000/svg" width="21.81" height="23.447" viewBox="0 0 21.81 23.447">
|
||||
<g id="Group_26" data-name="Group 26" transform="translate(0)">
|
||||
<path id="Path_28" data-name="Path 28" d="M4620.155,311.417h0l-10.881,3.9,1.637,14.4,9.244,5.152,9.244-5.152,1.685-14.4Z" transform="translate(-4609.274 -311.417)" fill="#e13439"/>
|
||||
<path id="Path_29" data-name="Path 29" d="M4702.088,311.417v23.447l9.244-5.152,1.685-14.4Z" transform="translate(-4691.207 -311.417)" fill="#b52f32"/>
|
||||
<path id="Path_30" data-name="Path 30" d="M4651.044,369.58v-.421h1.483a7.6,7.6,0,0,0-2.106-5.052l-1.123,1.123-.3-.3,1.122-1.121a7.588,7.588,0,0,0-4.946-2.055v1.482h-.421v-1.485a7.589,7.589,0,0,0-5.051,2.058l1.122,1.121-.3.3-1.123-1.123a7.591,7.591,0,0,0-2.106,5.052h1.482v.421h-1.489v1.734h15.241V369.58Zm-10.966-.263a4.835,4.835,0,0,1,9.67,0Z" transform="translate(-4634.008 -355.852)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a class="circle-link" title="Find a Local Meetup" href="https://www.meetup.com/find/?keywords=angular" target="_blank" rel="noopener">
|
||||
<svg alt="Meetup Logo" xmlns="http://www.w3.org/2000/svg" width="24.607" height="23.447" viewBox="0 0 24.607 23.447">
|
||||
<path id="logo--mSwarm" d="M21.221,14.95A4.393,4.393,0,0,1,17.6,19.281a4.452,4.452,0,0,1-.8.069c-.09,0-.125.035-.154.117a2.939,2.939,0,0,1-2.506,2.091,2.868,2.868,0,0,1-2.248-.624.168.168,0,0,0-.245-.005,3.926,3.926,0,0,1-2.589.741,4.015,4.015,0,0,1-3.7-3.347,2.7,2.7,0,0,1-.043-.38c0-.106-.042-.146-.143-.166a3.524,3.524,0,0,1-1.516-.69A3.623,3.623,0,0,1,2.23,14.557a3.66,3.66,0,0,1,1.077-3.085.138.138,0,0,0,.026-.2,3.348,3.348,0,0,1-.451-1.821,3.46,3.46,0,0,1,2.749-3.28.44.44,0,0,0,.355-.281,5.072,5.072,0,0,1,3.863-3,5.028,5.028,0,0,1,3.555.666.31.31,0,0,0,.271.03A4.5,4.5,0,0,1,18.3,4.7a4.4,4.4,0,0,1,1.334,2.751,3.658,3.658,0,0,1,.022.706.131.131,0,0,0,.1.157,2.432,2.432,0,0,1,1.574,1.645,2.464,2.464,0,0,1-.7,2.616c-.065.064-.051.1-.014.166A4.321,4.321,0,0,1,21.221,14.95ZM13.4,14.607a2.09,2.09,0,0,0,1.409,1.982,4.7,4.7,0,0,0,1.275.221,1.807,1.807,0,0,0,.9-.151.542.542,0,0,0,.321-.545.558.558,0,0,0-.359-.534,1.2,1.2,0,0,0-.254-.078c-.262-.047-.526-.086-.787-.138a.674.674,0,0,1-.617-.75,3.394,3.394,0,0,1,.218-1.109c.217-.658.509-1.286.79-1.918a15.609,15.609,0,0,0,.745-1.86,1.95,1.95,0,0,0,.06-1.073,1.286,1.286,0,0,0-1.051-1.033,1.977,1.977,0,0,0-1.521.2.339.339,0,0,1-.446-.042c-.1-.092-.2-.189-.307-.284a1.214,1.214,0,0,0-1.643-.061,7.563,7.563,0,0,1-.614.512A.588.588,0,0,1,10.883,8c-.215-.115-.437-.215-.659-.316a2.153,2.153,0,0,0-.695-.248A2.091,2.091,0,0,0,7.541,8.562a9.915,9.915,0,0,0-.405.986c-.559,1.545-1.015,3.123-1.487,4.7a1.528,1.528,0,0,0,.634,1.777,1.755,1.755,0,0,0,1.5.211,1.35,1.35,0,0,0,.824-.858c.543-1.281,1.032-2.584,1.55-3.875.142-.355.28-.712.432-1.064a.548.548,0,0,1,.851-.24.622.622,0,0,1,.185.539,2.161,2.161,0,0,1-.181.621c-.337.852-.68,1.7-1.018,2.552a2.564,2.564,0,0,0-.173.528.624.624,0,0,0,.333.71,1.073,1.073,0,0,0,.814.034,1.22,1.22,0,0,0,.657-.655q.758-1.488,1.511-2.978.35-.687.709-1.37a1.073,1.073,0,0,1,.357-.434.43.43,0,0,1,.463-.016.373.373,0,0,1,.153.387.7.7,0,0,1-.057.236c-.065.157-.127.316-.2.469-.42.883-.846,1.763-1.262,2.648A2.463,2.463,0,0,0,13.4,14.607Zm5.888,6.508a1.09,1.09,0,0,0-2.179.006,1.09,1.09,0,0,0,2.179-.006ZM1.028,12.139a1.038,1.038,0,1,0,.01-2.075,1.038,1.038,0,0,0-.01,2.075ZM13.782.528a1.027,1.027,0,1,0-.011,2.055A1.027,1.027,0,0,0,13.782.528ZM22.21,6.95a.882.882,0,0,0-1.763.011A.882.882,0,0,0,22.21,6.95ZM4.153,4.439a.785.785,0,1,0,.787-.78A.766.766,0,0,0,4.153,4.439Zm8.221,18.22a.676.676,0,1,0-.677.666A.671.671,0,0,0,12.374,22.658ZM22.872,12.2a.674.674,0,0,0-.665.665.656.656,0,0,0,.655.643.634.634,0,0,0,.655-.644A.654.654,0,0,0,22.872,12.2ZM7.171-.123A.546.546,0,0,0,6.613.43a.553.553,0,1,0,1.106,0A.539.539,0,0,0,7.171-.123ZM24.119,9.234a.507.507,0,0,0-.493.488.494.494,0,0,0,.494.494.48.48,0,0,0,.487-.483A.491.491,0,0,0,24.119,9.234Zm-19.454,9.7a.5.5,0,0,0-.488-.488.491.491,0,0,0-.487.5.483.483,0,0,0,.491.479A.49.49,0,0,0,4.665,18.936Z" transform="translate(0 0.123)" fill="#f64060"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a class="circle-link" title="Join the Conversation on Gitter" href="https://gitter.im/angular/angular" target="_blank" rel="noopener">
|
||||
<svg alt="Gitter Logo" xmlns="http://www.w3.org/2000/svg" width="19.447" height="19.447" viewBox="0 0 19.447 19.447">
|
||||
<g id="Group_40" data-name="Group 40" transform="translate(-1612 -405)">
|
||||
<rect id="Rectangle_19" data-name="Rectangle 19" width="19.447" height="19.447" transform="translate(1612 405)" fill="#e60257"/>
|
||||
<g id="gitter" transform="translate(1617.795 408.636)">
|
||||
<g id="Group_33" data-name="Group 33" transform="translate(0 0)">
|
||||
<rect id="Rectangle_15" data-name="Rectangle 15" width="1.04" height="9.601" transform="translate(2.304 2.324)" fill="#fff"/>
|
||||
<rect id="Rectangle_16" data-name="Rectangle 16" width="1.04" height="9.601" transform="translate(4.607 2.324)" fill="#fff"/>
|
||||
<rect id="Rectangle_17" data-name="Rectangle 17" width="1.04" height="4.648" transform="translate(6.91 2.324)" fill="#fff"/>
|
||||
<rect id="Rectangle_18" data-name="Rectangle 18" width="1.04" height="6.971" transform="translate(0 0)" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
Love Angular?
|
||||
<a href="https://github.com/angular/angular" target="_blank" rel="noopener"> Give our repo a star.
|
||||
<div class="github-star-badge">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>
|
||||
Star
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://github.com/angular/angular" target="_blank" rel="noopener">
|
||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" fill="#1976d2"/><path d="M0 0h24v24H0z" fill="none"/></svg>
|
||||
</a>
|
||||
</footer>
|
||||
|
||||
<svg id="clouds" alt="Gray Clouds Background" xmlns="http://www.w3.org/2000/svg" width="2611.084" height="485.677" viewBox="0 0 2611.084 485.677">
|
||||
<path id="Path_39" data-name="Path 39" d="M2379.709,863.793c10-93-77-171-168-149-52-114-225-105-264,15-75,3-140,59-152,133-30,2.83-66.725,9.829-93.5,26.25-26.771-16.421-63.5-23.42-93.5-26.25-12-74-77-130-152-133-39-120-212-129-264-15-54.084-13.075-106.753,9.173-138.488,48.9-31.734-39.726-84.4-61.974-138.487-48.9-52-114-225-105-264,15a162.027,162.027,0,0,0-103.147,43.044c-30.633-45.365-87.1-72.091-145.206-58.044-52-114-225-105-264,15-75,3-140,59-152,133-53,5-127,23-130,83-2,42,35,72,70,86,49,20,106,18,157,5a165.625,165.625,0,0,0,120,0c47,94,178,113,251,33,61.112,8.015,113.854-5.72,150.492-29.764a165.62,165.62,0,0,0,110.861-3.236c47,94,178,113,251,33,31.385,4.116,60.563,2.495,86.487-3.311,25.924,5.806,55.1,7.427,86.488,3.311,73,80,204,61,251-33a165.625,165.625,0,0,0,120,0c51,13,108,15,157-5a147.188,147.188,0,0,0,33.5-18.694,147.217,147.217,0,0,0,33.5,18.694c49,20,106,18,157,5a165.625,165.625,0,0,0,120,0c47,94,178,113,251,33C2446.709,1093.793,2554.709,922.793,2379.709,863.793Z" transform="translate(142.69 -634.312)" fill="#eee"/>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * The content above * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
|
||||
|
||||
31
packages/now-build-utils/test/fixtures/03-zero-config-angular/src/app/app.component.spec.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AppComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'angular'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('angular');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain(
|
||||
'angular app is running!'
|
||||
);
|
||||
});
|
||||
});
|
||||
10
packages/now-build-utils/test/fixtures/03-zero-config-angular/src/app/app.component.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css'],
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'angular';
|
||||
}
|
||||