mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Create with-firebase-hosting-and-typescript example (#4443)
Adds an example based off of @jthegedus work on firebase hosting, compatible with next v6 and using typescript in both the firebase functions and the next app.
This commit is contained in:
parent
f2261050a0
commit
35d32b48cc
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"projects": {
|
||||
"default": "<project-name-here>"
|
||||
}
|
||||
}
|
1
examples/with-firebase-hosting-and-typescript/.gitignore
vendored
Normal file
1
examples/with-firebase-hosting-and-typescript/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
dist/
|
74
examples/with-firebase-hosting-and-typescript/README.md
Normal file
74
examples/with-firebase-hosting-and-typescript/README.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
# With Firebase Hosting and Typescript example
|
||||
|
||||
## How to use
|
||||
|
||||
### Using `create-next-app`
|
||||
|
||||
Execute [`create-next-app`](https://github.com/segmentio/create-next-app) with [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) or [npx](https://github.com/zkat/npx#readme) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example with-firebase-hosting-and-typescript with-firebase-hosting-and-typescript-app
|
||||
# or
|
||||
yarn create next-app --example with-firebase-hosting-and-typescript with-firebase-hosting-and-typescript-app
|
||||
```
|
||||
|
||||
### Download manually
|
||||
|
||||
Download the example [or clone the repo](https://github.com/zeit/next.js):
|
||||
|
||||
```bash
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-firebase-hosting-and-typescript
|
||||
cd with-firebase-hosting-and-typescript
|
||||
```
|
||||
|
||||
Set up firebase:
|
||||
|
||||
* install Firebase Tools: `npm i -g firebase-tools`
|
||||
* create a project through the [firebase web console](https://console.firebase.google.com/)
|
||||
* grab the projects ID from the web consoles URL: https://console.firebase.google.com/project/<projectId>
|
||||
* update the `.firebaserc` default project ID to the newly created project
|
||||
* login to the Firebase CLI tool with `firebase login`
|
||||
|
||||
#### Install project:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
#### Run Next.js development:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
#### Run Firebase locally for testing:
|
||||
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
#### Deploy it to the cloud with Firebase:
|
||||
|
||||
```bash
|
||||
npm run deploy
|
||||
```
|
||||
|
||||
#### Clean dist folder
|
||||
|
||||
```bash
|
||||
npm run clean
|
||||
```
|
||||
|
||||
## The idea behind the example
|
||||
|
||||
The goal is to host the Next.js app on Firebase Cloud Functions with Firebase Hosting rewrite rules so our app is served from our Firebase Hosting URL, with a complete Typescript stack for both the Next app and for the Firebase Functions. Each individual `page` bundle is served in a new call to the Cloud Function which performs the initial server render.
|
||||
|
||||
This is based off of the work of @jthegedus in the [with-firebase-hosting](https://github.com/zeit/next.js/tree/canary/examples/with-firebase-hosting) example.
|
||||
|
||||
If you're having issues, feel free to tag @sampsonjoliver in the [issue you create on the next.js repo](https://github.com/zeit/next.js/issues/new)
|
||||
|
||||
## Important
|
||||
|
||||
* The empty `placeholder.html` file is so Firebase Hosting does not error on an empty `public/` folder and still hosts at the Firebase project URL.
|
||||
* `firebase.json` outlines the catchall rewrite rule for our Cloud Function.
|
||||
* The [Firebase predeploy](https://firebase.google.com/docs/cli/#predeploy_and_postdeploy_hooks) hooks defined in `firebase.json` will handle linting and compiling of the next app and the functions sourceswhen `firebase deploy` is invoked. The only scripts you should need are `dev`, `clean` and `deploy`.
|
24
examples/with-firebase-hosting-and-typescript/firebase.json
Normal file
24
examples/with-firebase-hosting-and-typescript/firebase.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"functions": {
|
||||
"source": "dist/functions",
|
||||
"predeploy": [
|
||||
"npm run lint-functions",
|
||||
"npm run lint-app",
|
||||
"npm run typecheck-app",
|
||||
"npm run build-functions",
|
||||
"npm run build-app",
|
||||
"npm run copy-deps",
|
||||
"npm run install-deps"
|
||||
]
|
||||
},
|
||||
"hosting": {
|
||||
"public": "dist/public",
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "**/**",
|
||||
"function": "nextApp"
|
||||
}
|
||||
],
|
||||
"predeploy": "npm run build-public"
|
||||
}
|
||||
}
|
38
examples/with-firebase-hosting-and-typescript/package.json
Normal file
38
examples/with-firebase-hosting-and-typescript/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "with-firebase-hosting",
|
||||
"version": "1.0.0",
|
||||
"description": "Host Next.js SSR app on Firebase Cloud Functions with Firebase Hosting redirects.",
|
||||
"scripts": {
|
||||
"dev": "next src/app",
|
||||
"serve": "NODE_ENV=production firebase serve --only functions,hosting",
|
||||
"deploy": "firebase deploy",
|
||||
"clean": "rimraf \"dist/functions\" && rimraf \"dist/public\"",
|
||||
"build-app": "next build \"src/app\"",
|
||||
"build-public": "cpx \"src/public/**/*.*\" \"dist/public\" -C",
|
||||
"build-functions": "tsc --project src/functions",
|
||||
"lint-app": "tslint --project src/app",
|
||||
"typecheck-app": "tsc --project src/app",
|
||||
"lint-functions": "tslint --project src/functions",
|
||||
"copy-deps": "cpx \"*{package.json,package-lock.json,yarn.lock}\" \"dist/functions\"",
|
||||
"install-deps": "cd \"dist/functions\" && npm i"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zeit/next-typescript": "^1.0.0",
|
||||
"firebase-admin": "~5.12.1",
|
||||
"firebase-functions": "^1.0.1",
|
||||
"next": "^6.0.3",
|
||||
"react": "^16.3.2",
|
||||
"react-dom": "^16.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/next": "^2.4.10",
|
||||
"@types/react": "^16.3.14",
|
||||
"cpx": "1.5.0",
|
||||
"firebase-tools": "3.18.4",
|
||||
"prettier": "1.12.1",
|
||||
"rimraf": "2.6.2",
|
||||
"tslint": "^5.8.0",
|
||||
"tslint-react": "3.6.0",
|
||||
"typescript": "^2.5.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"presets": ["next/babel", "@zeit/next-typescript/babel"]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import Header from './Header';
|
||||
|
||||
const App = ({ children }: { children?: any }) => (
|
||||
<main>
|
||||
<Header />
|
||||
{children}
|
||||
</main>
|
||||
);
|
||||
|
||||
export default App;
|
|
@ -0,0 +1,12 @@
|
|||
import Link from 'next/link';
|
||||
|
||||
export default ({ pathname }: { pathname?: any }) => (
|
||||
<header>
|
||||
<Link href='/'>
|
||||
<a className={pathname === '/' ? 'is-active' : ''}>Home</a>
|
||||
</Link>
|
||||
<Link href='/about'>
|
||||
<a className={pathname === '/about' ? 'is-active' : ''}>About</a>
|
||||
</Link>
|
||||
</header>
|
||||
);
|
|
@ -0,0 +1,2 @@
|
|||
const withTypescript = require('@zeit/next-typescript')
|
||||
module.exports = withTypescript({ distDir: '../../dist/functions/next' })
|
|
@ -0,0 +1,7 @@
|
|||
import App from '../components/App';
|
||||
|
||||
export default () => (
|
||||
<App>
|
||||
<p>About Page</p>
|
||||
</App>
|
||||
);
|
|
@ -0,0 +1,7 @@
|
|||
import App from '../components/App';
|
||||
|
||||
export default () => (
|
||||
<App>
|
||||
<p>Index Page</p>
|
||||
</App>
|
||||
);
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"allowJs": false,
|
||||
"jsx": "preserve",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noImplicitAny": false,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"preserveConstEnums": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"noEmit": true,
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom",
|
||||
"es2016"
|
||||
],
|
||||
"baseUrl": ".",
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": ["tslint:latest", "tslint-react"],
|
||||
"rules": {
|
||||
"quotemark": [true, "single"],
|
||||
"no-submodule-imports": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import * as functions from 'firebase-functions';
|
||||
const next = require('next');
|
||||
|
||||
const dev = process.env.NODE_ENV !== 'production';
|
||||
const app = next({ dev, conf: { distDir: 'next' } });
|
||||
const handle = app.getRequestHandler();
|
||||
|
||||
export const nextApp = functions.https.onRequest((req, res) => {
|
||||
console.log('File: ' + req.originalUrl);
|
||||
return app.prepare().then(() => handle(req, res));
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
import * as functions from 'firebase-functions';
|
||||
|
||||
export { nextApp } from './app/next';
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es6"],
|
||||
"module": "commonjs",
|
||||
"noImplicitReturns": true,
|
||||
"outDir": "../../dist/functions",
|
||||
"sourceMap": true,
|
||||
"target": "es6",
|
||||
"baseUrl": "./src"
|
||||
},
|
||||
"compileOnSave": true,
|
||||
"include": ["src"]
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
{
|
||||
"rules": {
|
||||
// -- Strict errors --
|
||||
// These lint rules are likely always a good idea.
|
||||
|
||||
// Force function overloads to be declared together. This ensures readers understand APIs.
|
||||
"adjacent-overload-signatures": true,
|
||||
|
||||
// Do not allow the subtle/obscure comma operator.
|
||||
"ban-comma-operator": true,
|
||||
|
||||
// Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules.
|
||||
"no-namespace": true,
|
||||
|
||||
// Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars.
|
||||
"no-parameter-reassignment": true,
|
||||
|
||||
// Force the use of ES6-style imports instead of /// <reference path=> imports.
|
||||
"no-reference": true,
|
||||
|
||||
// Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the
|
||||
// code currently being edited (they may be incorrectly handling a different type case that does not exist).
|
||||
"no-unnecessary-type-assertion": true,
|
||||
|
||||
// Disallow nonsensical label usage.
|
||||
"label-position": true,
|
||||
|
||||
// Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }.
|
||||
"no-conditional-assignment": true,
|
||||
|
||||
// Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed).
|
||||
"no-construct": true,
|
||||
|
||||
// Do not allow super() to be called twice in a constructor.
|
||||
"no-duplicate-super": true,
|
||||
|
||||
// Do not allow the same case to appear more than once in a switch block.
|
||||
"no-duplicate-switch-case": true,
|
||||
|
||||
// Do not allow a variable to be declared more than once in the same block. Consider function parameters in this
|
||||
// rule.
|
||||
"no-duplicate-variable": [true, "check-parameters"],
|
||||
|
||||
// Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should
|
||||
// instead use a separate variable name.
|
||||
"no-shadowed-variable": true,
|
||||
|
||||
// Empty blocks are almost never needed. Allow the one general exception: empty catch blocks.
|
||||
"no-empty": [true, "allow-empty-catch"],
|
||||
|
||||
// Functions must either be handled directly (e.g. with a catch() handler) or returned to another function.
|
||||
// This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on.
|
||||
"no-floating-promises": true,
|
||||
|
||||
// Do not allow any imports for modules that are not in package.json. These will almost certainly fail when
|
||||
// deployed.
|
||||
"no-implicit-dependencies": true,
|
||||
|
||||
// The 'this' keyword can only be used inside of classes.
|
||||
"no-invalid-this": true,
|
||||
|
||||
// Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead.
|
||||
"no-string-throw": true,
|
||||
|
||||
// Disallow control flow statements, such as return, continue, break, and throw in finally blocks.
|
||||
"no-unsafe-finally": true,
|
||||
|
||||
// Do not allow variables to be used before they are declared.
|
||||
"no-use-before-declare": true,
|
||||
|
||||
// Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid();
|
||||
"no-void-expression": [true, "ignore-arrow-function-shorthand"],
|
||||
|
||||
// Disallow duplicate imports in the same file.
|
||||
"no-duplicate-imports": true,
|
||||
|
||||
|
||||
// -- Strong Warnings --
|
||||
// These rules should almost never be needed, but may be included due to legacy code.
|
||||
// They are left as a warning to avoid frustration with blocked deploys when the developer
|
||||
// understand the warning and wants to deploy anyway.
|
||||
|
||||
// Warn when an empty interface is defined. These are generally not useful.
|
||||
"no-empty-interface": {"severity": "warning"},
|
||||
|
||||
// Warn when an import will have side effects.
|
||||
"no-import-side-effect": {"severity": "warning"},
|
||||
|
||||
// Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for
|
||||
// most values and let for values that will change.
|
||||
"no-var-keyword": {"severity": "warning"},
|
||||
|
||||
// Prefer === and !== over == and !=. The latter operators support overloads that are often accidental.
|
||||
"triple-equals": {"severity": "warning"},
|
||||
|
||||
// Warn when using deprecated APIs.
|
||||
"deprecation": {"severity": "warning"},
|
||||
|
||||
// -- Light Warnigns --
|
||||
// These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info"
|
||||
// if TSLint supported such a level.
|
||||
|
||||
// prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array.
|
||||
// (Even better: check out utils like .map if transforming an array!)
|
||||
"prefer-for-of": {"severity": "warning"},
|
||||
|
||||
// Warns if function overloads could be unified into a single function with optional or rest parameters.
|
||||
"unified-signatures": {"severity": "warning"},
|
||||
|
||||
// Warns if code has an import or variable that is unused.
|
||||
"no-unused-variable": {"severity": "warning"},
|
||||
|
||||
// Prefer const for values that will not change. This better documents code.
|
||||
"prefer-const": {"severity": "warning"},
|
||||
|
||||
// Multi-line object liiterals and function calls should have a trailing comma. This helps avoid merge conflicts.
|
||||
"trailing-comma": {"severity": "warning"}
|
||||
},
|
||||
|
||||
"defaultSeverity": "error"
|
||||
}
|
Loading…
Reference in a new issue