Skip to content
This repository has been archived by the owner on May 7, 2021. It is now read-only.

[Snyk] Upgrade @jaredpalmer/after from 1.4.0 to 1.6.1 #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

snyk-bot
Copy link

@snyk-bot snyk-bot commented Apr 9, 2020

Snyk has created this PR to upgrade @jaredpalmer/after from 1.4.0 to 1.6.1.

ℹ️ Keep your dependencies up-to-date. This makes it easier to fix existing vulnerabilities and to more quickly identify and fix newly disclosed vulnerabilities when they affect your project.
  • The recommended version is 4 versions ahead of your current version.
  • The recommended version was released a month ago, on 2020-03-08.
Release notes
Package name: @jaredpalmer/after
  • 1.6.1 - 2020-03-08
    • fix(serialize-data): fix component name d07d127

    v1.6.0...v1.6.1

  • 1.6.0 - 2020-03-08

    Tree Shaking 🌲

    After.js is now 60KB smaller

    Before: image

    After: image

    closes #238

    Auto-Scroll Control 📜

    Disable Auto-Scroll Globally

    By default, After.js will scroll to top when URL changes, you can change that by passing scrollToTop: false to render().

    // ./src/server.js
    

    const scrollToTop = false;

    const html = await render({
    req,
    res,
    routes,
    assets,
    scrollToTop,
    });

    Disable Auto-Scroll for a Specific Page

    We are using a ref object to minimize unnecessary re-renders, you can mutate scrollToTop.current and component will not re-rendered but its scroll behavior will change immediately.
    You can control auto-scroll behavior from getInitialProps.

    class MyComponent extends React.Component {
      static async getInitialProps({ scrollToTop }) {
        scrollToTop.current = false;
        return { scrollToTop, stuff: 'whatevs' };
      }
    

    render() {
    return <h1>Hello, World!</h1>;
    }

    componentWillUnmount() {
    this.props.scrollToTop.current = true; // at the end restore scroll behavior
    }
    }

    closes #258

    <SerializeData /> and getSerializedData() 📃

    when you do SSR and you use redux, mobx, ... in document.js you have to pass store data to the client and on the client before ensure ready get called you have to read that data and put in the redux store.
    <SeriallizeData /> will do that for you.

    // ./src/document.js
    

    import React from 'react';
    import {
    AfterRoot,
    AfterData,
    AfterScripts,
    AfterStyles,
    SerializeData,
    __AfterContext,
    } from '@jaredpalmer/after';
    import { Provider } from 'react-redux';
    import serialize from 'serialize-javascript';

    class Document extends React.Component {
    static async getInitialProps({ renderPage, store }) {
    const page = await renderPage(App => props => (
    <Provider store={store}>
    <App {...props} />
    </Provider>
    ));
    return { ...page };
    }

    render() {
    const { helmet } = this.props;
    // get attributes from React Helmet
    const htmlAttrs = helmet.htmlAttributes.toComponent();
    const bodyAttrs = helmet.bodyAttributes.toComponent();

    <span class="pl-k">return</span> (
      <span class="pl-k">&lt;</span>html {<span class="pl-k">...</span>htmlAttrs}<span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span>head<span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>meta httpEquiv<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>X-UA-Compatible<span class="pl-pds">"</span></span> content<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>IE=edge<span class="pl-pds">"</span></span> <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>meta charSet<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>utf-8<span class="pl-pds">"</span></span> <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>title<span class="pl-k">&gt;</span>Welcome to the Afterparty<span class="pl-k">&lt;</span><span class="pl-k">/</span>title<span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>meta name<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>viewport<span class="pl-pds">"</span></span> content<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>width=device-width, initial-scale=1<span class="pl-pds">"</span></span> <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          {<span class="pl-smi">helmet</span>.<span class="pl-c1">title</span>.<span class="pl-en">toComponent</span>()}
          {<span class="pl-smi">helmet</span>.<span class="pl-smi">meta</span>.<span class="pl-en">toComponent</span>()}
          {<span class="pl-smi">helmet</span>.<span class="pl-c1">link</span>.<span class="pl-en">toComponent</span>()}
          <span class="pl-k">&lt;</span>AfterStyles <span class="pl-k">/</span><span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span><span class="pl-k">/</span>head<span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span>body {<span class="pl-k">...</span>bodyAttrs}<span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>AfterRoot <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>AfterData <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>ReduxData <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>AfterScripts <span class="pl-k">/</span><span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span><span class="pl-k">/</span>body<span class="pl-k">&gt;</span>
      <span class="pl-k">&lt;</span><span class="pl-k">/</span>html<span class="pl-k">&gt;</span>
    );
    

    }
    }

    function ReduxData() {
    const { store } = React.useContext(__AfterContext);
    return <SerializeData name="preloaded_state" data={store.getState()} />;
    }

    export default Document;

    to get data in the client use getSerializedData method:

    const preloadedState = getSerializedData('preloaded_state');
    const store = configureStore(preloadedState);

    getSerializedData will read data from window object and then it will remove object from window, you can change this behavior by passing a second argument to the method:

    function getSerializedData(name, remove = true) {
      const data = window[`_${name.toUpperCase()}_`];
      if (remove) {
        delete window[`_${name.toUpperCase()}_`];
      }
      return data;
    };
    • feat(with-redux): update with-redux example abcd759
    • Rename SerializeData.tsx to serializeData.tsx e0fd440
    • Merge branch 'canary' into feat/serialize-data c29f833
    • fix(serialize-data): change file names 71707ff
    • Merge branch 'master' into canary f23a6c1
    • feat(seriallize-data): pass props to <script /> tag cc66e46
    • feat(serialize-data): add serilizeData.js to package.json 008c110
    • feat(serilize-data): add e68d29e
    • feat(esm-build): update build scripts 526b703
    • feat(esm-build): fix imports 2fd854c
    • Update README.md 863c516
    • Feature - Auto Scroll Control (#282) 615468c
    • Feature - Create After App (#283) 33e288a

    v1.5.1...v1.6.0

  • 1.5.1 - 2020-02-05

    v1.5.0...v1.5.1

  • 1.5.0 - 2020-01-18

    Changed getInitialProps Behavior

    Old Behavior

    URL Change -> getInitialProps get called -> matched component get renderd on screen -> getInitialProps resolved -> component gets re-renered and can acess getInitialProps data from it's props

    this is very bad and there are some problems:

    1. very bad UX, this will cause page jank since matched component gets rendered on-screen without any data, and we have to show <Spinner /> till getInitialProps resolved
    2. scroll to top happen after getInitialProps resolved, so the user will see nothing (or footer) for a while
    3. if we use data from getInitialProps with hooks, we have to write very complicated code
    function PageB({ data }) 
      const [count, setCount] = React.useState(data)
    

    if (!data) return <Spinner />

    return <span>{count}</span>
    }

    PageB.getInitialProps = () => {
    return new Promise(reslove => setTimeout(() => reslove({ data: 1 }) , 3000))
    }

    data is undefined so count is undefined, and to fix it we have to write an effect like below:

    React.useEffect(() => {
      setCount(data)
    }, [ data ])
    

    not-concurrent

    New Behavior:

    URL Change -> getInitialProps get called -> wait's on current location until getInitialProps resolved -> render matched component with data from getInitialProps

    When a user moves from page /a to page /b, URL changes but the user still sees /a page on the screen till /b page data get fetched.

    concurrent

    Custom Document.js

    Now we have a simpler custom Document with <AfterScripts /> and <AfterStyles />.
    Any params that passed to getInitialProps and return values of it are available from __AfterContext.

    import { __AfterContext } from "@jaredpalmer/after"

    Use this context to build components for your custom Document.

    import React from 'react';
    import { AfterScripts, AfterStyles, AfterRoot, AfterData } from "@jaredpalmer/after"
    

    class Document extends React.Component {
    static async getInitialProps({ renderPage }) {
    const page = await renderPage();

    <span class="pl-k">return</span> { <span class="pl-k">...</span>page };
    

    }

    render() {
    const { helmet } = this.props;
    // get attributes from React Helmet
    const htmlAttrs = helmet.htmlAttributes.toComponent();
    const bodyAttrs = helmet.bodyAttributes.toComponent();

    <span class="pl-k">return</span> (
      <span class="pl-k">&lt;</span>html {<span class="pl-k">...</span>htmlAttrs}<span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span>head<span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>meta httpEquiv<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>X-UA-Compatible<span class="pl-pds">"</span></span> content<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>IE=edge<span class="pl-pds">"</span></span> <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>meta charSet<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>utf-8<span class="pl-pds">"</span></span> <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>title<span class="pl-k">&gt;</span>Welcome to the Afterparty<span class="pl-k">&lt;</span><span class="pl-k">/</span>title<span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>meta name<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>viewport<span class="pl-pds">"</span></span> content<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>width=device-width, initial-scale=1<span class="pl-pds">"</span></span> <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          {<span class="pl-smi">helmet</span>.<span class="pl-c1">title</span>.<span class="pl-en">toComponent</span>()}
          {<span class="pl-smi">helmet</span>.<span class="pl-smi">meta</span>.<span class="pl-en">toComponent</span>()}
          {<span class="pl-smi">helmet</span>.<span class="pl-c1">link</span>.<span class="pl-en">toComponent</span>()}
          <span class="pl-k">&lt;</span>AfterStyles <span class="pl-k">/</span><span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span><span class="pl-k">/</span>head<span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span>body {<span class="pl-k">...</span>bodyAttrs}<span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>AfterRoot <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>AfterData <span class="pl-k">/</span><span class="pl-k">&gt;</span>
          <span class="pl-k">&lt;</span>AfterScripts <span class="pl-k">/</span><span class="pl-k">&gt;</span>
        <span class="pl-k">&lt;</span><span class="pl-k">/</span>body<span class="pl-k">&gt;</span>
      <span class="pl-k">&lt;</span><span class="pl-k">/</span>html<span class="pl-k">&gt;</span>
    );
    

    }
    }

    v1.4.0...v1.5.0

  • 1.4.0 - 2019-10-24

    Dynamic 404 and Redirects

    404 Page

    React Router can detect No Match (404) Routes and show a fallback component, you can define your custom fallback component in routes.js file.

    // ./src/routes.js
    

    import React from 'react';
    import Home from './Home';
    import Notfound from './Notfound';
    import { asyncComponent } from '@jaredpalmer/after';

    export default [
    // normal route
    {
    path: '/',
    exact: true,
    component: Home,
    },
    // 404 route
    {
    // there is no need to declare path variable
    // react router will pick this component as fallback
    component: Notfound,
    },
    ];

    Notfound component must set staticContext.statusCode to 404 so express can set response status code more info.

    // ./src/Notfound.js
    

    import React from 'react';
    import { Route } from 'react-router-dom';

    function NotFound() {
    return (
    <Route
    render={({ staticContext }) => {
    if (staticContext) staticContext.statusCode = 404;
    return <div>The Page You Were Looking For Was Not Found</div>;
    }}
    />
    );
    }

    export default NotFound;

    if you don't declare 404 component in routes.js After.js will use its default fallback.

    Dynamic 404

    Sometimes you may need to send a 404 response based on some API response, in this case, react-router don't show fallback and you have to check for that in your component.

    import Notfound from './Notfound';
    

    function ProductPage({ product, error }) {
    if (error) {
    if (error.response.status === 404) {
    return <Notfound />;
    }

    <span class="pl-k">return</span> <span class="pl-k">&lt;</span>p<span class="pl-k">&gt;</span>Something went Wrong <span class="pl-k">!</span><span class="pl-k">&lt;</span><span class="pl-k">/</span>p<span class="pl-k">&gt;</span>;
    

    }
    { / if there were no errors we have our data / }
    return <h1>{product.name}</h1>;
    }

    ProductPage.getInitialProps = async ({ match }) => {
    try {
    const { data } = await fetchProduct(match.params.slug);
    return { product: data };
    } catch (error) {
    return { error };
    }
    };

    this makes code unreadable and hard to maintain. after.js makes this easy by providing an API for handling Dynamic 404 pages. you can return { statusCode: 404 } from getInitialProps and after.js will show 404 fallback components that you defined in routes.js for you.

    function ProductPage({ product }) {
      return <h1>{product.name}</h1>;
    }
    

    ProductPage.getInitialProps = async ({ match }) => {
    try {
    const { data } = await fetchProduct(match.params.slug);
    return { product: data };
    } catch (error) {
    if (error.response.status === 404) return { statusCode: 404 };
    return { error };
    }
    };

    Redirect

    You can redirect the user to another route by using Redirect from react-router, but it can make your code unreadable and hard to maintain.
    with after.js you can redirect client to other route by returning { redirectTo: "/new-location" } from getInitialProps.
    this can become handy for authorization when user does not have permission to access a specific route and you can redirect him/her to the login page.

    Dashboard.getInitialProps = async ({ match }) => {
      try {
        const { data } = await fetchProfile();
        return { data };
      } catch (error) {
        if (error.response.status === 401)
          return { statusCode: 401, redirectTo: '/login' };
        return { error };
      }
    };

    The redirect will happen before after.js start renders react to string soo it's fast.
    when using redirectTo default value for statusCode is 301, but you can use any numeric value you want.

    Commits:

    • Dynamic 404 and Redirects (#231) 2daea6c
    • #226: Fix anchor scroll behaviour (#227) 9868004
    • Fix scroll to top behaviour (#223) 1bf1e87
    • fix: examples/basic/package.json to reduce vulnerabilities (#200) ac1bb58
    • A Express.js -> An Express.js (#187) 5418910
    • Update render.tsx (#202) 2c03aaa
    • add first jest unit tests and fix another bug in loadInitialProps (#178) 3e4f2f4
    • Change NavLink import in code snippet in README.md (#180) 4bf6dfe
    • fix: examples/basic/package.json to reduce vulnerabilities (#181) 9626742
    • change examples basic references to build and not package (#169) cd468f6
    • fix: examples/basic/package.json to reduce vulnerabilities (#171) 3a267cf
    • remove as any in withRouter in after (#176) 57301bb
    • fix getInitialProps match, add ctx type, update deps (#174) 4606542
    • Fix: browser error on deserializing a state with Date (#164) 97e17a2
    • make options optional for render (#166) 7d6f5fe
    • remove any from AfterRenderOptions (#163) 41d1719
    • remove as many any types is as sane right now (#162) e3f1526
    • Stop swallowing getInitialProps errors (#151) 0ec6932
    • Create stale.yml 61c76ad
    • Add missing comma (#159) 7eb1e5c
    • Fix "}" in final example code - styled-components (#138) 23dfc40
    • Pass custom args to getInitialProps() (#157) f96e293
    • fix: package.json to reduce vulnerabilities (#137) e713035
    • Update README.md 55a12eb
    • Remove console.log 26fc5e1
from @jaredpalmer/after GitHub release notes

Note: You are seeing this because you or someone else with access to this repository has authorized Snyk to open upgrade PRs.

For more information:

🧐 View latest project report

🛠 Adjust upgrade PR settings

🔕 Ignore this dependency or unsubscribe from future upgrade PRs

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Is there a normal way to disable the auto-scroll-to-top on route change? Smaller Bundle Size ?
1 participant