<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Andrea Carraro</title>
    <description>The latest articles on Forem by Andrea Carraro (@toomuchdesign).</description>
    <link>https://forem.com/toomuchdesign</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F202875%2F4c48491c-9705-4304-a814-059985f14ad0.jpeg</url>
      <title>Forem: Andrea Carraro</title>
      <link>https://forem.com/toomuchdesign</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/toomuchdesign"/>
    <language>en</language>
    <item>
      <title>Unlocking API Interoperability: Converting OpenAPI to TypeScript JSON Schema</title>
      <dc:creator>Andrea Carraro</dc:creator>
      <pubDate>Mon, 04 Sep 2023 07:51:44 +0000</pubDate>
      <link>https://forem.com/toomuchdesign/unlocking-api-interoperability-converting-openapi-to-typescript-json-schema-55m</link>
      <guid>https://forem.com/toomuchdesign/unlocking-api-interoperability-converting-openapi-to-typescript-json-schema-55m</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This post briefly tells the story of why I wrote &lt;a href="https://github.com/toomuchdesign/openapi-ts-json-schema"&gt;&lt;code&gt;openapi-ts-json-schema&lt;/code&gt;&lt;/a&gt; to fill the unexpected gap existing between &lt;strong&gt;OpenAPI specification&lt;/strong&gt; and &lt;strong&gt;TypeScript JSON schema&lt;/strong&gt; format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prologue
&lt;/h2&gt;

&lt;p&gt;In the last few weeks at work I was faced with an obvious task which I thought had an obvious technical solution, from my naive fronted engineer background:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given an &lt;strong&gt;OpenAPI Specification&lt;/strong&gt;, generate the relevant &lt;strong&gt;JSON schema&lt;/strong&gt; files to be consumed and type-interpreted by a &lt;strong&gt;TypeScript&lt;/strong&gt; application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main idea consists of leveraging a library like &lt;a href="https://www.npmjs.com/package/json-schema-to-ts"&gt;&lt;code&gt;json-schema-to-ts&lt;/code&gt;&lt;/a&gt; to infer TypeScript types from the generated JSON schema files. This is a quite common pattern documented by &lt;a href="https://ajv.js.org/guide/typescript.html#utility-type-for-jtd-data-type"&gt;Ajv&lt;/a&gt; and &lt;a href="https://fastify.dev/docs/latest/Reference/Type-Providers"&gt;Fastify&lt;/a&gt;, to name a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codesandbox.io/p/devbox/cranky-euler-yhv7l8?file=%2Fsrc%2Fajv.ts%3A3%2C1"&gt;&lt;strong&gt;Ajv&lt;/strong&gt; example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codesandbox.io/p/devbox/cranky-euler-yhv7l8?file=%2Fsrc%2Fajv.ts%3A3%2C1"&gt;&lt;strong&gt;Fastify&lt;/strong&gt; example&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Ajv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ajv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FromSchema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json-schema-to-ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mySchema&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path/to/generated/schemas/MyModel.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ajv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ajv&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Perform data validation and type inference using the same schema&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ajv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FromSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;mySchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mySchema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// data gets type inference&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the &lt;a href="https://swagger.io/specification/"&gt;OpenAPI Specification&lt;/a&gt; is a &lt;em&gt;"machine-readable interface definition language for describing, [...] web services"&lt;/em&gt;, and &lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; is practically the only available type solution for Node.js, I confidently googled:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"openAPI to typescript JSON schema"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...and found no relevant results.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAPI to TypeScript JSON schema gap
&lt;/h2&gt;

