From ab03cafab2c6e787a9886cd320742c5abe918d84 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Fri, 20 Dec 2019 11:01:21 -0800 Subject: [PATCH 01/14] WIP --- packages/web/next.config.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/web/next.config.js b/packages/web/next.config.js index 956774e6f8b..9da07e8887d 100644 --- a/packages/web/next.config.js +++ b/packages/web/next.config.js @@ -24,6 +24,21 @@ module.exports = withImages( } if (!isServer) { config.resolve.alias['@sentry/node'] = '@sentry/browser' + + const cacheGroups = config.optimization.splitChunks.cacheGroups + + // delete cacheGroups.react + cacheGroups.default = false + + cacheGroups.vendors = { + minChunks: 5, + // enforce: true, + name: 'vendors', + priority: 20, + test: /[\\/](node_modules|packages)[\\/]/, + } + + cacheGroups.commons = { name: 'commons', minChunks: 5, priority: 10 } } return config From 56fc62de684e71a7598103822f40612ba646384f Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Fri, 20 Dec 2019 16:51:31 -0800 Subject: [PATCH 02/14] Dynamically load carousel to reduce home page bundle Defer loading tracking --- packages/web/pages/_app.tsx | 8 +- packages/web/src/analytics/analytics.ts | 24 +- packages/web/src/header/CookieConsent.tsx | 8 +- packages/web/src/home/HomeCarousel.tsx | 37 +- packages/web/src/privacy/Privacy.tsx | 392 +++++++++++----------- 5 files changed, 256 insertions(+), 213 deletions(-) diff --git a/packages/web/pages/_app.tsx b/packages/web/pages/_app.tsx index 8cb39227ba7..7f204cddc8d 100644 --- a/packages/web/pages/_app.tsx +++ b/packages/web/pages/_app.tsx @@ -14,10 +14,7 @@ import { appWithTranslation } from '../src/i18n' config({ ssrReveal: true }) class MyApp extends App { - componentDidMount() { - if (canTrack()) { - initSentry() - } + async componentDidMount() { if (window.location.hash) { hashScroller(window.location.hash) } @@ -27,6 +24,9 @@ class MyApp extends App { if (getConfig().publicRuntimeConfig.FLAGS.ENV === 'development') { checkH1Count() } + if (await canTrack()) { + initSentry() + } } // there are a few pages we dont want the header on diff --git a/packages/web/src/analytics/analytics.ts b/packages/web/src/analytics/analytics.ts index e0d27e277ee..6f3b3306e05 100644 --- a/packages/web/src/analytics/analytics.ts +++ b/packages/web/src/analytics/analytics.ts @@ -1,6 +1,5 @@ import Cookies from 'js-cookie' import getConfig from 'next/config' -const isInEU = require('@segment/in-eu') let analytics: { track: (key: string, properties?: object, options?: object) => void @@ -10,17 +9,22 @@ const RESPONDED_TO_CONSENT = '__responded_to_consent__' declare var process: any -export function canTrack(): boolean { - return !!Cookies.get(ALLOW_ANALYTICS_COOKIE_NAME) || !isInEU() +export async function canTrack() { + return !!Cookies.get(ALLOW_ANALYTICS_COOKIE_NAME) || !(await isInEU()) } -export function showVisitorCookieConsent(): boolean { - return isInEU() && !Cookies.get(RESPONDED_TO_CONSENT) +export async function showVisitorCookieConsent() { + const euro = await isInEU() + return euro && !Cookies.get(RESPONDED_TO_CONSENT) } -const initializeAnalytics = () => { - if (process.browser && canTrack()) { - const Segment = require('load-segment') +async function isInEU() { + const inEU = await import('@segment/in-eu').then((mod) => mod.default) + return inEU() +} +async function initializeAnalytics() { + if (process.browser && (await canTrack())) { + const Segment = await import('load-segment').then((mod) => mod.default) const { publicRuntimeConfig } = getConfig() analytics = Segment({ key: publicRuntimeConfig.__SEGMENT_KEY__ }) } else { @@ -32,10 +36,10 @@ const initializeAnalytics = () => { initializeAnalytics() -export const agree = () => { +export async function agree() { Cookies.set(ALLOW_ANALYTICS_COOKIE_NAME, true, { expires: OPTIN_EXPIRE_DAYS }) Cookies.set(RESPONDED_TO_CONSENT, true, { expires: OPTIN_EXPIRE_DAYS }) - initializeAnalytics() + await initializeAnalytics() } export const disagree = () => { diff --git a/packages/web/src/header/CookieConsent.tsx b/packages/web/src/header/CookieConsent.tsx index e9f1163693e..b8f19222789 100644 --- a/packages/web/src/header/CookieConsent.tsx +++ b/packages/web/src/header/CookieConsent.tsx @@ -17,14 +17,14 @@ export class CookieConsent extends React.PureComponent { showConsent: false, } - componentDidMount() { + async componentDidMount() { this.setState({ - showConsent: showVisitorCookieConsent(), + showConsent: await showVisitorCookieConsent(), }) } - onAgree = () => { - agree() + onAgree = async () => { + await agree() this.setState({ showConsent: false, }) diff --git a/packages/web/src/home/HomeCarousel.tsx b/packages/web/src/home/HomeCarousel.tsx index 017ab65b279..4a7f5bd0055 100644 --- a/packages/web/src/home/HomeCarousel.tsx +++ b/packages/web/src/home/HomeCarousel.tsx @@ -1,19 +1,40 @@ -import Carousel from 'nuka-carousel' +import Dynamic from 'next/dynamic' import * as React from 'react' import FadeIn from 'react-lazyload-fadein' import { Dimensions, Image, StyleSheet, Text, View } from 'react-native' import Fade from 'react-reveal/Fade' -import CarouselDot from 'src/home/carousel/CarouselDot' import Responsive from 'src/shared/Responsive' +import Spinner from 'src/shared/Spinner' import { DESKTOP_BREAKPOINT, TABLET_BREAKPOINT } from 'src/shared/Styles' -import { fonts, textStyles } from 'src/styles' +import { colors, fonts, standardStyles, textStyles } from 'src/styles' + +const Carousel = Dynamic(import('nuka-carousel'), { + loading: () => ( + + + + ), + ssr: false, +}) + +const CarouselDot = Dynamic(import('src/home/carousel/CarouselDot'), { + ssr: false, +}) const Cell = ({ image: { image, width, height, caption }, imageWidth }) => { const imageHeight = (height * imageWidth) / width return ( - + + + + } + > {(onload) => ( { ) } +const placeholder = { + height: 300, + width: 450, + image: '', + caption: '', +} + const images = [ { height: 300, @@ -194,6 +222,7 @@ const CONTAINER_PADDING_TOP = 0 const CONTAINER_PADDING_BOTTOM = 0 const styles = StyleSheet.create({ + placeholder: { height: '100%', flex: 1 }, container: { flex: 1, paddingTop: CONTAINER_PADDING_TOP, diff --git a/packages/web/src/privacy/Privacy.tsx b/packages/web/src/privacy/Privacy.tsx index e8cc163adc7..f093b78ef8c 100644 --- a/packages/web/src/privacy/Privacy.tsx +++ b/packages/web/src/privacy/Privacy.tsx @@ -1,185 +1,185 @@ -import * as React from 'react'; -import { StyleSheet, Text, View } from 'react-native'; -import { H1, Li, TABLE, TD, TH, TR, Ul } from 'src/fonts/Fonts'; -import OpenGraph from 'src/header/OpenGraph'; -import { Cell, GridRow, Spans } from 'src/layout/GridRow'; -import SideTitledSection from 'src/layout/SideTitledSection'; -import Link from 'src/shared/Link'; -import { fonts, standardStyles, textStyles } from 'src/styles'; +import * as React from 'react' +import { StyleSheet, Text, View } from 'react-native' +import { H1, Li, TABLE, TD, TH, TR, Ul } from 'src/fonts/Fonts' +import OpenGraph from 'src/header/OpenGraph' +import { Cell, GridRow, Spans } from 'src/layout/GridRow' +import SideTitledSection from 'src/layout/SideTitledSection' +import Link from 'src/shared/Link' +import { fonts, standardStyles, textStyles } from 'src/styles' export default class Privacy extends React.Component { - static getInitialProps() { - return { namespacesRequired: ['common'] } - } render() { return ( - + - {} - + allStyle={standardStyles.centered} + desktopStyle={standardStyles.blockMarginBottom} + tabletStyle={standardStyles.blockMarginBottomTablet} + mobileStyle={standardStyles.blockMarginBottomMobile} + > + {} +

Privacy Policy

-
-
+ + Valid as of Jan 7, 2019

- - This Privacy Policy and Cookies Statement describes how A Protocol Inc. and its - affiliated companies (referred to in this document as “Celo,” “we,” “us” or “our”) - collects, uses, shares and otherwise processes Personal Data (defined below) - including: -

-
    -
  • - Visitors to our website(s), mobile applications and other online properties - (“Site” or “Sites”) -
  • -
  • Any other individual about whom Celo may obtain Personal Data
  • -
-

- In this Privacy Policy, “Personal Data” means information that (either in - isolation or in combination with other information held by Celo) enables you to be - identified as an individual or recognized directly or indirectly. We may collect - Personal Data when you use our Sites. + This Privacy Policy and Cookies Statement describes how A Protocol Inc. and its + affiliated companies (referred to in this document as “Celo,” “we,” “us” or “our”) + collects, uses, shares and otherwise processes Personal Data (defined below) + including:

-
-
- -

Unless we specifically state otherwise, Celo is the data processor of the Personal - Data we process, and is therefore responsible for ensuring that the systems and - processes we use are compliant with data protection laws, to the extent applicable - to us. +

    +
  • + Visitors to our website(s), mobile applications and other online properties (“Site” + or “Sites”) +
  • +
  • Any other individual about whom Celo may obtain Personal Data
  • +
+

+ In this Privacy Policy, “Personal Data” means information that (either in isolation or + in combination with other information held by Celo) enables you to be identified as an + individual or recognized directly or indirectly. We may collect Personal Data when you + use our Sites.

+ + + +

+ Unless we specifically state otherwise, Celo is the data processor of the Personal Data + we process, and is therefore responsible for ensuring that the systems and processes we + use are compliant with data protection laws, to the extent applicable to us. +

- Celo personnel are required to comply with this Privacy Policy and complete data - protection training, where appropriate.

+ Celo personnel are required to comply with this Privacy Policy and complete data + protection training, where appropriate. +

- +

- Celo collects information that you provide directly to us when you browse our - Site, register to receive newsletter requests or other information, provide - feedback through surveys, participate in any interactive features on our Sites - including contests, promotions, challenges, activities or events. -

+ Celo collects information that you provide directly to us when you browse our Site, + register to receive newsletter requests or other information, provide feedback through + surveys, participate in any interactive features on our Sites including contests, + promotions, challenges, activities or events. +

- We also collect data provided by job applicants or others on our Sites or offline - means in connection with employment or consulting opportunities, which may also be - subject to other Policies. -

+ We also collect data provided by job applicants or others on our Sites or offline means + in connection with employment or consulting opportunities, which may also be subject to + other Policies. +

- We may also collect Computer Internet Protocol (IP) address, unique device - identifier (“UDID”), cookies, web beacons, web server logs and other technologies - and other data linked to a device, and data about usage of our Sites (Usage Data). - A “cookie” is a text file that websites send to a visitor’s computer or other - Internet-connected device to identify the visitor’s browser or to store - information or settings in the browser. A “web beacon,” also known as an Internet - tag, pixel tag or clear GIF, links web pages to web servers and their cookies and - may be used to transmit information collected through cookies back to a web - server. -

+ We may also collect Computer Internet Protocol (IP) address, unique device identifier + (“UDID”), cookies, web beacons, web server logs and other technologies and other data + linked to a device, and data about usage of our Sites (Usage Data). A “cookie” is a text + file that websites send to a visitor’s computer or other Internet-connected device to + identify the visitor’s browser or to store information or settings in the browser. A + “web beacon,” also known as an Internet tag, pixel tag or clear GIF, links web pages to + web servers and their cookies and may be used to transmit information collected through + cookies back to a web server. +

- Other types of information we may collect include your name, email address, - username, password, phone number, location and any other information you choose to - provide. -

+ Other types of information we may collect include your name, email address, username, + password, phone number, location and any other information you choose to provide. +

- We may use these automated technologies to collect information about your - equipment, browsing actions, and usage patterns. The information we obtain in this - manner may include your device IP address, identifiers associated with your - devices, types of devices connected to our services, web browser characteristics, - device characteristics, language preferences, referring/exit pages, clickstream - data, and dates and times of visits to our Site. -

+ We may use these automated technologies to collect information about your equipment, + browsing actions, and usage patterns. The information we obtain in this manner may + include your device IP address, identifiers associated with your devices, types of + devices connected to our services, web browser characteristics, device characteristics, + language preferences, referring/exit pages, clickstream data, and dates and times of + visits to our Site. +

We use the Personal Data that we collect:

  • - To make our Sites more intuitive and easier to use we use device data, - cookies and other information that you may provide. This data is necessary for - our legitimate interests in monitoring how our Sites are used to help us improve - these Sites, and the information and tools available on these Sites. -
  • + To make our Sites more intuitive and easier to use we use device data, cookies + and other information that you may provide. This data is necessary for our legitimate + interests in monitoring how our Sites are used to help us improve these Sites, and the + information and tools available on these Sites. +
  • - To provide relevant marketing including providing you with information - about events or services that may be of interest to you. It is necessary for our - legitimate interests to process this information in order to provide you with - tailored and relevant marketing, updates and invitations. -
  • + To provide relevant marketing including providing you with information about + events or services that may be of interest to you. It is necessary for our legitimate + interests to process this information in order to provide you with tailored and + relevant marketing, updates and invitations. +
  • To {' '} consider individuals for employment and contractor opportunities and manage - on-boarding processes{' '} + on-boarding processes{' '} - we use job applicant data. The processing is necessary for the purposes of - recruitment and on-boarding. -
  • + we use job applicant data. The processing is necessary for the purposes of recruitment + and on-boarding. +
  • To carry out any other purpose for which the information was collected.

- We may also use automated technologies to collect information about your - equipment, browsing actions, and usage patterns. The information we obtain in this - manner may include your device IP address, identifiers associated with your - devices, types of devices connected to our services, web browser characteristics, - device characteristics, language preferences, referring/exit pages, clickstream - data, and dates and times of visits to our Site. -

+ We may also use automated technologies to collect information about your equipment, + browsing actions, and usage patterns. The information we obtain in this manner may + include your device IP address, identifiers associated with your devices, types of + devices connected to our services, web browser characteristics, device characteristics, + language preferences, referring/exit pages, clickstream data, and dates and times of + visits to our Site. +

The information we collect through cookies and similar technologies helps Celo (1) - remember your information so you will not have to re-enter it; (2) understand how - you use and interact with our website; (3) measure the usability of our website - and the effectiveness of our communications; and (4) otherwise manage and enhance - our website, and help ensure it is working properly. Your browser may tell you how - to be notified when you receive certain types of cookies or how to restrict or - disable certain types of cookies. Please note, however, that without cookies you - may not be able to use all of the features of our website. -

+ remember your information so you will not have to re-enter it; (2) understand how you + use and interact with our website; (3) measure the usability of our website and the + effectiveness of our communications; and (4) otherwise manage and enhance our website, + and help ensure it is working properly. Your browser may tell you how to be notified + when you receive certain types of cookies or how to restrict or disable certain types of + cookies. Please note, however, that without cookies you may not be able to use all of + the features of our website. +

-

You have control regarding our use of Personal Data for direct marketing. In - certain markets, you will need to expressly consent before receiving marketing. In - all markets, you can choose to not receive marketing communications at any time. - If you no longer wish to receive marketing communications from Celo, or remain on - a mailing list to which you previously subscribed, or receive any other marketing - communication, please follow the unsubscribe link in the relevant communications - or contact us as specified below.

+

+ You have control regarding our use of Personal Data for direct marketing. In certain + markets, you will need to expressly consent before receiving marketing. In all markets, + you can choose to not receive marketing communications at any time. If you no longer + wish to receive marketing communications from Celo, or remain on a mailing list to which + you previously subscribed, or receive any other marketing communication, please follow + the unsubscribe link in the relevant communications or contact us as specified below. +

  • With vendors, consultants and other service providers who need access to such information to carry out work on our behalf; -
  • +
  • - In response to a request for information if we believe disclosure is in - accordance with any applicable law, regulation or legal process, or as otherwise - required by any applicable law, rule or regulation; -
  • + In response to a request for information if we believe disclosure is in accordance + with any applicable law, regulation or legal process, or as otherwise required by any + applicable law, rule or regulation; +
  • - If we believe your actions are inconsistent with our user agreements or - policies, or to protect the rights, property and safety of us or any - third-party; -
  • + If we believe your actions are inconsistent with our user agreements or policies, or + to protect the rights, property and safety of us or any third-party; +
  • - In connection with, or during negotiations of, any merger, sale of company - assets, financing or acquisition of all or a portion of our business to another - company; -
  • + In connection with, or during negotiations of, any merger, sale of company assets, + financing or acquisition of all or a portion of our business to another company; +
  • With your consent or at your direction; and
  • - We may also share aggregated or de-identified information, which cannot - reasonably be used to identify you. -
  • + We may also share aggregated or de-identified information, which cannot reasonably be + used to identify you. +
@@ -219,90 +219,100 @@ export default class Privacy extends React.Component {

- If you are an individual from the European Economic Area (“EEA”), we collect and - process your Personal Data only where we have legal basis for doing so under - applicable EU laws. The legal basis depends on the Services you use and how you - use them. This means we collect and use your personal data only: -

+ If you are an individual from the European Economic Area (“EEA”), we collect and process + your Personal Data only where we have legal basis for doing so under applicable EU laws. + The legal basis depends on the Services you use and how you use them. This means we + collect and use your personal data only: +

  • - To operate our business, including to improve and develop our services, for - fraud prevention purposes, improve user experience, or other legitimate - interest; -
  • + To operate our business, including to improve and develop our services, for fraud + prevention purposes, improve user experience, or other legitimate interest; +
  • To fulfill contractual responsibilities; and/or
  • As otherwise in compliance with law.

- If you have any questions about the legal basis for processing, please contact us - at the address listed in the “Contact Us” section. -

-
- -

We may transfer your Personal Data to countries outside the United Kingdom and the - European Economic Area (“EEA”), including, but not limited to the United States, - where Celo’s headquarters and some of its IT systems (including email) are - located.

+ If you have any questions about the legal basis for processing, please contact us at the + address listed in the “Contact Us” section. +

+
+ +

+ We may transfer your Personal Data to countries outside the United Kingdom and the + European Economic Area (“EEA”), including, but not limited to the United States, where + Celo’s headquarters and some of its IT systems (including email) are located. +

-

Protecting your information is important to us. We maintain administrative, - technical and physical safeguards designed to protect against accidental, unlawful - or unauthorized destruction, loss, alteration, access, disclosure or use of - Personal Data.

+

+ Protecting your information is important to us. We maintain administrative, technical + and physical safeguards designed to protect against accidental, unlawful or unauthorized + destruction, loss, alteration, access, disclosure or use of Personal Data. +

-

We strive to only keep your Personal Data only for the period of time needed for - legitimate business purposes. In certain circumstances, however, legal or - regulatory obligations may require us to retain records for a longer than we - otherwise would.

+

+ We strive to only keep your Personal Data only for the period of time needed for + legitimate business purposes. In certain circumstances, however, legal or regulatory + obligations may require us to retain records for a longer than we otherwise would. +

-

Our Services are not directed to children under the age of 16. If you learn that a - child under the age of 16 has provided us with personal information without - consent, please contact us. +

+ Our Services are not directed to children under the age of 16. If you learn that a child + under the age of 16 has provided us with personal information without consent, please + contact us.

- If you are in the EEA you have have the right, subject to certain exceptions, to - request a copy of the Personal Data we are processing about you, to require that - any incomplete or inaccurate Personal Data is amended, to request that we delete - your Personal Data (although we may not be able to delete certain data due to - legal or other obligations), to object to the use of your Personal Data or to - withdraw consent. -

+ If you are in the EEA you have have the right, subject to certain exceptions, to request + a copy of the Personal Data we are processing about you, to require that any incomplete + or inaccurate Personal Data is amended, to request that we delete your Personal Data + (although we may not be able to delete certain data due to legal or other obligations), + to object to the use of your Personal Data or to withdraw consent. +

- If you are in the EEA, you also have a right to lodge a complaint with the local - data protection authority if you believe that we have not complied with the - applicable data protection laws. -

+ If you are in the EEA, you also have a right to lodge a complaint with the local data + protection authority if you believe that we have not complied with the applicable data + protection laws. +

- You may also contact us to address and resolve concerns you may have about our use - of your Personal Data. Please contact us at{' '} + You may also contact us to address and resolve concerns you may have about our use of + your Personal Data. Please contact us at{' '} privacy@celo.org. -

+

-

We reserve the right to change and update this Privacy Policy from time to time. - If we make changes, you will be notified of the change by the date at the top of - Privacy Policy, which will reflect the last date updated.

+

+ We reserve the right to change and update this Privacy Policy from time to time. If we + make changes, you will be notified of the change by the date at the top of Privacy + Policy, which will reflect the last date updated. +

+
+ +

+ Certain third-party services, websites, or applications you use, or navigate to from our + Services may have separate user terms and privacy policies that are independent of this + Policy. This includes, for example, websites owned and operated by our customers or + partners. We are not responsible for the privacy practices of these third-party services + or applications. We recommend carefully reviewing the user terms and privacy statement + of each third-party service, website, and/or application prior to use. +

- -

Certain third-party services, websites, or applications you use, or navigate to - from our Services may have separate user terms and privacy policies that are - independent of this Policy. This includes, for example, websites owned and - operated by our customers or partners. We are not responsible for the privacy - practices of these third-party services or applications. We recommend carefully - reviewing the user terms and privacy statement of each third-party service, - website, and/or application prior to use.

-
) } } - -function P({children}: {children: React.ReactNode}) { +function P({ children }: { children: React.ReactNode }) { return {children} } @@ -312,9 +322,9 @@ function B({ children }: { children: React.ReactNode }) { const styles = StyleSheet.create({ container: { - marginTop: 100 + marginTop: 100, }, paragraph: { - marginBottom: 24 - } + marginBottom: 24, + }, }) From 57896679d7ab3a64ed703f445ec95028a7d38a1b Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Fri, 20 Dec 2019 18:25:33 -0800 Subject: [PATCH 03/14] Deffer loading sentry --- packages/web/fullstack/sentry.ts | 13 +- packages/web/next.config.js | 19 +-- packages/web/package.json | 3 +- packages/web/pages/_app.tsx | 9 +- packages/web/pages/_document.tsx | 3 +- packages/web/server/Announcement.ts | 2 +- packages/web/server/EventHelpers.ts | 2 +- packages/web/server/FirebaseServerSide.ts | 2 +- packages/web/server/addToCRM.ts | 2 +- packages/web/server/index.ts | 4 +- packages/web/server/mediumAPI.ts | 2 +- packages/web/server/sentry.ts | 15 +++ packages/web/src/header/BlueBanner.tsx | 3 +- packages/web/src/header/CookieConsent.tsx | 4 +- packages/web/src/utils/sentry.ts | 23 ++++ yarn.lock | 137 ++++++++++++++++++++-- 16 files changed, 202 insertions(+), 41 deletions(-) create mode 100644 packages/web/server/sentry.ts create mode 100644 packages/web/src/utils/sentry.ts diff --git a/packages/web/fullstack/sentry.ts b/packages/web/fullstack/sentry.ts index 35fa30eb7a7..3525ca8604f 100644 --- a/packages/web/fullstack/sentry.ts +++ b/packages/web/fullstack/sentry.ts @@ -1,18 +1,13 @@ -import * as Sentry from '@sentry/node' import getConfig from 'next/config' -export function initSentry() { + +export default function sentryConfig() { const { publicRuntimeConfig } = getConfig() const config = publicRuntimeConfig.SENTRY - if (publicRuntimeConfig.ENV === 'development') { - return - } - Sentry.init({ + return { dsn: `https://${config.KEY}@sentry.io/${config.PROJECT}`, environment: publicRuntimeConfig.ENV, ignoreErrors: [ "The fetching process for the media resource was aborted by the user agent at the user's request.", ], - }) + } } - -export default Sentry diff --git a/packages/web/next.config.js b/packages/web/next.config.js index 9da07e8887d..8fbb7500443 100644 --- a/packages/web/next.config.js +++ b/packages/web/next.config.js @@ -1,8 +1,8 @@ const withSass = require('@zeit/next-sass') const withImages = require('next-images') -const webpack = require('webpack') const envConfig = require('./env-config') const serverEnvConfig = require('./server-env-config') +const Visualizer = require('webpack-visualizer-plugin') module.exports = withImages( withSass({ @@ -22,23 +22,26 @@ module.exports = withImages( ...config.resolve.alias, 'react-native$': 'react-native-web', } + + config.plugins = config.plugins || [] + config.plugins.push(new Visualizer()) + if (!isServer) { config.resolve.alias['@sentry/node'] = '@sentry/browser' const cacheGroups = config.optimization.splitChunks.cacheGroups - // delete cacheGroups.react - cacheGroups.default = false + delete cacheGroups.react cacheGroups.vendors = { - minChunks: 5, - // enforce: true, + enforce: true, + minChunks: 8, name: 'vendors', - priority: 20, - test: /[\\/](node_modules|packages)[\\/]/, + priority: 5, + test: /[\\/](node_modules)[\\/]/, } - cacheGroups.commons = { name: 'commons', minChunks: 5, priority: 10 } + cacheGroups.commons = { name: 'commons', minChunks: 12, priority: 10 } } return config diff --git a/packages/web/package.json b/packages/web/package.json index f19dbf56447..86fb7ad9e4c 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -99,6 +99,7 @@ "nodemon": "^2.0.2", "postcss-scss": "^2.0.0", "react-native-svg": "^9.13.6", - "webpack": "4.41.2" + "webpack": "4.41.2", + "webpack-visualizer-plugin": "^0.1.11" } } diff --git a/packages/web/pages/_app.tsx b/packages/web/pages/_app.tsx index 7f204cddc8d..8a04fe7d3ab 100644 --- a/packages/web/pages/_app.tsx +++ b/packages/web/pages/_app.tsx @@ -9,7 +9,7 @@ import Header from 'src/header/Header.3' import { ScreenSizeProvider } from 'src/layout/ScreenSize' import Footer from 'src/shared/Footer.3' import { HEADER_HEIGHT } from 'src/shared/Styles' -import Sentry, { initSentry } from '../fullstack/sentry' +import { getSentry, initSentry } from 'src/utils/sentry' import { appWithTranslation } from '../src/i18n' config({ ssrReveal: true }) @@ -25,7 +25,7 @@ class MyApp extends App { checkH1Count() } if (await canTrack()) { - initSentry() + await initSentry() } } @@ -39,8 +39,9 @@ class MyApp extends App { return this.props.router.asPath.startsWith('/experience') } - componentDidCatch = (error: Error, info: object) => { - Sentry.withScope((scope: Sentry.Scope) => { + componentDidCatch = async (error: Error, info: object) => { + const Sentry = await getSentry() + Sentry.withScope((scope) => { scope.setExtras(info) Sentry.captureException(error) }) diff --git a/packages/web/pages/_document.tsx b/packages/web/pages/_document.tsx index cf66e94ea3b..a399b6d1e69 100644 --- a/packages/web/pages/_document.tsx +++ b/packages/web/pages/_document.tsx @@ -3,7 +3,7 @@ import * as React from 'react' import { AppRegistry, I18nManager } from 'react-native-web' import analytics from 'src/analytics/analytics' import { setDimensionsForScreen } from 'src/layout/ScreenSize' -import Sentry from '../fullstack/sentry' +import { getSentry } from 'src/utils/sentry' import { isLocaleRTL } from '../server/i18nSetup' // @ts-ignore const a = analytics @@ -40,6 +40,7 @@ export default class MyDocument extends Document { ]) if (context.err) { + const Sentry = await getSentry() Sentry.captureException(context.err) } diff --git a/packages/web/server/Announcement.ts b/packages/web/server/Announcement.ts index 1001fbe06cf..44d0e862ee7 100644 --- a/packages/web/server/Announcement.ts +++ b/packages/web/server/Announcement.ts @@ -1,5 +1,5 @@ import getConfig from 'next/config' -import Sentry from '../fullstack/sentry' +import Sentry from '../server/sentry' import airtableInit from '../server/airtable' interface Fields { diff --git a/packages/web/server/EventHelpers.ts b/packages/web/server/EventHelpers.ts index 40d43d5a5ff..35df4af2ac8 100644 --- a/packages/web/server/EventHelpers.ts +++ b/packages/web/server/EventHelpers.ts @@ -1,7 +1,7 @@ import getConfig from 'next/config' import { EventProps } from '../fullstack/EventProps' -import Sentry from '../fullstack/sentry' import airtableInit from '../server/airtable' +import Sentry from '../server/sentry' import { abort } from '../src/utils/abortableFetch' const TABLE_NAME = 'Community Calendar' // Intermediate step Event With all String Values diff --git a/packages/web/server/FirebaseServerSide.ts b/packages/web/server/FirebaseServerSide.ts index 7addf789849..4259b1bffde 100644 --- a/packages/web/server/FirebaseServerSide.ts +++ b/packages/web/server/FirebaseServerSide.ts @@ -2,7 +2,7 @@ import * as firebase from 'firebase/app' import 'firebase/auth' import 'firebase/database' import getConfig from 'next/config' -import Sentry from '../fullstack/sentry' +import Sentry from '../server/sentry' import { Address, E164Number, diff --git a/packages/web/server/addToCRM.ts b/packages/web/server/addToCRM.ts index 9ec98938bf0..04b26ad328a 100644 --- a/packages/web/server/addToCRM.ts +++ b/packages/web/server/addToCRM.ts @@ -1,6 +1,6 @@ import fetch from 'cross-fetch' import getConfig from 'next/config' -import Sentry from '../fullstack/sentry' +import Sentry from '../server/sentry' interface ActiveCampaignNewContact { email: string firstName: string diff --git a/packages/web/server/index.ts b/packages/web/server/index.ts index 91f3e3c04da..cccb521db33 100644 --- a/packages/web/server/index.ts +++ b/packages/web/server/index.ts @@ -7,7 +7,7 @@ import helmet from 'helmet' import next from 'next' import nextI18NextMiddleware from 'next-i18next/middleware' import { Tables } from '../fullstack/EcoFundFields' -import Sentry, { initSentry } from '../fullstack/sentry' +import Sentry, { initSentryServer } from '../server/sentry' import addToCRM from '../server/addToCRM' import ecoFundSubmission from '../server/EcoFundApp' import { RequestType } from '../src/fauceting/FaucetInterfaces' @@ -194,7 +194,7 @@ function wwwRedirect(req, res, nextAction) { return handle(req, res) }) - initSentry() + await initSentryServer() await server.listen(port) // tslint:disable-next-line diff --git a/packages/web/server/mediumAPI.ts b/packages/web/server/mediumAPI.ts index 70464e26eaf..b358f1a6608 100644 --- a/packages/web/server/mediumAPI.ts +++ b/packages/web/server/mediumAPI.ts @@ -1,7 +1,7 @@ import { parse, validate } from 'fast-xml-parser' import { Articles } from 'fullstack/ArticleProps' import * as htmlToFormattedText from 'html-to-formatted-text' -import Sentry from '../fullstack/sentry' +import Sentry from '../server/sentry' import abortableFetch from '../src/utils/abortableFetch' interface JSONRSS { rss: { diff --git a/packages/web/server/sentry.ts b/packages/web/server/sentry.ts new file mode 100644 index 00000000000..c8575e3403a --- /dev/null +++ b/packages/web/server/sentry.ts @@ -0,0 +1,15 @@ +import * as Sentry from '@sentry/node' +import getConfig from 'next/config' +import sentryConfig from '../fullstack/sentry' + +export async function initSentryServer() { + const { publicRuntimeConfig } = getConfig() + if (publicRuntimeConfig.ENV === 'development') { + return + } + Sentry.init(sentryConfig()) + + return Sentry +} + +export default Sentry diff --git a/packages/web/src/header/BlueBanner.tsx b/packages/web/src/header/BlueBanner.tsx index 13add735cfa..a88c6281985 100644 --- a/packages/web/src/header/BlueBanner.tsx +++ b/packages/web/src/header/BlueBanner.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { StyleSheet, Text, View } from 'react-native' import Chevron from 'src/icons/chevron' import { colors, fonts, textStyles } from 'src/styles' -import Sentry from '../../fullstack/sentry' +import { getSentry } from 'src/utils/sentry' interface Props { link: string @@ -111,6 +111,7 @@ export default class Announcement extends React.Component { this.setState({ showConsent: false, }) - initSentry() + await initSentry() } onDisagree = () => { diff --git a/packages/web/src/utils/sentry.ts b/packages/web/src/utils/sentry.ts new file mode 100644 index 00000000000..f82052d47ec --- /dev/null +++ b/packages/web/src/utils/sentry.ts @@ -0,0 +1,23 @@ +import getConfig from 'next/config' +import sentryConfig from '../../fullstack/sentry' +let hasInitialized = false + +let Sentry + +export async function initSentry() { + const { publicRuntimeConfig } = getConfig() + if (publicRuntimeConfig.ENV === 'development') { + return + } + + if (!hasInitialized) { + const sentry = await getSentry() + sentry.init(sentryConfig()) + hasInitialized = true + } +} + +export async function getSentry() { + Sentry = Sentry || (await import('@sentry/browser')) + return Sentry +} diff --git a/yarn.lock b/yarn.lock index 30c89cb1f2a..c81790fe012 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6691,7 +6691,7 @@ acorn-jsx@^5.0.0: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== -"acorn@>= 2.5.2 <= 5.7.3": +"acorn@>= 2.5.2 <= 5.7.3", acorn@^5.2.1: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== @@ -7833,6 +7833,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-types@0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk= + ast-types@0.x.x: version "0.12.2" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.12.2.tgz#341656049ee328ac03fc805c156b49ebab1e4462" @@ -9014,6 +9019,11 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" +base62@^1.1.0: + version "1.2.8" + resolved "https://registry.yarnpkg.com/base62/-/base62-1.2.8.tgz#1264cb0fb848d875792877479dbe8bae6bae3428" + integrity sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA== + base64-js@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" @@ -11032,6 +11042,11 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== +commander@^2.5.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -11064,6 +11079,21 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +commoner@^0.10.1: + version "0.10.8" + resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + integrity sha1-NPw2cs0kOT6LtH5wyqApOBH08sU= + dependencies: + commander "^2.5.0" + detective "^4.3.1" + glob "^5.0.15" + graceful-fs "^4.1.2" + iconv-lite "^0.4.5" + mkdirp "^0.5.0" + private "^0.1.6" + q "^1.1.2" + recast "^0.11.17" + compare-func@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648" @@ -12058,6 +12088,11 @@ d3-timer@^1.0.9: resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.9.tgz#f7bb8c0d597d792ff7131e1c24a36dd471a471ba" integrity sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg== +d3@^3.5.6: + version "3.5.17" + resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8" + integrity sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g= + d64@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/d64/-/d64-1.0.0.tgz#4002a87e850cbfc9f9d9706b60fca613a3336e90" @@ -12443,7 +12478,7 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -defined@~1.0.0: +defined@^1.0.0, defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= @@ -12593,6 +12628,14 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== +detective@^4.3.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" + integrity sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig== + dependencies: + acorn "^5.2.1" + defined "^1.0.0" + detox@^14.5.0: version "14.5.0" resolved "https://registry.yarnpkg.com/detox/-/detox-14.5.0.tgz#cc96b41a2b76a029ef26be861fb04f69fe70c965" @@ -13249,6 +13292,14 @@ env-variable@0.0.x: resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== +envify@^3.0.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/envify/-/envify-3.4.1.tgz#d7122329e8df1688ba771b12501917c9ce5cbce8" + integrity sha1-1xIjKejfFoi6dxsSUBkXyc5cvOg= + dependencies: + jstransform "^11.0.3" + through "~2.3.4" + envinfo@^7.1.0: version "7.4.0" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.4.0.tgz#bef4ece9e717423aaf0c3584651430b735ad6630" @@ -13726,12 +13777,17 @@ esprima-extract-comments@^1.1.0: dependencies: esprima "^4.0.0" +esprima-fb@^15001.1.0-dev-harmony-fb: + version "15001.1.0-dev-harmony-fb" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz#30a947303c6b8d5e955bee2b99b1d233206a6901" + integrity sha1-MKlHMDxrjV6VW+4rmbHSMyBqaQE= + esprima@2.7.x, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= -esprima@3.x.x, esprima@^3.1.3: +esprima@3.x.x, esprima@^3.1.3, esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= @@ -15091,6 +15147,17 @@ fbjs-scripts@^1.1.0: semver "^5.1.0" through2 "^2.0.0" +fbjs@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.6.1.tgz#9636b7705f5ba9684d44b72f78321254afc860f7" + integrity sha1-lja3cF9bqWhNRLcveDISVK/IYPc= + dependencies: + core-js "^1.0.0" + loose-envify "^1.0.0" + promise "^7.0.3" + ua-parser-js "^0.7.9" + whatwg-fetch "^0.9.0" + fbjs@^0.8.0, fbjs@^0.8.9: version "0.8.16" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" @@ -18436,7 +18503,7 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -20588,6 +20655,17 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jstransform@^11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/jstransform/-/jstransform-11.0.3.tgz#09a78993e0ae4d4ef4487f6155a91f6190cb4223" + integrity sha1-CaeJk+CuTU70SH9hVakfYZDLQiM= + dependencies: + base62 "^1.1.0" + commoner "^0.10.1" + esprima-fb "^15001.1.0-dev-harmony-fb" + object-assign "^2.0.0" + source-map "^0.4.2" + jstz@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/jstz/-/jstz-2.1.1.tgz#fff3373a518fa7cce69299930466f5a2b980389d" @@ -24606,6 +24684,11 @@ object-assign@4.1.1, object-assign@^4, object-assign@^4.0.0, object-assign@^4.0. resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +object-assign@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" + integrity sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo= + object-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" @@ -26688,7 +26771,7 @@ prismjs@^1.15.0: optionalDependencies: clipboard "^2.0.0" -private@^0.1.6, private@^0.1.8: +private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== @@ -26791,7 +26874,7 @@ promise@7.1.1: dependencies: asap "~2.0.3" -"promise@>=3.2 <8", promise@^7.1.1: +"promise@>=3.2 <8", promise@^7.0.3, promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== @@ -27174,7 +27257,7 @@ q@2.0.x: pop-iterate "^1.0.1" weak-map "^1.0.5" -q@^1.5.1: +q@^1.1.2, q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= @@ -27518,6 +27601,11 @@ react-dom@16.9.0: prop-types "^15.6.2" scheduler "^0.15.0" +react-dom@^0.14.0: + version "0.14.9" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.14.9.tgz#05064a3dcf0fb1880a3b2bfc9d58c55d8d9f6293" + integrity sha1-BQZKPc8PsYgKOyv8nVjFXY2fYpM= + react-error-overlay@5.1.6: version "5.1.6" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.6.tgz#0cd73407c5d141f9638ae1e0c63e7b2bf7e9929d" @@ -28194,6 +28282,14 @@ react@16.9.0: object-assign "^4.1.1" prop-types "^15.6.2" +react@^0.14.0: + version "0.14.9" + resolved "https://registry.yarnpkg.com/react/-/react-0.14.9.tgz#9110a6497c49d44ba1c0edd317aec29c2e0d91d1" + integrity sha1-kRCmSXxJ1EuhwO3TF67CnC4NkdE= + dependencies: + envify "^3.0.0" + fbjs "^0.6.1" + read-cmd-shim@^1.0.1, read-cmd-shim@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" @@ -28473,6 +28569,16 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" +recast@^0.11.17: + version "0.11.23" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM= + dependencies: + ast-types "0.9.6" + esprima "~3.1.0" + private "~0.1.5" + source-map "~0.5.0" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -30865,7 +30971,7 @@ source-map@^0.4.2, source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -35248,6 +35354,16 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" +webpack-visualizer-plugin@^0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/webpack-visualizer-plugin/-/webpack-visualizer-plugin-0.1.11.tgz#b8770ad86b4f652612c68b1b782253faf9f8a34e" + integrity sha1-uHcK2GtPZSYSxosbeCJT+vn4o04= + dependencies: + d3 "^3.5.6" + mkdirp "^0.5.1" + react "^0.14.0" + react-dom "^0.14.0" + webpack@4.39.1: version "4.39.1" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.39.1.tgz#60ed9fb2b72cd60f26ea526c404d2a4cc97a1bd8" @@ -35418,6 +35534,11 @@ whatwg-fetch@3.0.0, whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== +whatwg-fetch@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz#0e3684c6cb9995b43efc9df03e4c365d95fd9cc0" + integrity sha1-DjaExsuZlbQ+/J3wPkw2XZX9nMA= + whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4" From 35ece2a8d788f6c4d3716e183dd535976afe9e64 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Fri, 27 Dec 2019 12:20:00 -0800 Subject: [PATCH 04/14] Replace Animated RN with CSS transitions to save hundred Kb --- packages/web/src/header/Header.3.tsx | 198 +++++++++++++-------------- 1 file changed, 94 insertions(+), 104 deletions(-) diff --git a/packages/web/src/header/Header.3.tsx b/packages/web/src/header/Header.3.tsx index 1b5a44c8afe..3b783ae9ad8 100644 --- a/packages/web/src/header/Header.3.tsx +++ b/packages/web/src/header/Header.3.tsx @@ -3,7 +3,7 @@ import throttle from 'lodash.throttle' import dynamic from 'next/dynamic' import { SingletonRouter as Router, withRouter } from 'next/router' import * as React from 'react' -import { Animated, Dimensions, Easing, StyleSheet, View } from 'react-native' +import { Dimensions, StyleSheet, View, ViewStyle } from 'react-native' import BlueBanner, { styles as bannerStyle } from 'src/header/BlueBanner' import cssStyles from 'src/header/Header.3.scss' import { I18nProps, withNamespaces } from 'src/i18n' @@ -42,8 +42,6 @@ type Props = OwnProps & I18nProps interface State { showDesktopMenu: boolean mobileMenuActive: boolean - mobileMenuFade: Animated.Value - menuFade: Animated.Value menuFaded: boolean belowFoldUpScroll: boolean isBannerShowing: boolean @@ -74,19 +72,9 @@ export class Header extends React.PureComponent { } if (goingUp) { - this.setState({ menuFaded: false }, () => { - Animated.timing(this.state.menuFade, { - toValue: 1, - duration: 100, - easing: Easing.in(Easing.quad), - }).start() - }) + this.setState({ menuFaded: false }) } else if (belowFold) { - Animated.timing(this.state.menuFade, { - toValue: 0, - duration: 100, - easing: Easing.in(Easing.quad), - }).start(() => this.setState({ menuFaded: true })) + this.setState({ menuFaded: true }) } this.lastScrollOffset = scrollOffset() @@ -94,18 +82,9 @@ export class Header extends React.PureComponent { clickHamburger = debounce(() => { if (!this.state.mobileMenuActive) { - this.setState( - { - mobileMenuActive: true, - }, - () => { - Animated.timing(this.state.mobileMenuFade, { - toValue: 1, - duration: 150, - easing: Easing.inOut(Easing.quad), - }).start() - } - ) + this.setState({ + mobileMenuActive: true, + }) } else { this.closeMenu() } @@ -116,8 +95,6 @@ export class Header extends React.PureComponent { this.state = { showDesktopMenu: false, - mobileMenuFade: new Animated.Value(0), - menuFade: new Animated.Value(1), menuFaded: false, mobileMenuActive: false, belowFoldUpScroll: false, @@ -153,11 +130,7 @@ export class Header extends React.PureComponent { } } closeMenu = () => { - Animated.timing(this.state.mobileMenuFade, { - toValue: 0, - duration: 200, - easing: Easing.inOut(Easing.quad), - }).start(() => this.setState({ mobileMenuActive: false })) + this.setState({ mobileMenuActive: false }) } isDarkMode = () => { @@ -216,96 +189,101 @@ export class Header extends React.PureComponent { {isHomePage && ( )} - {this.state.menuFaded || ( - - )} + + + - {!this.state.menuFaded ? ( - <> - - {this.isDarkMode() ? ( - - ) : ( - - )} - - - ) : null} + <> + + {this.isDarkMode() ? ( + + ) : ( + + )} + + - {this.state.showDesktopMenu && - !this.state.menuFaded && ( - - {menuItems.map((item, index) => ( - -