From 39233389cba832219dd8affd83e24f586f407053 Mon Sep 17 00:00:00 2001 From: Scott Willeke Date: Tue, 8 Dec 2020 23:14:17 -0800 Subject: [PATCH] fix: vendor scripts included and no more console warnings --- .gitignore | 5 ++ README.md | 90 +++++++++++----------- src/react-app/package-lock.json | 26 ++++++- src/react-app/package.json | 15 +++- src/react-app/src/App.tsx | 2 +- src/react-app/src/components/layout.tsx | 13 ++-- src/react-app/src/components/nav.tsx | 6 +- src/react-app/src/components/policyNav.tsx | 4 +- src/react-app/src/lib/useApiHooks.ts | 5 +- src/react-app/src/pages/data.tsx | 6 +- 10 files changed, 108 insertions(+), 64 deletions(-) diff --git a/.gitignore b/.gitignore index c3f6f95..d141aed 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,8 @@ sam.yaml /public/ !/public/readme.md src/react-app/src/**/*.js +src/react-app/public/static/vendor/svg-injector/ +src/react-app/public/static/vendor/bootstrap/ +src/react-app/public/static/vendor/cookieconsent/ +src/react-app/public/static/vendor/jquery/ +src/react-app/public/static/vendor/popper.js/ diff --git a/README.md b/README.md index 9418ed7..659a578 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,10 @@ This project is intended to be a template for using [Architect](https://arc.codes/) on the server and React on the client for a web application. It uses TypeScript on both the server and the client. - ## Goals The goal is to make it quick and easy to start a new web application with the most basic functionality that any application needs set up and ready to go. - ## Stack **[Architect](https://arc.codes/)** provides lightweight infrastructure as code (IaC) deployment for an AWS-based backend. It provides support for TypeScript-based serverless functions on Lambda/APIG, DynamoDB, SQS, Static assets, and more. It's really a lightweight facade over cloudformation and provides [IaC extensibility via macros](https://arc.codes/primitives/macros). @@ -23,7 +21,6 @@ Architect also supports multiple environments and local development. **Hygene** Linting of all files is handled with a combo of eslint & prettier. See `lint*` scripts in `package.json`. - ## Getting Started To run the base stack as is, run the following commands: @@ -31,59 +28,60 @@ To run the base stack as is, run the following commands: npm run install-all npm start - ## Usage ### To add a new page -1. *Add it to `src/react-app/src/pages` as `mypage.tsx` -2. *Add a route for the page in `src/react-app/src/App.tsx` (this allows react-router to handle it) -3. *Add a serverless function for the route's path in `app.arc` that returns react-app's `index.html` OR copy `index.html` to that path in `src/react-app/public/...` so that index.html is always returned if someone navigates directly to the route's path on the server (see https://create-react-app.dev/docs/deployment#serving-apps-with-client-side-routing for details) +1. Add it to `src/react-app/src/pages` as `mypage.tsx` +2. Add a route for the page in `src/react-app/src/App.tsx` (this allows react-router to handle it) +3. Add a serverless function for the route's path in `app.arc` that returns react-app's `index.html` OR copy `index.html` to that path in `src/react-app/public/...` so that index.html is always returned if someone navigates directly to the route's path on the server (see https://create-react-app.dev/docs/deployment#serving-apps-with-client-side-routing for details) **NOTE**: We use the `spa` support in Architect to force all 404s to just return `index.html` which supports our react-client-app (where client routing shows the right thing based on the route). This has a couple side-effects: -1. You don't get clean 404 when it should be a 404. Instead the client routing just kind of poops a blank page out. -2. If we used static assets (just put a copy of index.html) then it would be possible to leverage cloudfront for much faster support of the non-404 files. See fingerprinting at https://arc.codes/reference/arc/static and then you could front-end it with cloudfront and more at https://docs.begin.com/en/static-assets/working-with-static-assets and https://arc.codes/primitives/cdn -For info on `spa` and how to turn off the "return index.html by default" behavior see https://arc.codes/reference/functions/http/node/proxy +1. You don't get clean 404 when it should be a 404. Instead the client routing just kind of poops a blank page out. +2. If we used static assets (just put a copy of index.html) then it would be possible to leverage cloudfront for much faster support of the non-404 files. See fingerprinting at https://arc.codes/reference/arc/static and then you could front-end it with cloudfront and more at https://docs.begin.com/en/static-assets/working-with-static-assets and https://arc.codes/primitives/cdn + For info on `spa` and how to turn off the "return index.html by default" behavior see https://arc.codes/reference/functions/http/node/proxy ## Roadmap -* [+] Bootstrap -* [+] Get two pages working and routing between them. -* [+] Layout: - * [+] Add components for Layout & Head (ala [next/head](https://nextjs.org/docs/api-reference/next/head)) to make it easy to have a common layout across all pages. - -* [+] Document the steps to add a new page. - -* [+] demo of a client-side fetching api data in the `/data` page -* [+] fix: footer policy link color -* [ ] fix: path for cookieconsent `/static/vendor/cookieconsent/cookieconsent.min.js` (is it deployed? Is SVGInjector deployed?) -* [ ] fix: no more console warnings -* [ ] chore: basic unit tests -* [ ] chore: git hooks for linting -* [ ] chore: git hooks for unit tests -* [ ] fix: hamburger menu dropdown in a responsive view for narrow mobile clients - -* Allow adding multiple OAuth Authorization servers to allow a user to authenticate: - * [ ] feat: configuration for client ID & secret - * [ ] feat: DDB tables to store user and table to store tokens by provider - * [ ] feat: user can use one or more OAuth providers - -* UserContext: - * [ ] feat: UserContext available as a react context so that client side app always has access to user/auth when authenticated (see alert genie, but no need for auth0) - * [ ] feat: when serving index.html always return a signed cookie that also has an accessToken claim in it (HOW??) - * See the session stuff [here](https://arc.codes/reference/functions/http/node/session) and [here](https://docs.begin.com/en/http-functions/sessions) (which one??) the `requireLogin` example at https://arc.codes/reference/functions/http/node/async - * The "Greedy Root" behavior means we can inject cookies: https://docs.begin.com/en/http-functions/provisioning#greedy-root. Should we? - * CSRF: See https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#xmlhttprequest-native-javascript to include it in the fetch client by default. See https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#hmac-based-token-pattern for HMAC-based CRSF. Needed on all "state changing requests". - * [ ] feat: all local API requests in `src/react-app/src/lib/useApiHooks.ts` use accessToken - * [ ] feat: login/logout pages - * [ ] feat: Avatar and login/logout/profile stuff in header +- [+] Bootstrap +- [+] Get two pages working and routing between them. +- [+] Layout: + - [+] Add components for Layout & Head (ala [next/head](https://nextjs.org/docs/api-reference/next/head)) to make it easy to have a common layout across all pages. + +- [+] Document the steps to add a new page. + +- [+] demo of a client-side fetching api data in the `/data` page +- [+] fix: footer policy link color +- [+] fix: path for cookieconsent `/static/vendor/cookieconsent/cookieconsent.min.js` (is it deployed? Is SVGInjector deployed?) +- [+] fix: no more console warnings +- [ ] chore: basic unit tests +- [ ] chore: git hooks for linting +- [ ] chore: git hooks for unit tests +- [ ] fix: hamburger menu dropdown in a responsive view for narrow mobile clients + +- Allow adding multiple OAuth Authorization servers to allow a user to authenticate: + + - [ ] feat: configuration for client ID & secret + - [ ] feat: DDB tables to store user and table to store tokens by provider + - [ ] feat: user can use one or more OAuth providers + +- UserContext: + - [ ] feat: UserContext available as a react context so that client side app always has access to user/auth when authenticated (see alert genie, but no need for auth0) + - [ ] feat: when serving index.html always return a signed cookie that also has an accessToken claim in it (HOW??) + - See the session stuff [here](https://arc.codes/reference/functions/http/node/session) and [here](https://docs.begin.com/en/http-functions/sessions) (which one??) the `requireLogin` example at https://arc.codes/reference/functions/http/node/async + - The "Greedy Root" behavior means we can inject cookies: https://docs.begin.com/en/http-functions/provisioning#greedy-root. Should we? + - CSRF: See https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#xmlhttprequest-native-javascript to include it in the fetch client by default. See https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#hmac-based-token-pattern for HMAC-based CRSF. Needed on all "state changing requests". + - [ ] feat: all local API requests in `src/react-app/src/lib/useApiHooks.ts` use accessToken + - [ ] feat: login/logout pages + - [ ] feat: Avatar and login/logout/profile stuff in header ### Future -* [ ] feat: HMR for react-app while using architect's sandbox (so API's still work) 🤔 -* [ ] chore: Integration tests for pages (see puppeteer, https://arc.codes/guides/testing) -* [ ] chore: Automated test to detect console warnings (puppeteer? part of unit test fixture?) -* [ ] chore: Integration tests for api (see https://arc.codes/guides/testing) -* [ ] feat: server-side rendering for react (like Next.js, see https://reacttraining.com/react-router/web/guides/server-rendering) -* [ ] \ No newline at end of file + +- [ ] feat: HMR for react-app while using architect's sandbox (so API's still work) 🤔 +- [ ] chore: Integration tests for pages (see puppeteer, https://arc.codes/guides/testing) +- [ ] chore: Automated test to detect console warnings (puppeteer? part of unit test fixture?) +- [ ] chore: Integration tests for api (see https://arc.codes/guides/testing) +- [ ] feat: server-side rendering for react (like Next.js, see https://reacttraining.com/react-router/web/guides/server-rendering) +- [ ] diff --git a/src/react-app/package-lock.json b/src/react-app/package-lock.json index 498456c..750814b 100644 --- a/src/react-app/package-lock.json +++ b/src/react-app/package-lock.json @@ -3889,6 +3889,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cookieconsent": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cookieconsent/-/cookieconsent-3.1.1.tgz", + "integrity": "sha512-v8JWLJcI7Zs9NWrs8hiVldVtm3EBF70TJI231vxn6YToBGj0c9dvdnYwltydkAnrbBMOM/qX1xLFrnTfm5wTag==" + }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", @@ -7816,10 +7821,15 @@ } } }, + "jquery": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", + "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" + }, "js-base64": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.2.tgz", - "integrity": "sha512-1hgLrLIrmCgZG+ID3VoLNLOSwjGnoZa8tyrUdEteMeIzsT6PH7PMLyUvbDwzNE56P3PNxyvuIOx4Uh2E5rzQIw==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" }, "js-tokens": { "version": "4.0.0", @@ -9687,6 +9697,11 @@ "ts-pnp": "^1.1.6" } }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, "portfinder": { "version": "1.0.26", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz", @@ -12781,6 +12796,11 @@ "has-flag": "^3.0.0" } }, + "svg-injector": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/svg-injector/-/svg-injector-1.1.3.tgz", + "integrity": "sha1-j7oY10GeX4GOcSxPgtg+41dhDmE=" + }, "svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", diff --git a/src/react-app/package.json b/src/react-app/package.json index 0122860..924fbdf 100644 --- a/src/react-app/package.json +++ b/src/react-app/package.json @@ -11,19 +11,32 @@ "@types/react-dom": "^16.9.8", "@types/react-helmet": "^6.0.0", "bootstrap": "^4.5.0", + "cookieconsent": "^3.1.1", "isomorphic-unfetch": "^3.0.0", + "jquery": "^3.5.1", "node-sass": "^4.14.1", + "popper.js": "^1.16.1", "react": "^16.13.1", "react-dom": "^16.13.1", "react-helmet": "^6.1.0", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", + "svg-injector": "^1.1.3", "typescript": "^3.7.5" }, "scripts": { "start": "react-scripts start", + "prebuild": "npm run -s copy-vendors", "build": "react-scripts build && mkdir -p ../../public ; cp -R ./build/* ../../public/", - "test": "react-scripts test" + "test": "react-scripts test", + "copy-vendors": "rm -rfd ./public/static/vendor && npm run -s copy-bootstrap && npm run -s copy-jquery && npm run -s copy-popper && npm run -s copy-svg-injector && npm run -s copy-cookieconsent && echo \"copy-vendors completed!\n\"", + "copy-bootstrap": "THEVENDOR=bootstrap npm run -s copy-vendor-dist", + "copy-jquery": "THEVENDOR=jquery npm run -s copy-vendor-dist", + "copy-popper": "THEVENDOR=popper.js npm run -s copy-vendor-dist", + "copy-svg-injector": "THEVENDOR=svg-injector npm run -s copy-vendor-dist", + "copy-cookieconsent": "THEVENDOR=cookieconsent npm run -s copy-vendor-build", + "copy-vendor-dist": "mkdir -p \"./public/static/vendor/$THEVENDOR\" && cp -fR ./node_modules/$THEVENDOR/dist/* \"./public/static/vendor/$THEVENDOR/\"", + "copy-vendor-build": "mkdir -p \"./public/static/vendor/$THEVENDOR\" && cp -fR ./node_modules/$THEVENDOR/build/* \"./public/static/vendor/$THEVENDOR/\"" }, "eslintConfig": { "extends": "react-app" diff --git a/src/react-app/src/App.tsx b/src/react-app/src/App.tsx index 5fc8c13..d208739 100644 --- a/src/react-app/src/App.tsx +++ b/src/react-app/src/App.tsx @@ -1,5 +1,5 @@ import React from "react" -import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom" +import { BrowserRouter as Router, Switch, Route } from "react-router-dom" import Home from "./pages/home" import About from "./pages/about" diff --git a/src/react-app/src/components/layout.tsx b/src/react-app/src/components/layout.tsx index 32667bb..6c4d8a7 100644 --- a/src/react-app/src/components/layout.tsx +++ b/src/react-app/src/components/layout.tsx @@ -33,19 +33,20 @@ const Layout = (props: Props): JSX.Element => { href="/static/images/iconic/font/css/open-iconic-bootstrap.min.css" rel="stylesheet" > + {/* Bootstrap requirements */} + + + + {/* for iconic svg icon support https://useiconic.com/open#reference */} + - {/* Bootstrap requirements */} - - - - {/* for iconic svg icon support https://useiconic.com/open#reference */} - {/* for iconic svg icon support https://useiconic.com/open#reference */}