&lt;p&gt;If &lt;strong&gt;OpenAPI -&amp;gt; TypeScript types&lt;/strong&gt; is mostly covered by &lt;a href="https://www.npmjs.com/package/openapi-typescript"&gt;&lt;code&gt;openapi-typescript&lt;/code&gt;&lt;/a&gt; and &lt;strong&gt;OpenAPI -&amp;gt; JSON schema&lt;/strong&gt; is covered by &lt;a href="https://www.npmjs.com/package/@openapi-contrib/openapi-schema-to-json-schema"&gt;&lt;code&gt;openapi-schema-to-json-schema&lt;/code&gt;&lt;/a&gt;, &lt;strong&gt;there is no clear way to generate TypeScript JSON schemas from an OpenAPI definition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The main shortcomings consist of TypeScript not being able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interpret/resolve JSON schema's &lt;code&gt;$ref&lt;/code&gt; and &lt;code&gt;$id&lt;/code&gt; props&lt;/li&gt;
&lt;li&gt;Import JSON files &lt;code&gt;as const&lt;/code&gt; (See &lt;a href="https://github.com/microsoft/TypeScript/issues/32063"&gt;relevant GitHub thread&lt;/a&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dogSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// TS cannot interpret/resolve $refs&lt;/span&gt;
    &lt;span class="na"&gt;favoriteFood&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;components/schemas/Food&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;favoriteFood&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Considering the example above, in order to have a JSON schema which TypeScript can properly interpret, all &lt;code&gt;$ref&lt;/code&gt; entries should be somehow statically resolved at generation time.&lt;/p&gt;

&lt;p&gt;After an initial attempt to manually replace the &lt;code&gt;$ref&lt;/code&gt;s all around my JSON schemas, I ended up putting together a few lines to automate the process which I eventually abstracted into a JS NPM package: &lt;a href="https://github.com/toomuchdesign/openapi-ts-json-schema"&gt;&lt;code&gt;openapi-ts-json-schema&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The generation flow consists of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resolve external/remote &lt;code&gt;$ref&lt;/code&gt;s and dereference them with &lt;a href="https://github.com/APIDevTools/json-schema-ref-parser"&gt;&lt;code&gt;@apidevtools/json-schema-ref-parser&lt;/code&gt;&lt;/a&gt; (resolving &lt;code&gt;$ref&lt;/code&gt;'s)&lt;/li&gt;
&lt;li&gt;Convert to JSON schema with &lt;a href="https://github.com/openapi-contrib/openapi-schema-to-json-schema"&gt;&lt;code&gt;@openapi-contrib/openapi-schema-to-json-schema&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/openapi-jsonschema-parameters"&gt;&lt;code&gt;openapi-jsonschema-parameters&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Generate one TypeScript JSON schema file for each definition (&lt;code&gt;.ts&lt;/code&gt; files with &lt;code&gt;as const&lt;/code&gt; assertion)&lt;/li&gt;
&lt;li&gt;Store schemas in a folder structure reflecting the original OpenAPI definition structure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The example above would result into a &lt;strong&gt;TypeScript JSON schema&lt;/strong&gt; file, ready to be imported and consumed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;componentsSchemasFood&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../components/schemas/Food&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;favoriteFood&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;componentsSchemasFood&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;favoriteFood&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since v0.3.0, &lt;code&gt;$ref&lt;/code&gt; definitions get generated as standalone TS JSON schema files and imported where needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Given the centrality of JSON schemas in most of web development, I would be glad to see TypeScript taking over and make JSON schemas first class citizens by adding native support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;importing JSON schema import as const&lt;/li&gt;
&lt;li&gt;inferring types natively from any JSON schema (currently achieved with the outstanding &lt;a href="https://www.npmjs.com/package/json-schema-to-ts"&gt;&lt;code&gt;json-schema-to-ts&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TypeScript JSON schemas are 100% valid JSON schemas and would be able to represent the missing joining link between &lt;strong&gt;runtime type validation&lt;/strong&gt; and &lt;strong&gt;static type check&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the meanwhile feel free to take a look at the approach taken by &lt;a href="https://github.com/toomuchdesign/openapi-ts-json-schema"&gt;&lt;code&gt;openapi-ts-json-schema&lt;/code&gt;&lt;/a&gt; and start a discussion there in case something doesn't fit your use case.&lt;/p&gt;

</description>
      <category>openapi</category>
      <category>typescript</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Bringing together testing and development environment with Mock Service Worker</title>
      <dc:creator>Andrea Carraro</dc:creator>
      <pubDate>Tue, 22 Mar 2022 16:52:54 +0000</pubDate>
      <link>https://forem.com/toomuchdesign/developing-with-msw-3a6l</link>
      <guid>https://forem.com/toomuchdesign/developing-with-msw-3a6l</guid>
      <description>&lt;p&gt;This post is a brief write-up about how &lt;a href="https://mswjs.io/"&gt;&lt;code&gt;Mock Service Worker&lt;/code&gt;&lt;/a&gt; radically improved testing experience and -surprisingly- overall development flow on a couple frontend projects I recently worked on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing: mock API to support test
&lt;/h2&gt;

&lt;p&gt;I initially chose &lt;code&gt;Mock Service Worker&lt;/code&gt; just as a &lt;a href="https://github.com/wheresrhys/fetch-mock"&gt;Fetch mock&lt;/a&gt; replacement, for the only reason that it &lt;strong&gt;intercepts network requests at the network layer&lt;/strong&gt; enabling mocking any requests including &lt;a href="https://axios-http.com/"&gt;Axios&lt;/a&gt;'s &lt;code&gt;XMLHttpRequest&lt;/code&gt; ones.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;msw&lt;/code&gt; approach favors building API mocks in a centralized way so that all tests run against the same set of mocks. (Still, any test can extend &lt;code&gt;msw&lt;/code&gt; mock handlers on the fly, when strictly necessary).&lt;/p&gt;

&lt;p&gt;As the projects have scaled, &lt;code&gt;msw&lt;/code&gt; mocks ended up &lt;strong&gt;simplistically replicating most of the consumed API&lt;/strong&gt;. This opened to...&lt;/p&gt;

&lt;h2&gt;
  
  
  Development: using the same mocks
&lt;/h2&gt;

&lt;p&gt;Since &lt;code&gt;msw&lt;/code&gt; handlers replicate most of API dependencies, I could run the same mocks used by tests in the browser to run the development environment. For free.&lt;/p&gt;

&lt;p&gt;Running tests and development environment with the same mocks turned out to be a huge improvement for both testing and development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging tests
&lt;/h3&gt;

&lt;p&gt;Broken tests could be debugged more easily be replicating the  testing scenario in browser. Same mocks means same application state in tests and browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decouple local development from API
&lt;/h3&gt;

&lt;p&gt;Developing in the browser using local mocks resulted in a faster and more flexible development flow: local mocks take almost no time to load but the keep the &lt;strong&gt;exact same async flow&lt;/strong&gt; of real API responses.&lt;/p&gt;

&lt;p&gt;Local mocks are easy to extend or change, therefore replicating a new API scenario is trivial.&lt;/p&gt;

&lt;p&gt;I ended up using local mocks most of my development time and contacting the actual API in very rare cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook
&lt;/h3&gt;

&lt;p&gt;In case you used Storybook, &lt;code&gt;msw&lt;/code&gt; &lt;a href="https://storybook.js.org/addons/msw-storybook-addon"&gt;integrates&lt;/a&gt; seamlessy with it, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  MSW inspector: asserting against mocked requests
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;msw&lt;/code&gt; encourages an &lt;a href="https://mswjs.io/docs/recipes/request-assertions"&gt;end-to-end testing approach&lt;/a&gt;, decoupled from code's implementation details, &lt;em&gt;which I also recommend&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Instead of asserting that a request was made, or had the correct data, test how your application reacted to that request.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even though, I sometimes found it necessary asserting against a specific sent request. Like ensuring that a &lt;code&gt;post/put&lt;/code&gt; request is issued with proper payload.&lt;/p&gt;

&lt;p&gt;For this reason &lt;code&gt;msw&lt;/code&gt; provides an API to &lt;a href="https://mswjs.io/docs/extensions/life-cycle-events#tracking-a-request"&gt;listen to intercepted requests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/toomuchdesign/msw-inspector"&gt;&lt;code&gt;msw-inspector&lt;/code&gt;&lt;/a&gt; is a tiny utility I wrote to inspect &lt;code&gt;msw&lt;/code&gt; intercepted requests and enable any testing framework to assert against them. It's open source and published as an npm package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mswInspector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRequests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://my.url/path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>msw</category>
    </item>
    <item>
      <title>Switching from React To Vue.js: don't lock yourself in</title>
      <dc:creator>Andrea Carraro</dc:creator>
      <pubDate>Fri, 19 Mar 2021 14:52:39 +0000</pubDate>
      <link>https://forem.com/toomuchdesign/switching-from-react-to-vue-js-survival-tips-58bc</link>
      <guid>https://forem.com/toomuchdesign/switching-from-react-to-vue-js-survival-tips-58bc</guid>
      <description>&lt;p&gt;This year I happened to onboard a &lt;strong&gt;Vue.js&lt;/strong&gt; based company after several years of mainly &lt;strong&gt;React&lt;/strong&gt; related activities. This is how I managed to approach this new ecosystem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;These notes are a work in progress. I'll keep them updated as long as I get familiar with Vue ecosystem.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Stay away from Vue cli tools
&lt;/h3&gt;

&lt;p&gt;Vue provides a &lt;a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue"&gt;set of optional cli integrations&lt;/a&gt; to provide additional plug-and-play functionalities to the core one. Most of them are not extensible and poorly maintained.&lt;/p&gt;

&lt;p&gt;My suggestion is to ignore them and use universal tools configured to work with Vue (eg. &lt;code&gt;jest&lt;/code&gt; instead of &lt;code&gt;@vue/cli-plugin-unit-jest&lt;/code&gt;, &lt;code&gt;eslint&lt;/code&gt; instead of &lt;code&gt;@vue/cli-plugin-eslint&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I'm currently just using &lt;code&gt;vue-cli-service&lt;/code&gt; dev server to run my development environment. Compile with Rollup (even though &lt;a href="https://github.com/vuejs/rollup-plugin-vue"&gt;&lt;code&gt;rollup-plugin-vue&lt;/code&gt;&lt;/a&gt; is still quite flaky).&lt;/p&gt;

&lt;h3&gt;
  
  
  Vue + Typescript
&lt;/h3&gt;

&lt;p&gt;Vue (at least v2) and Vue's &lt;em&gt;Single File Components&lt;/em&gt; don't play nice with Typescript, but luckily there are tools that can partially fill this gap.&lt;/p&gt;

&lt;h4&gt;
  
  
  Vuex + Typescript
&lt;/h4&gt;

&lt;p&gt;If using Vuex these helper libraries can help to bring store types into your components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/danielroe/typed-vuex"&gt;typed-vuex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/istrib/vuex-typescript"&gt;vuex-typescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mrcrowl/vuex-typex"&gt;vuex-typex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I eventually opted for &lt;strong&gt;Typed Vuex&lt;/strong&gt;, which seems to be the current de facto official Vuex/TypeScript library. It definitely does its job with a minimal impact over the existing codebase.&lt;/p&gt;

&lt;p&gt;The only minor downside consists on the fact that every component connected to the store is supposed to import a &lt;code&gt;storeAccessor&lt;/code&gt; object exposed by the same store instance used by the application. Not a real blocker in my opinion.&lt;/p&gt;

&lt;h4&gt;
  
  
  Type checking Vue components
&lt;/h4&gt;

&lt;p&gt;Vue components (and especially their &lt;em&gt;Vue Template Syntax&lt;/em&gt;) are unfortunately invisible to typescript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=octref.vetur"&gt;Vetur&lt;/a&gt; and &lt;a href="https://github.com/znck/vue-developer-experience"&gt;VueDX&lt;/a&gt; (&lt;em&gt;still in alpha&lt;/em&gt;) expose 2 &lt;strong&gt;cli component type checkers&lt;/strong&gt; which I've not been able to use with a Vue 2 project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vuejs.github.io/vetur/guide/vti.html"&gt;vti&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/znck/vue-developer-experience/tree/main/packages/typecheck"&gt;TypeCheck for Vue
&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luckily Vetur provides a working component &lt;strong&gt;type checking in VSC&lt;/strong&gt; by enabling experimental template interpolation service in your config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vetur.experimental.templateInterpolationService: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...not the best solution but better then nothing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Replacing Vue template with tsx
&lt;/h4&gt;

&lt;p&gt;Since Vue 2 type checking experience turned out to be quite a failure, I considered the option of skipping Vue templates (and Single File Component pattern) and just use TSX, which is type checkable by definition.&lt;/p&gt;

&lt;p&gt;I've found a &lt;a href="https://github.com/wonderful-panda/vue-tsx-support"&gt;very promising library&lt;/a&gt; which provides the necessary glue between Vue and Typescript + TSX. &lt;/p&gt;

&lt;p&gt;I've toyed with &lt;code&gt;vue-tsx-support&lt;/code&gt; a couple hours with encouraging results, but I couldn't actually suggest my team to base our project on a library not officially supported by Vue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write framework-agnostic tests
&lt;/h3&gt;

&lt;p&gt;When it comes to write unit tests, don't lock yourself into Vue ecosystem but use an abstraction on top of this.&lt;/p&gt;

&lt;p&gt;I'm using &lt;a href="https://github.com/testing-library/vue-testing-library"&gt;&lt;code&gt;vue-testing-library&lt;/code&gt;&lt;/a&gt; with &lt;a href="https://mswjs.io/"&gt;&lt;code&gt;msw&lt;/code&gt;&lt;/a&gt; (to mock network responses) and it works as well as &lt;code&gt;react-testing-library&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  General considerations
&lt;/h3&gt;

&lt;p&gt;Vue ecosystem is not mature as React's. A significant number of Vue-specific libraries are solo projects with uncertain present and future.&lt;/p&gt;

&lt;p&gt;As a general approach I'm trying to rely on Vue ecosystem only for what is strictly necessary and find a way of using tools built outside of Vue realm. On the long term I expect Vue to open to established standards of web frontend industry.&lt;/p&gt;

&lt;p&gt;Just an example. Vue's &lt;a href="https://vuejs.org/v2/guide/single-file-components.html"&gt;Single File Component pattern&lt;/a&gt; seems a good idea in the first half hour, until you realize it places your code out of any language standard, preventing any third party tool from being able to parse it.&lt;/p&gt;

</description>
      <category>vue</category>
    </item>
    <item>
      <title>Contextual routing and modal routes in Next.js</title>
      <dc:creator>Andrea Carraro</dc:creator>
      <pubDate>Sun, 18 Oct 2020 20:24:49 +0000</pubDate>
      <link>https://forem.com/toomuchdesign/contextual-routing-and-modal-routes-in-next-js-18fn</link>
      <guid>https://forem.com/toomuchdesign/contextual-routing-and-modal-routes-in-next-js-18fn</guid>
      <description>&lt;p&gt;&lt;strong&gt;Contextual routing&lt;/strong&gt; is a widespread UI technic made popular by applications like Facebook, Instagram and Reddit usually in the shape of &lt;strong&gt;Modal Routes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Modal routes pattern consists of opening a modal while temporary &lt;strong&gt;replacing the current URL&lt;/strong&gt; (usually with the one pointing to the resource being displayed in-modal):&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4NR2uOBsIu4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic contextual routing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; router recently added support for contextual routing by simply providing &lt;code&gt;Link&lt;/code&gt; component with the relevant &lt;code&gt;href&lt;/code&gt; + &lt;code&gt;as&lt;/code&gt; props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt;
  &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/post-list?postId=42&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/post/42&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example would update browser address' path to &lt;code&gt;/post/42&lt;/code&gt; while rendering the page specified as &lt;code&gt;href&lt;/code&gt; (&lt;code&gt;/post-list&lt;/code&gt; with &lt;code&gt;postId&lt;/code&gt; parameters equal to &lt;code&gt;42&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This leads to &lt;strong&gt;2 possible outcomes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user closes the modal and the URL is restored to the value where contextual routing was started (in our case &lt;code&gt;/post-list&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;user refreshes the page landing on the actual page described by the URL&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  HREF property
&lt;/h2&gt;

&lt;p&gt;The minimal necessary information to render a Next.js page consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;page &lt;code&gt;pathname&lt;/code&gt; (eg. &lt;code&gt;/post/[id]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;page params (eg. &lt;code&gt;id=42&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main idea behind contextual routing consists of creating a &lt;strong&gt;divergence&lt;/strong&gt; between the URL displayed and the page actually rendered.&lt;/p&gt;

&lt;p&gt;Since contextual navigation replaces the URL, it means that rendered pages cannot rely anymore on the URL to retrieve &lt;code&gt;pathname&lt;/code&gt; and relative page params.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;href&lt;/code&gt; prop&lt;/strong&gt; plays therefore the crucial role of supplying the aforementioned information as a &lt;strong&gt;single string&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// page pathname + all required params as query string&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;`?param1=1&amp;amp;param2=2`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real world scenario
&lt;/h2&gt;

&lt;p&gt;Before starting contextual routing navigation you need to know &lt;strong&gt;3 information beforehand&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;as&lt;/code&gt; path (the path displayed during contextual routing)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;href&lt;/code&gt; path&lt;/li&gt;
&lt;li&gt;return &lt;code&gt;href&lt;/code&gt; (the path to return to to end contextual routing)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;href&lt;/strong&gt; and &lt;strong&gt;return href&lt;/strong&gt; are trivial to get when the starting page has a static path, let's say: &lt;code&gt;/post-list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Things gets trickier when starting page path is not statically defined, in other words when the path includes &lt;strong&gt;dynamic parameters&lt;/strong&gt; like: &lt;code&gt;/post-list/bob&lt;/code&gt; (where &lt;code&gt;bob&lt;/code&gt; is an author name).&lt;/p&gt;

&lt;p&gt;This means &lt;code&gt;href&lt;/code&gt; has to be generated from initial page &lt;code&gt;pathname&lt;/code&gt; plus route params and then &lt;strong&gt;persisted&lt;/strong&gt; during the whole contextual routing navigation in order to keep the page alive.&lt;/p&gt;

&lt;p&gt;On top of this a developer might want to &lt;strong&gt;extend available route params&lt;/strong&gt; with extra ones to be made available during contextual navigation. Eg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post/42&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;returnHref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post-list/bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post-list/[author]?author=bob&amp;amp;id=42&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above provides &lt;code&gt;id=42&lt;/code&gt; as extra param to make the modal route aware of which post should be displayed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://toomuchdesign.github.io/next-use-contextual-routing/"&gt;This demo&lt;/a&gt; shows a basic implementation of what you just read.&lt;/p&gt;

&lt;h2&gt;
  
  
  The devil is in the details
&lt;/h2&gt;

&lt;p&gt;There's is an extra pitfall worth mentioning: the application would loose reference to &lt;code&gt;returnHref&lt;/code&gt; after a page reload followed by one or more back button presses.&lt;/p&gt;

&lt;p&gt;This means the application won't be able to restore the initial URL while the modal route is open, breaking the user flow or forcing Next.js to reload the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  One hook to rule them all
&lt;/h2&gt;

&lt;p&gt;In order to overcome this issue and make contextual routing setup trivial, I wrapped the necessary boilerplate logic in a React hook published as &lt;a href="https://www.npmjs.com/package/next-use-contextual-routing"&gt;&lt;code&gt;next-use-contextual-routing&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can read the source code and star it &lt;a href="https://github.com/toomuchdesign/next-use-contextual-routing"&gt;on github&lt;/a&gt;. It's &lt;strong&gt;fully tested&lt;/strong&gt; and weights &lt;strong&gt;~0.5 kb gzipped&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContextualRouting&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-use-contextual-routing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;makeContextualHref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;returnHref&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useContextualRouting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt;
  &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/post/42&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;makeContextualHref&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;
  &lt;span class="nx"&gt;shallow&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hook returns 2 values:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;makeContextualHref&lt;/code&gt;&lt;/strong&gt;: a function returning the &lt;code&gt;href&lt;/code&gt; value necessary to start contextual navigation. It optionally accepts an object providing &lt;strong&gt;extra &lt;code&gt;href&lt;/code&gt; parameters&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;returnHref&lt;/code&gt;&lt;/strong&gt;: the path to return to to close contextual navigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://toomuchdesign.github.io/next-use-contextual-routing/"&gt;The demo mentioned above&lt;/a&gt; makes use of &lt;code&gt;next-use-contextual-routing&lt;/code&gt; hook. Check it out to make sure it can suit your needs.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>DOM testing Next.js applications</title>
      <dc:creator>Andrea Carraro</dc:creator>
      <pubDate>Sat, 26 Sep 2020 22:27:53 +0000</pubDate>
      <link>https://forem.com/toomuchdesign/dom-testing-next-js-applications-46ke</link>
      <guid>https://forem.com/toomuchdesign/dom-testing-next-js-applications-46ke</guid>
      <description>&lt;p&gt;This article analyses the current status of DOM tests in Next.js and presents a utility library (&lt;a href="https://github.com/toomuchdesign/next-page-tester#next-page-tester" rel="noopener noreferrer"&gt;next-page-tester&lt;/a&gt;) to get back DOM integration tests alongside Next.js apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The missing tile
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; comes with an outstanding tool belt out of the box, providing any web project with great dev experience and productivity since day one.&lt;/p&gt;

&lt;p&gt;The value provided by Next.js is truly priceless, but there's a missing tile: &lt;strong&gt;DOM integration testing&lt;/strong&gt; (&lt;a href="https://github.com/testing-library/react-testing-library" rel="noopener noreferrer"&gt;React Testing Library&lt;/a&gt; or &lt;a href="https://github.com/enzymejs/enzyme" rel="noopener noreferrer"&gt;Enzyme&lt;/a&gt; tests, to put it simple) is quite uneffective and fragmented when it comes to Next.js.&lt;/p&gt;

&lt;p&gt;Let's see why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;An average Next.js project is made of disconnected pieces which are glued together by Next.js internals on &lt;code&gt;next dev&lt;/code&gt; or &lt;code&gt;next build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means &lt;strong&gt;less boilerplate code&lt;/strong&gt; 👍but also &lt;strong&gt;no explicit relations&lt;/strong&gt; among &lt;strong&gt;separate parts&lt;/strong&gt; 😔. In other words: only Next.js knows how to put your application together.&lt;/p&gt;

&lt;p&gt;This affects the way &lt;strong&gt;unit tests for Next.js apps are written&lt;/strong&gt;: &lt;strong&gt;isolated tests targeting different parts&lt;/strong&gt; and optimistically mocking what's in-between.&lt;/p&gt;

&lt;p&gt;Let's be more explicit. This involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;testing &lt;strong&gt;individual page components&lt;/strong&gt; providing the expected server-side generated props&lt;/li&gt;
&lt;li&gt;testing pages' &lt;a href="https://nextjs.org/docs/basic-features/data-fetching" rel="noopener noreferrer"&gt;&lt;strong&gt;data fetching methods&lt;/strong&gt;&lt;/a&gt; (&lt;code&gt;getServerSideProps&lt;/code&gt; and &lt;code&gt;getStaticProps&lt;/code&gt;) providing the expected &lt;code&gt;context&lt;/code&gt; object&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mocking &lt;a href="https://nextjs.org/docs/api-reference/next/router#router-object" rel="noopener noreferrer"&gt;&lt;code&gt;NextRouter&lt;/code&gt; object&lt;/a&gt;&lt;/strong&gt; with relevant current route data (&lt;code&gt;path&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, &lt;code&gt;querystring&lt;/code&gt;...) when the tested page makes use of Next's &lt;a href="https://nextjs.org/docs/api-reference/next/link" rel="noopener noreferrer"&gt;&lt;code&gt;Link&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://nextjs.org/docs/api-reference/next/router#userouter" rel="noopener noreferrer"&gt;&lt;code&gt;useRouter&lt;/code&gt; or &lt;code&gt;withRouter&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;hoping that &lt;strong&gt;page file names&lt;/strong&gt; are 100% correct, since Next.js relies on those to configure file system routing&lt;/li&gt;
&lt;li&gt;rendering &lt;strong&gt;custom &lt;a href="https://nextjs.org/docs/advanced-features/custom-app" rel="noopener noreferrer"&gt;App&lt;/a&gt; and &lt;a href="https://nextjs.org/docs/advanced-features/custom-document" rel="noopener noreferrer"&gt;Document&lt;/a&gt;&lt;/strong&gt; components, if the case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All this is feasible but, where are the times when we could write integration tests by rendering the whole components tree in Node.js with &lt;a href="https://github.com/jsdom/jsdom" rel="noopener noreferrer"&gt;JSDOM&lt;/a&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  Write tests. Not too many. Mostly integration.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft2w9qfa09rp86352hy4u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft2w9qfa09rp86352hy4u.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/rauchg/status/807626710350839808" rel="noopener noreferrer"&gt;https://twitter.com/rauchg/status/807626710350839808&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since &lt;strong&gt;business logic is spread among different disconnected places&lt;/strong&gt; (and the fact that Next.js runs a web server), the currently &lt;a href="https://github.com/vercel/next.js/discussions?discussions_q=tests" rel="noopener noreferrer"&gt;suggested way of testing Next.js applications&lt;/a&gt; consists of running e2e tests against a fully fledged instance of the app.&lt;/p&gt;

&lt;p&gt;With the rise of tools like &lt;a href="https://www.cypress.io/" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt; and &lt;a href="https://devexpress.github.io/testcafe/" rel="noopener noreferrer"&gt;Test Café&lt;/a&gt;, e2e tester lives became significantly easier but, as everything in life, &lt;a href="https://en.wikipedia.org/wiki/The_Mythical_Man-Month#No_silver_bullet" rel="noopener noreferrer"&gt;there's no silver bullet™&lt;/a&gt; and browser tests make no exception. It'd be cool to be able to &lt;strong&gt;grab the right tool for the right task&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The internet is packed with resources documenting the trade-offs of different testing strategies. It's mostly a matter of cost, speed and determinism. &lt;a href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests" rel="noopener noreferrer"&gt;This is a popular article by Kent C. Dodds to name one 🔗&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcbot3v9lpgjagh8dj8v5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcbot3v9lpgjagh8dj8v5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  DOM Integration tests for Next.js
&lt;/h2&gt;

&lt;p&gt;Ideally, a promising integration testing routine might consist of &lt;strong&gt;testing&lt;/strong&gt; Next.js apps &lt;strong&gt;by route&lt;/strong&gt;: given a route path, I receive the matching page element ready to be tested with any DOM testing library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNextJsPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to get to such testing routine we need to &lt;strong&gt;replicate part of Next.js glue&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;resolving&lt;/strong&gt; provided &lt;strong&gt;routes&lt;/strong&gt; into the matching page component&lt;/li&gt;
&lt;li&gt;calling &lt;strong&gt;Next.js data fetching methods&lt;/strong&gt; (&lt;code&gt;getServerSideProps&lt;/code&gt;, &lt;code&gt;getInitialProps&lt;/code&gt; or &lt;code&gt;getStaticProps&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;set up the expected &lt;strong&gt;mocked &lt;code&gt;next/router&lt;/code&gt; provider&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;wrapping page with custom &lt;code&gt;_app&lt;/code&gt;/&lt;code&gt;_document&lt;/code&gt; component&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;instantiating&lt;/strong&gt; page component with the &lt;strong&gt;expected props&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Emulate client side navigation via &lt;code&gt;Link&lt;/code&gt;, &lt;code&gt;router.push&lt;/code&gt;, &lt;code&gt;router.replace&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I put together this logic in &lt;a href="https://github.com/toomuchdesign/next-page-tester#next-page-tester" rel="noopener noreferrer"&gt;next-page-tester&lt;/a&gt;, an utility library which enables approaching tests like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-page-tester&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renders blog page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Linked page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;next-page-tester is &lt;a href="https://www.npmjs.com/package/next-page-tester" rel="noopener noreferrer"&gt;available on NPM&lt;/a&gt; and aims to make DOM integration tests first class citizens in Next.js.&lt;/p&gt;

&lt;p&gt;It's written in Typescript, fully tested and open to receive any feedback from curious Next.js users. Hop over to &lt;a href="https://github.com/toomuchdesign/next-page-tester#next-page-tester" rel="noopener noreferrer"&gt;&lt;code&gt;next-page-tester&lt;/code&gt; GitHub page&lt;/a&gt; to see how it works or lend hand :).&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>testing</category>
      <category>react</category>
    </item>
    <item>
      <title>Use next.js with react-router</title>
      <dc:creator>Andrea Carraro</dc:creator>
      <pubDate>Sun, 28 Jul 2019 18:11:16 +0000</pubDate>
      <link>https://forem.com/toomuchdesign/next-js-react-router-2kl8</link>
      <guid>https://forem.com/toomuchdesign/next-js-react-router-2kl8</guid>
      <description>&lt;p&gt;This repo documents an attempt of using &lt;a href="https://github.com/zeit/next.js/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; (preserving native SSR features) with the following setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single entry point (like &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt; and &lt;a href="https://github.com/xing/hops" rel="noopener noreferrer"&gt;Hops&lt;/a&gt;). No file system-based routing&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ReactTraining/react-router" rel="noopener noreferrer"&gt;react-router&lt;/a&gt; as only routing system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This document is available as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/toomuchdesign/next-react-router" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/toomuchdesign/next-js-react-router-2kl8"&gt;dev.to post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Disclaimers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js team strongly advises against this approach.&lt;/li&gt;
&lt;li&gt;This experiment was carried out at the times of Next.js v9.3: the framework has changed a lot since then.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part one, basic setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1 - Install Next.js
&lt;/h3&gt;

&lt;p&gt;Relevant &lt;a href="https://github.com/toomuchdesign/next-react-router/tree/1-initial-setup" rel="noopener noreferrer"&gt;repo commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs#setup" rel="noopener noreferrer"&gt;Install NextJS&lt;/a&gt; as usual and create the &lt;strong&gt;single entry point&lt;/strong&gt; file at &lt;code&gt;pages/index.js&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 - Redirect all requests to single entrypoint
&lt;/h3&gt;

&lt;p&gt;Relevant &lt;a href="https://github.com/toomuchdesign/next-react-router/tree/2-redirect-to-entrypoint" rel="noopener noreferrer"&gt;repo commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to skip file system-based routing, we'll configure a &lt;a href="https://nextjs.org/docs#custom-server-and-routing" rel="noopener noreferrer"&gt;custom Next.js server&lt;/a&gt; to forward all the requests to our single entrypoint.&lt;/p&gt;

&lt;p&gt;We'll use Next.js &lt;a href="https://github.com/zeit/next.js/blob/2b1a5c3eb4f67a30e1a9000d7d21e14bbe536687/packages/next-server/server/next-server.ts#L405" rel="noopener noreferrer"&gt;&lt;code&gt;Server.render&lt;/code&gt; method&lt;/a&gt; to render and serve the entrypoint.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// server.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;nextJS&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Redirect all requests to main entrypoint pages/index.js&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;gt; Ready on http://localhost:3000`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run the dev server, and the entrypoint page at &lt;code&gt;pages/index.js&lt;/code&gt; should be served as response for any requested url. 👊&lt;/p&gt;

&lt;h3&gt;
  
  
  3 - Introduce react-router
&lt;/h3&gt;

&lt;p&gt;Relevant &lt;a href="https://github.com/toomuchdesign/next-react-router/tree/3-introduce-react-router" rel="noopener noreferrer"&gt;repo commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to get different responses according to the requested url we need a routing system.&lt;/p&gt;

&lt;p&gt;We'll use &lt;code&gt;react-router&lt;/code&gt; (see it's &lt;a href="https://reacttraining.com/react-router/web/guides/server-rendering" rel="noopener noreferrer"&gt;docs about SSR&lt;/a&gt;) and wrap the application with a &lt;code&gt;StaticRouter&lt;/code&gt; or a &lt;code&gt;BrowserRouter&lt;/code&gt; based on the environment application environment (server or browser).&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;react-router&lt;/code&gt; and &lt;code&gt;react-router-dom&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm i react-router react-router-dom -S


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;...and update the &lt;code&gt;pages/index.js&lt;/code&gt; entrypoint to use some &lt;code&gt;Link&lt;/code&gt; and &lt;code&gt;Route&lt;/code&gt; components from &lt;code&gt;react-router-dom&lt;/code&gt; (see repo).&lt;/p&gt;

&lt;p&gt;Let's now declare a &lt;code&gt;withReactRouter&lt;/code&gt; HOC to wrap the application with the proper router:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// next/with-react-router.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppWithReactRouter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;StaticRouter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StaticRouter&lt;/span&gt;
            &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/StaticRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;...and wrap the application with &lt;code&gt;withReactRouter&lt;/code&gt; HOC:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// pages/_app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;withReactRouter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../next/with-react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Container&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Container&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;withReactRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run the dev server, and you should be able to see your routes live and server side rendered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part two, context information
&lt;/h2&gt;

&lt;p&gt;One of my favourite &lt;code&gt;react-router&lt;/code&gt; features consists of the possibility of &lt;a href="https://reacttraining.com/react-router/web/guides/server-rendering/adding-app-specific-context-information" rel="noopener noreferrer"&gt;adding context information&lt;/a&gt; during the rendering phase and &lt;strong&gt;returning server side responses&lt;/strong&gt; based on the information collected into the &lt;strong&gt;&lt;code&gt;context&lt;/code&gt; object&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This enables client side code to take control of the responses returned by the node server like &lt;strong&gt;returning a HTTP 404&lt;/strong&gt; instead of a "not found page" or returning a &lt;strong&gt;real HTTP 302 redirect&lt;/strong&gt; instead of a client side one.&lt;/p&gt;

&lt;p&gt;In order to achieve this behaviour we have to configure Next.js to do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;render the requested page providing a context object to the app router&lt;/li&gt;
&lt;li&gt;check whether context object was mutated during the rendering process&lt;/li&gt;
&lt;li&gt;decide whether to return the rendered page or do something else based on context object&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4 - Provide context object to the router
&lt;/h3&gt;

&lt;p&gt;Relevant &lt;a href="https://github.com/toomuchdesign/next-react-router/tree/4-provide-context" rel="noopener noreferrer"&gt;repo commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We'll inject an empty &lt;code&gt;context&lt;/code&gt; object into Express' &lt;code&gt;req.local&lt;/code&gt; object and make it available to the router application via &lt;a href="https://reactjs.org/docs/context.html" rel="noopener noreferrer"&gt;React Context&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's inject &lt;code&gt;context&lt;/code&gt; object into Express' &lt;code&gt;req.local&lt;/code&gt; object:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;// server.js
&lt;span class="p"&gt;server.get('/*', async (req, res, next) =&amp;gt; {
&lt;/span&gt;  try {
&lt;span class="gi"&gt;+   req.locals = {};
+   req.locals.context = {};
&lt;/span&gt;    app.render(req, res, '/');
&lt;span class="err"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next.js provides a &lt;code&gt;req&lt;/code&gt; and &lt;code&gt;res&lt;/code&gt; objects as props of &lt;a href="https://nextjs.org/docs#fetching-data-and-component-lifecycle" rel="noopener noreferrer"&gt;&lt;code&gt;getInitialProps&lt;/code&gt; static method&lt;/a&gt;. We'll fetch &lt;code&gt;req.originalUrl&lt;/code&gt; and &lt;code&gt;req.locals.context&lt;/code&gt; and handle it over to the static router.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;// next/with-react-router.js
  return class AppWithReactRouter extends React.Component {
&lt;span class="gi"&gt;+   static async getInitialProps(appContext) {
+     const {
+       ctx: {
+         req: {
+           originalUrl,
+           locals = {},
+         },
+       },
+     } = appContext;
+     return {
+       originalUrl,
+       context: locals.context || {},
+     };
+   }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  // Code omitted
          &amp;lt;StaticRouter
&lt;span class="gd"&gt;-           location={this.props.router.asPath}
&lt;/span&gt;&lt;span class="gi"&gt;+           location={this.props.originalUrl}
+           context={this.props.context}
&lt;/span&gt;          &amp;gt;
&lt;span class="err"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  5 - Separate rendering and response
&lt;/h3&gt;

&lt;p&gt;Relevant &lt;a href="https://github.com/toomuchdesign/next-react-router/" rel="noopener noreferrer"&gt;repo commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since we want to provide extra server behaviours based on &lt;code&gt;req.locals.context&lt;/code&gt; in-between SSR and server response, Next.js &lt;code&gt;Server.render&lt;/code&gt; falls short of flexibility.&lt;/p&gt;

&lt;p&gt;We'll re-implement &lt;code&gt;Server.render&lt;/code&gt; in &lt;code&gt;server.js&lt;/code&gt; using Next.js &lt;code&gt;Server.renderToHTML&lt;/code&gt; and &lt;code&gt;Server.sendHTML&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;Please note that some code was omitted. Refer to the source code for the complete implementation.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;// server.js
  server.get('/*', async (req, res, next) =&amp;gt; {
    try {
&lt;span class="gi"&gt;+     // Code omitted
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;      req.locals = {};
      req.locals.context = {};
&lt;span class="gd"&gt;-     app.render(req, res, '/');
&lt;/span&gt;&lt;span class="gi"&gt;+     const html = await app.renderToHTML(req, res, '/', {});
+
+     // Handle client redirects
+     const context = req.locals.context;
+     if (context.url) {
+       return res.redirect(context.url)
+     }
+
+     // Handle client response statuses
+     if (context.status) {
+       return res.status(context.status).send();
+     }
+
+     // Code omitted
+     app.sendHTML(req, res, html);
&lt;/span&gt;    } catch (e) {
&lt;span class="err"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before sending the response with the rendered HTML to the client, we now check the &lt;code&gt;context&lt;/code&gt; object and redirect or return a custom HTTP code, if necessary.&lt;/p&gt;

&lt;p&gt;In order to try it out, update the &lt;code&gt;pages/index.js&lt;/code&gt; entrypoint to &lt;a href="https://github.com/toomuchdesign/next-react-router/blob/master/pages/index.js" rel="noopener noreferrer"&gt;make use of &lt;code&gt;&amp;lt;Redirect&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Status&amp;gt;&lt;/code&gt; components&lt;/a&gt; and start the dev server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We showed how it's be possible to setup Next.js take full &lt;strong&gt;advantage of &lt;code&gt;react-router&lt;/code&gt;&lt;/strong&gt;, enabling &lt;strong&gt;single entrypoint&lt;/strong&gt; approach and fully &lt;strong&gt;preserving SSR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In order to do so we:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Redirected all server requests to a &lt;strong&gt;single entrypoint&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrapped&lt;/strong&gt; the application (using HOC) with the proper &lt;strong&gt;&lt;code&gt;react-router&lt;/code&gt; router&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Injected &lt;code&gt;req&lt;/code&gt; server object with a &lt;strong&gt;&lt;code&gt;locals.context&lt;/code&gt; object&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Provided &lt;strong&gt;HOC wrapper&lt;/strong&gt; with &lt;code&gt;req.locals.context&lt;/code&gt; and &lt;code&gt;req.originalUrl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extended next.js &lt;code&gt;Server.render&lt;/code&gt;&lt;/strong&gt; to take into account &lt;code&gt;req.locals.context&lt;/code&gt; before sending HTML&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The re-implementation of &lt;code&gt;Server.render&lt;/code&gt; in userland code is the most disturbing part of it, but it might be made unnecessary by extending a bit &lt;code&gt;Server.render&lt;/code&gt; API in Next.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;react-router&lt;/code&gt; rendered server side
&lt;/h4&gt;

&lt;p&gt;react-router's &lt;code&gt;&amp;lt;Route&amp;gt;&lt;/code&gt; components get &lt;strong&gt;statically rendered&lt;/strong&gt; on the server based on received &lt;a href="https://expressjs.com/en/api.html#req.originalUrl" rel="noopener noreferrer"&gt;&lt;code&gt;req.originalUrl&lt;/code&gt;&lt;/a&gt; url.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ftoomuchdesign%2Fnext-react-router%2Fmaster%2Fdocs%2Fssr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ftoomuchdesign%2Fnext-react-router%2Fmaster%2Fdocs%2Fssr.png" alt="Server side render"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  HTTP 302 redirect triggered by client code
&lt;/h4&gt;

&lt;p&gt;When server rendering process encounters &lt;code&gt;&amp;lt;Redirect from="/people/" to="/users/" /&amp;gt;&lt;/code&gt; component, the server response will return an &lt;strong&gt;HTTP 302 response&lt;/strong&gt; with the expected &lt;strong&gt;&lt;code&gt;Location&lt;/code&gt; header&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ftoomuchdesign%2Fnext-react-router%2Fmaster%2Fdocs%2F302.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ftoomuchdesign%2Fnext-react-router%2Fmaster%2Fdocs%2F302.png" alt="HTTP 302 redirect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  HTTP 404 triggered by client code
&lt;/h4&gt;

&lt;p&gt;When server rendering process encounters &lt;code&gt;&amp;lt;Status code={404}/&amp;gt;&lt;/code&gt; component, the &lt;strong&gt;server&lt;/strong&gt; response returns an &lt;strong&gt;HTTP response&lt;/strong&gt; with the &lt;strong&gt;expected status code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ftoomuchdesign%2Fnext-react-router%2Fmaster%2Fdocs%2F404.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ftoomuchdesign%2Fnext-react-router%2Fmaster%2Fdocs%2F404.png" alt="HTTP 404 redirect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Further consideration
&lt;/h3&gt;

&lt;p&gt;I'm sure this setup is way far from being optimal. I'll be happy take into account any suggestions, feedbacks, improvements, ideas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issues
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Static pages not being exported&lt;/li&gt;
&lt;li&gt;Dev mode cannot build requested route on demand&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getInitialProps&lt;/code&gt; not implemented&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>reactrouter</category>
      <category>react</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
