<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/react/</id>
  <link href="https://www.endpointdev.com/blog/tags/react/"/>
  <link href="https://www.endpointdev.com/blog/tags/react/" rel="self"/>
  <updated>2023-06-26T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Migrating Rails 6 React to Rails 7 React</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/06/migrating-rails6-react-rails7-react/"/>
      <id>https://www.endpointdev.com/blog/2023/06/migrating-rails6-react-rails7-react/</id>
      <published>2023-06-26T00:00:00+00:00</published>
      <author>
        <name>Indra Pranesh Palanisamy</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/06/migrating-rails6-react-rails7-react/pexels-indra-pranesh-palanisamy-17019134.webp&#34; alt=&#34;A coconut tree stands in the corner of a serene blue sky&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Indra Pranesh Palanisamy, 2022 --&gt;
&lt;p&gt;CasePointer’s disease reporting portal is built on React and Rails 6, and it&amp;rsquo;s time for an upgrade to Rails 7. This blog post will cover the steps, benefits, and challenges of migrating from Rails 6 to Rails 7, and offer valuable insights into the world of Ruby on Rails.&lt;/p&gt;
&lt;p&gt;With the recent release of Rails 7, there are many new features and improvements to explore.
One of the biggest changes in Rails 7 is the retirement of Webpacker in favor of using the native webpack for bundling JavaScript.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For those who are not familiar, Webpacker is a Rails gem which is a wrapper around the webpack build system that provides a standard webpack configuration and reasonable defaults.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;steps-for-migrating-rails-6-react-to-rails-7-react&#34;&gt;Steps for migrating Rails 6 React to Rails 7 React&lt;/h3&gt;
&lt;p&gt;To migrate a Rails 6 React application to Rails 7 React, follow these steps:&lt;/p&gt;
&lt;h4 id=&#34;1-update-the-rails-gem-in-the-gemfile&#34;&gt;1. Update the Rails Gem in the Gemfile&lt;/h4&gt;
&lt;p&gt;In your application&amp;rsquo;s Gemfile, update the Rails gem version to Rails 7:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-gem &amp;#34;rails&amp;#34;, &amp;#34;~&amp;gt; 6.1.4&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+gem &amp;#34;rails&amp;#34;, &amp;#34;~&amp;gt; 7.0.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;2-upgrade-rails-packages&#34;&gt;2. Upgrade Rails packages&lt;/h4&gt;
&lt;p&gt;Upgrade the Rails packages using Yarn:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn upgrade @rails/actioncable --latest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn upgrade @rails/activestorage --latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;3-run-the-rails-update-task&#34;&gt;3. Run the Rails update task&lt;/h4&gt;
&lt;p&gt;Run the following command to initiate the Rails update task:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bin/rails app:update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This task guides you file by file to integrate the new Rails 7 defaults. Refer to the &lt;a href=&#34;https://guides.rubyonrails.org/upgrading_ruby_on_rails.html&#34;&gt;Rails documentation&lt;/a&gt; for detailed information on this update task.&lt;/p&gt;
&lt;h4 id=&#34;4-remove-webpacker&#34;&gt;4. Remove Webpacker&lt;/h4&gt;
&lt;p&gt;Since Webpacker is no longer the default in Rails 7, follow these steps to remove it:&lt;/p&gt;
&lt;p&gt;Remove the webpacker gem from your Gemfile:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-gem &amp;#39;webpacker&amp;#39;, &amp;#39;~&amp;gt; 4.0&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Remove the &lt;code&gt;webpacker.yml&lt;/code&gt; file and any other files associated with webpacker.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;bundle install&lt;/code&gt; to update the Gemfile.lock:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bundle install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;5-setting-up-webpack&#34;&gt;5. Setting up Webpack&lt;/h4&gt;
&lt;p&gt;To set up Webpack for your Rails 7 React application, follow these steps:&lt;/p&gt;
&lt;p&gt;Install webpack and other necessary libraries:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn install webpack webpack-cli @babel/core&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a webpack.config.js file at the root of your application:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// webpack.config.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; path = require(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; webpack = require(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;webpack&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Add other necessary plugins and configurations
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;module.exports = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// Webpack configuration options
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  output: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Make sure to use the path of the rails asset pipeline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    path: path.join(__dirname, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/app/assets/builds&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  module: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rules: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;// Add CSS/SASS/SCSS rule with loaders
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        test: &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/\.(?:sa|sc|c)ss$/i&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        use: [MiniCssExtractPlugin.loader, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;css-loader&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;sass-loader&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        test: &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/\.(png|jpe?g|gif|eot|woff2|woff|ttf|svg)$/i&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        use: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;file-loader&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        test: &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/\.(js|jsx)$/&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        exclude: &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/node_modules/&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        use: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          loader: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;babel-loader&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Add a .babelrc file for Babel configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;presets&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;@babel/preset-env&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;@babel/preset-react&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update the scripts section in your package.json:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;build&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;webpack&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;webpack --watch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;6-update-rails-asset-tags&#34;&gt;6. Update Rails asset tags&lt;/h4&gt;
&lt;p&gt;In your application views, update the asset tags from &lt;code&gt;stylesheet_pack_tag&lt;/code&gt; and &lt;code&gt;javascript_pack_tag&lt;/code&gt; to &lt;code&gt;stylesheet_link_tag&lt;/code&gt; and &lt;code&gt;javascript_include_tag&lt;/code&gt;, respectively:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;%= stylesheet_link_tag &amp;#39;application&amp;#39;, media: &amp;#39;all&amp;#39;, &amp;#39;data-turbolinks-track&amp;#39;: &amp;#39;reload&amp;#39; %&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;%= javascript_include_tag &amp;#39;application&amp;#39;, &amp;#39;data-turbolinks-track&amp;#39;: &amp;#39;reload&amp;#39; %&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;7-start-the-dev-server&#34;&gt;7. Start the dev server&lt;/h4&gt;
&lt;p&gt;Start the Rails development server with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rails server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then start the React development server with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn run dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By following these steps, we can take advantage of the new features and improvements in Rails 7 while continuing to leverage the power of React.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Integrating Laravel With a React Frontend</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2021/05/integrating-laravel-with-a-react-frontend/"/>
      <id>https://www.endpointdev.com/blog/2021/05/integrating-laravel-with-a-react-frontend/</id>
      <published>2021-05-07T00:00:00+00:00</published>
      <author>
        <name>Daniel Gomm</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2021/05/integrating-laravel-with-a-react-frontend/banner.jpg&#34; alt=&#34;&#34;&gt;
Photo by &lt;a href=&#34;https://unsplash.com/@scottwebb&#34;&gt;Scott Webb&lt;/a&gt; on &lt;a href=&#34;https://unsplash.com/photos/K8PXJMU2-3s&#34;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Frontend frameworks can be useful, and provide a lot of advantages over server-side rendering of views. It’s not uncommon now for websites to be purely presentational frontend applications. Thankfully &lt;a href=&#34;https://laravel.com/&#34;&gt;Laravel&lt;/a&gt; provides some helpers for including a dedicated frontend, including a fantastic npm package, laravel-mix, which heavily simplifies the use of webpack.&lt;/p&gt;
&lt;p&gt;In this article I’ll go over how to set up a new Laravel application to work with React as its frontend. While this article may focus on React, the main issues are the same regardless of framework. You’ll need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add your JavaScript application to the project’s file system and set up a build process for the frontend sources&lt;/li&gt;
&lt;li&gt;Write some additional code to bootstrap your frontend application once the page has loaded&lt;/li&gt;
&lt;li&gt;Carefully set up URL conventions to distinguish between frontend and backend routes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;scaffolding-the-frontend&#34;&gt;Scaffolding The Frontend&lt;/h3&gt;
&lt;p&gt;In a standard Laravel 8 application (created using &lt;code&gt;composer create-project laravel/laravel &amp;lt;NAME&amp;gt;&lt;/code&gt;), the frontend JS application is stored in the &lt;code&gt;/resources/js&lt;/code&gt; folder. Laravel provides a helper package called &lt;a href=&#34;https://packagist.org/packages/laravel/ui&#34;&gt;laravel/ui&lt;/a&gt;, which can be used to scaffold the frontend with many popular frameworks, including React. To scaffold an empty React application, you can run the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bat&#34; data-lang=&#34;bat&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;composer require laravel/ui
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php artisan ui react&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will add a new folder &lt;code&gt;resources/js/components/&lt;/code&gt; with a single file called Example.js in it, which contains a basic stateless functional component called &lt;code&gt;Example&lt;/code&gt;. It’ll also add a new line to &lt;code&gt;resources/js/app.js&lt;/code&gt; that requires the &lt;code&gt;Example&lt;/code&gt; component. Finally, &lt;code&gt;webpack.mix.js&lt;/code&gt; will be updated to include adding React in the build. I’ll go over what this file does in the next section.&lt;/p&gt;
&lt;h3 id=&#34;compiling-assets-with-laravel-mix&#34;&gt;Compiling Assets With Laravel Mix&lt;/h3&gt;
&lt;p&gt;Laravel Mix is an npm package that comes bundled with every Laravel application. It’s not Laravel specific though; you can add it to any application where you want a simple build process. It defines helpers for popular frameworks, React included. The &lt;code&gt;mix.react()&lt;/code&gt; helper automatically handles adding in Babel to support using JSX syntax.
For Laravel, the frontend build process is configured in &lt;code&gt;webpack.mix.js&lt;/code&gt;. By default, it includes some scaffolding code that gives you a general idea of how it can be used:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; mix = require(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;laravel-mix&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mix
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .js(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;resources/js/app.js&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;public/js&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .react()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .sass(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;resources/sass/app.scss&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;public/css&amp;#34;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To run this build process, use the &lt;code&gt;npm run dev&lt;/code&gt; command. This will use laravel-mix to compile everything specified in &lt;code&gt;webpack.mix.js&lt;/code&gt;. The output directory for the build is also specified there. You can also start a basic development server by running &lt;code&gt;php artisan serve&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This works just fine out of the box, but one thing worth noting is that by default, it’ll package all the code, including your dependencies, in the same file: &lt;code&gt;public/js/app.js&lt;/code&gt;. This will cause the entire dependency tree to be reloaded if you make even a single line change to your code. You can use the &lt;code&gt;mix.extract()&lt;/code&gt; helper to put the modules into a separate file, &lt;code&gt;public/js/vendor.js&lt;/code&gt;. This allows the browser to cache your dependencies, which won’t change too much, separately from your application, which will change much more often. Here’s how this looks in &lt;code&gt;webpack.mix.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mix
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .js(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;resources/js/app.js&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;public/js&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .react()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .extract([&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;react&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .sass(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;resources/sass/app.scss&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;public/css&amp;#34;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, to actually include your built JavaScript sources, go to &lt;code&gt;views/welcome.blade.php&lt;/code&gt; and add them in the header, in this order:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  . . .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- Include Frontend Application (webpack mix) --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/js/manifest.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/js/vendor.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/js/app.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;head&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The order is important because each successive script depends on the content of the previous one being defined.&lt;/p&gt;
&lt;p&gt;Notice that all the script tags have the &lt;code&gt;defer&lt;/code&gt; attribute added to them. This forces the browser to wait until the DOM has fully loaded in order to execute the scripts. If you don’t add the &lt;code&gt;defer&lt;/code&gt; attribute, you’ll end up with a blank screen when you try to load the application. This happens because the browser will, by default, run your scripts as soon as they’re loaded. And, when they’re in the head section, they get loaded before the body. So, if the script loads before the body, the root element of the React application won’t be in the DOM yet, which in turn causes the application to fail to load.&lt;/p&gt;
&lt;h3 id=&#34;handling-frontend-routing&#34;&gt;Handling Frontend Routing&lt;/h3&gt;
&lt;p&gt;The next roadblock to tackle for setting up the frontend is routing. If you’re planning to have the frontend do its own routing, you’ll need to make sure that the backend routes don’t clash with the frontend ones. You’ll also need to make sure that, for all routes that the backend doesn’t recognize, it falls back to rendering the layout page that bootstraps the frontend, and not a 404 page. If you fail to do the latter, nested frontend routes won’t work if you navigate to them directly, or refresh the page after navigating from the root URL.&lt;/p&gt;
&lt;p&gt;One way to ensure the routes don’t clash is to add a prefix like &lt;code&gt;/app/&lt;/code&gt; for web routes. API routes already have the &lt;code&gt;/api/&lt;/code&gt; prefix set up by default, and shouldn’t pose any issues. Then, since all frontend routes won’t be recognized by Laravel, we’ll want to add a fallback route. The fallback route ensures that &lt;code&gt;welcome.blade.php&lt;/code&gt;, which contains our root React component Example, gets rendered instead of a 404 error page for all frontend routes. We can do this by using Laravel’s &lt;code&gt;Route::fallback()&lt;/code&gt; function in &lt;code&gt;/routes/web.php&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Route::&lt;span style=&#34;color:#369&#34;&gt;fallback&lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; view(welcome);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Make sure you add this at the very bottom of &lt;code&gt;/routes/web.php&lt;/code&gt;, so that it’s the last route registered by your application. This is recommended by the Laravel docs and is also good practice since this route should be the last possible route to match any given URL.&lt;/p&gt;
&lt;h3 id=&#34;csrf-tokens&#34;&gt;CSRF Tokens&lt;/h3&gt;
&lt;p&gt;One other thing that’s important to mention is that by default Laravel has built-in features for generating and verifying CSRF tokens. This is set up in the &lt;code&gt;VerifyCsrfToken&lt;/code&gt; middleware class that comes bundled with a fresh application. It provides nice and easy helpers for Blade pages like &lt;code&gt;@csrf&lt;/code&gt; to ease adding this to your forms as a hidden input. However, if you’re making forms outside of Blade in React, you might receive an error page that says &lt;strong&gt;419 Page Expired&lt;/strong&gt; when you try to submit a form or send a request:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/05/integrating-laravel-with-a-react-frontend/419-page-expired.jpg&#34; alt=&#34;419 Page Expired Error&#34;&gt;&lt;/p&gt;
&lt;p&gt;This error happens for both vanilla HTML forms, and when sending a POST request via JavaScript, depending on the library being used. For example, I’ve encountered this issue when using &lt;strong&gt;jQuery&lt;/strong&gt;, but not &lt;strong&gt;axios&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You can handle this in a few different ways. The easiest way is to simply add an exception for this route in your &lt;code&gt;VerifyCsrfToken&lt;/code&gt; class:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;VerifyCsrfToken&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;extends&lt;/span&gt; Middleware
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * The URIs that should be excluded from CSRF verification.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @var array
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$except&lt;/span&gt; = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/my-route&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, this removes CSRF protection entirely and in most cases, you’ll want the CSRF protection in your forms. This can be done by setting either &lt;code&gt;X-XSRF-TOKEN&lt;/code&gt; or &lt;code&gt;X-CSRF-TOKEN&lt;/code&gt; request headers, and also by adding a &lt;code&gt;_token&lt;/code&gt; property to the request parameters containing the CSRF token. It’s important to note that these similarly named values are not the same thing. The &lt;strong&gt;XSRF&lt;/strong&gt; token is just an encrypted version of the actual &lt;strong&gt;CSRF&lt;/strong&gt; token. Laravel 8 always sets the &lt;code&gt;XSRF-TOKEN&lt;/code&gt; cookie in the response headers by default:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/05/integrating-laravel-with-a-react-frontend/xsrf-token-cookie.jpg&#34; alt=&#34;XSRF-TOKEN Cookie&#34;&gt;&lt;/p&gt;
&lt;p&gt;This means that &lt;code&gt;XSRF-TOKEN&lt;/code&gt; is defined in &lt;code&gt;document.cookie&lt;/code&gt; when the page loads. By default, &lt;strong&gt;axios&lt;/strong&gt; (which is included with your new Laravel application) automatically looks for this value in the cookie, and adds it to the request headers.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;And that’s it! I’ve found Laravel works pretty well with a dedicated frontend once you get the initial setup out of the way. Have any questions? Feel free to leave a comment!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>React: Style Tips</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/09/react-style-tips/"/>
      <id>https://www.endpointdev.com/blog/2019/09/react-style-tips/</id>
      <published>2019-09-28T00:00:00+00:00</published>
      <author>
        <name>Zed Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2019/09/react-style-tips/image-0.jpg&#34; alt=&#34;Icon design&#34; /&gt;&lt;br&gt;Photo by &lt;a href=&#34;https://unsplash.com/photos/_zKxPsGOGKg&#34;&gt;Harpal Singh&lt;/a&gt; on Unsplash&lt;/p&gt;
&lt;p&gt;I’ve worked on a couple of large React projects over the last few years. In my experience, one of the trickiest parts of getting a React project up and running is figuring out how you want to visually style your application in the browser, so I’ll share in this post some of the ways I’ve styled my projects.&lt;/p&gt;
&lt;h3 id=&#34;css-modules&#34;&gt;CSS Modules&lt;/h3&gt;
&lt;p&gt;Libraries like Material-UI (which I’ll discuss next) do a lot of the work of styling for you. However, sometimes you’ll still need to define styles unique to your project, and the most common way is with CSS.&lt;/p&gt;
&lt;p&gt;For projects created with &lt;a href=&#34;https://github.com/facebook/create-react-app&#34;&gt;create-react-app&lt;/a&gt;, any CSS you include in a React project isn’t scoped. This means that if you define a class &lt;code&gt;tall&lt;/code&gt; in one component that has a height of 40 pixels and a class &lt;code&gt;tall&lt;/code&gt; in another component with a height of 80 pixels, one of your rules will overwrite the other—whichever makes it into the compiled CSS file last. However, webpack allows you to use CSS modules, which restrict your CSS rules to components that explicitly import them. It took me a long time to figure out how to use them due to lack of relevant documentation, but eventually I discovered a very easy way to do it.&lt;/p&gt;
&lt;p&gt;If your file structure looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.css&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It’s as simple as renaming your CSS file like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.module.css&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using the suffix &lt;code&gt;.module.css&lt;/code&gt; tells create-react-app that the rules within should be scoped only for where they’re imported. They can be used like other styles by importing and passing the classes like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import styles from &amp;#39;./App.module.css&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export default function Component(props) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  return &amp;lt;div className={styles.myClass} /&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;material-ui-and-similar-libraries&#34;&gt;Material-UI and similar libraries&lt;/h3&gt;
&lt;p&gt;There are many different design philosophies for web, but probably the most popular is Google’s &lt;a href=&#34;https://material.io/design/&#34;&gt;Material Design&lt;/a&gt;. Material Design lays out some rules that help keep a user interface uncluttered, intuitive, and pleasant to use. However, jumping into the guidelines on Google’s website can be very intimidating. In addition, manually defining CSS for your web application is a lot of work. There are several different libraries that offer solutions to this, my favorite being &lt;a href=&#34;https://material-ui.com/&#34;&gt;Material-UI&lt;/a&gt;. Material-UI provides a set of components that you can reuse to put your application together.&lt;/p&gt;
&lt;p&gt;Here’s a simple example showing different styles of text fields:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; TextField from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;@material-ui/core/TextField&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; TextFieldDemo(props) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  render() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;form&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;TextField
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          label=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          value={values.name}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          onChange={handleChange(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;TextField
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          label=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          value={values.name}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          onChange={handleChange(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          variant=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;outlined&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;TextField
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          label=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          value={values.name}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          onChange={handleChange(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          variant=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;filled&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;/form&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And here’s what that looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/09/react-style-tips/image-1.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;vanilla-css-with-material-ui&#34;&gt;Vanilla CSS with Material-UI&lt;/h3&gt;
&lt;p&gt;It’s also important to note that Material-UI’s preferred way of defining additional styles is using &lt;a href=&#34;https://cssinjs.org/&#34;&gt;CSSinJS&lt;/a&gt; rather than plain CSS. Given the following CSS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;: --theme-spacing
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;input&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You would instead use the following JSS object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  button: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    margin: theme.spacing(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  input: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    display: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;none&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using the styles in your project is mostly the same after that, but I won’t go into detail about that here. CSSinJS has some advantages (which you can read about in the &lt;a href=&#34;https://material-ui.com/styles/basics/&#34;&gt;Material-UI documentation&lt;/a&gt; as well as on the &lt;a href=&#34;https://cssinjs.org&#34;&gt;CSSinJS website&lt;/a&gt;), but I prefer vanilla CSS. It’s not immediately obvious from their site, but you can still use vanilla CSS as well as CSS modules with Material-UI, and setting it up is pretty simple.&lt;/p&gt;
&lt;p&gt;First, you need to make sure that your CSS is injected before styles included with Material-UI. There are two steps to making this work: first, you define an injection point for your CSS by adding an element to your index.html at the injection point:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;noscript id=&amp;#34;jss-insertion-point&amp;#34; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, you wrap the entire application in the &lt;code&gt;StylesProvider&lt;/code&gt; component with a prop named &lt;code&gt;injectFirst&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import { StylesProvider } from &amp;#39;@material-ui/styles&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;class App extends Component {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  render() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    return (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;StylesProvider injectFirst&amp;gt;...&amp;lt;/StylesProvider&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, your imported CSS will take predence over the styles provided by Material-UI, so you can still use vanilla CSS if you like!&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;These methods have worked great for me, but they’re certainly not the only way to do things. Leave a comment if you’ve found a library you like, or have an approach you recommend!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Campendium: A Responsive, Fancy Detail Page</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/09/campendium-detail-page/"/>
      <id>https://www.endpointdev.com/blog/2019/09/campendium-detail-page/</id>
      <published>2019-09-09T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2019/09/campendium-detail-page/banner.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;This week, I was very excited to deploy a project for &lt;a href=&#34;https://www.campendium.com/&#34;&gt;Campendium&lt;/a&gt;, one of our long-time clients. As noted in &lt;a href=&#34;/blog/2019/08/campendium-updates/&#34;&gt;my recent post on Campendium updates for the year&lt;/a&gt;, Campendium has thousands of listings of places to camp and provides a great infrastructure for the development of a rich community of travelers around North America.&lt;/p&gt;
&lt;p&gt;For the past few months, I’ve been working on a significant update to Campendium’s campground detail page, the page template where in-depth information is provided for each of Campendium’s locations. This is equivalent to a product detail page on an ecommerce site.&lt;/p&gt;
&lt;p&gt;The “guts” of the update included a new detail page design with expanded responsiveness, the introduction of 360° videos, and expanded user driven content in the form of Question &amp;amp; Answer (Q&amp;amp;A or QnA), reviews, notes, nightly rates, etc. Read on to find out more and see video examples of several of the features!&lt;/p&gt;
&lt;h3 id=&#34;user-interface--responsiveness-updates&#34;&gt;User Interface &amp;amp; Responsiveness Updates&lt;/h3&gt;
&lt;p&gt;One of the things the Campendium team and I are most proud of here is the responsiveness of the new design. In the case of traveling and camping, responsiveness is important since a large amount of traffic comes from mobile devices, relative to what you might see in other industries.&lt;/p&gt;
&lt;p&gt;User images are shown as “hero images” and the user interface updates depending on the browser device and width, as shown in the following videos for &lt;a href=&#34;https://www.campendium.com/gilbert-ray-campground&#34;&gt;Gilbert Ray Campground&lt;/a&gt; and &lt;a href=&#34;https://www.campendium.com/cayuga-lake-state-park&#34;&gt;Cayuga Lake State Park&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&#34;text-align:center;font-weight:bold;&#34;&gt;&lt;iframe src=&#34;https://drive.google.com/file/d/1FFF8GcztnV-KGaJ4pjDYixCbkxw6kduu/preview&#34; width=&#34;770&#34; height=&#34;450&#34;&gt;&lt;/iframe&gt;A preview of responsive behavior on the campground detail page with user submitted photos.&lt;/p&gt;
&lt;p style=&#34;text-align:center;font-weight:bold;&#34;&gt;&lt;iframe src=&#34;https://drive.google.com/file/d/1caQZT9ogh_piuTX2UDIvWGEBZse0zwnx/preview&#34; width=&#34;770&#34; height=&#34;450&#34;&gt;&lt;/iframe&gt;A second preview of responsive behavior on the campground detail page with embedded maps.&lt;/p&gt;
&lt;p&gt;Another updated design usability tweak was a sticky navigation bar to navigation throughout the page, which can get especially long with user submitted content. See how the “Overview”, “Video”, etc. links become sticky as you scroll down on the page, and the current region coming into view of the page is underlined:&lt;/p&gt;
&lt;p style=&#34;text-align:center;font-weight:bold;&#34;&gt;&lt;iframe src=&#34;https://drive.google.com/file/d/1w_MjP_HUXntYXHTG6FeREtMWwhKv4KgG/preview&#34; width=&#34;770&#34; height=&#34;450&#34;&gt;&lt;/iframe&gt;Navigation becomes fixed to the top of the browser as a user scrolls through the content.&lt;/p&gt;
&lt;p&gt;Campendium uses Ruby on Rails as a backend, a bit of &lt;a href=&#34;https://getbootstrap.com/&#34;&gt;Bootstrap&lt;/a&gt;, and &lt;a href=&#34;https://sass-lang.com/&#34;&gt;Sass&lt;/a&gt; and best practice responsive design is used throughout this updated user interface.&lt;/p&gt;
&lt;h3 id=&#34;360-videos&#34;&gt;360° Videos&lt;/h3&gt;
&lt;p&gt;The Campendium team has been hard at work creating 360 degree videos of the various locations to provide significant value to their users. These videos are now embedded into the campground detail page. Video hosting is provided by YouTube and dropped into the Campendium campground HTML template.&lt;/p&gt;
&lt;p style=&#34;text-align:center;font-weight:bold;&#34;&gt;&lt;iframe src=&#34;https://drive.google.com/file/d/12XEu-95diRRMjlqb28jD0xdj9qIWXSb7/preview&#34; width=&#34;770&#34; height=&#34;450&#34;&gt;&lt;/iframe&gt;A video in a video—a 360 degree video example.&lt;/p&gt;
&lt;p&gt;I personally think these 360° videos are awesome, especially to those visual learners out there! You can learn so much from a video that can be hard to capture in user reviews.&lt;/p&gt;
&lt;h3 id=&#34;community-qa&#34;&gt;Community Q&amp;amp;A&lt;/h3&gt;
&lt;p&gt;Another new feature with this deploy is the introduction of community driven Question &amp;amp; Answer. Users can submit questions about a campground, and users who have contributed to this campground are invited to respond (or they can opt-out site-wide to responding to questions). In addition to Q&amp;amp;A itself, user content can be “upvoted” (marked as Helpful) or flagged for an improved user content browsing experience.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/09/campendium-detail-page/community.png&#34; alt=&#34;Campendium community in Question &amp;amp; Answer&#34;&gt;&lt;/p&gt;
&lt;p&gt;All Q&amp;amp;A functionality is driven by JavaScript coupled with the Ruby on Rails backend.&lt;/p&gt;
&lt;h3 id=&#34;expansion-of-user-contributed-content-and-features&#34;&gt;Expansion of User Contributed Content and Features&lt;/h3&gt;
&lt;p&gt;Finally, this update includes expansion of user contributed content in addition to Q&amp;amp;A. This includes the ability for users to contribute notes, cell signal reports, and nightly rates. Reviews can now be filtered by user profile information and sorted by date or specific ranking. Reviews can also be searched by keywords and those keywords highlighted in the results. The following video demonstrates sorting and searching of reviews with highlighted keyword match:&lt;/p&gt;
&lt;p style=&#34;text-align:center;font-weight:bold;&#34;&gt;&lt;iframe src=&#34;https://drive.google.com/file/d/1G2KGfxCkOmuJm-AJE8BPXUC-OWdw1iQS/preview&#34; width=&#34;770&#34; height=&#34;450&#34;&gt;&lt;/iframe&gt;Review searchability with highlighting and filterability.&lt;/p&gt;
&lt;p&gt;All search functionality driven by JavaScript on the frontend, and a Ruby on Rails backend coupled with &lt;a href=&#34;https://github.com/sunspot/sunspot&#34;&gt;Sunspot&lt;/a&gt; and &lt;a href=&#34;https://lucene.apache.org/solr/&#34;&gt;Solr&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;who-doesnt-love-stats&#34;&gt;Who Doesn’t Love Stats?&lt;/h3&gt;
&lt;p&gt;Just for the sake of sharing stats, from GitHub, this update included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;215 changed files&lt;/li&gt;
&lt;li&gt;6,284 additions&lt;/li&gt;
&lt;li&gt;3,924 deletions (removal / cleanup of unneeded JavaScript files)&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Campendium v2019: A Summary of Recent Updates</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/08/campendium-updates/"/>
      <id>https://www.endpointdev.com/blog/2019/08/campendium-updates/</id>
      <published>2019-08-05T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;p&gt;This year has brought a handful of exciting changes for &lt;a href=&#34;https://www.campendium.com/&#34;&gt;Campendium&lt;/a&gt;, one of End Point’s long-time clients, by yours truly. Created by campers for campers, Campendium has thousands of listings of places to camp, from swanky RV parks to free remote destinations, vetted by a team of full-time travelers and reviewed by over 200,000 members. I thought I would take some time to summarize these recent updates.&lt;/p&gt;
&lt;h3 id=&#34;maps-and-clustering&#34;&gt;Maps and Clustering&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/08/campendium-updates/map-clusters.png&#34; alt=&#34;Campendium map clustering of campground locations&#34;&gt;&lt;/p&gt;
&lt;p&gt;Campendium uses &lt;a href=&#34;https://www.mapbox.com/&#34;&gt;Mapbox&lt;/a&gt; for map rendering to display campgrounds and locations throughout North America. One of the new features added this year was &lt;a href=&#34;https://docs.mapbox.com/mapbox-gl-js/example/cluster/&#34;&gt;clustering&lt;/a&gt; of campground locations, where campgrounds are grouped together and presented in a “cluster” with a size relative to how many campgrounds are in the cluster.&lt;/p&gt;
&lt;p&gt;If a user is searching for campgrounds in a broad location, they can see where campgrounds might be more densely grouped by location. Once a user zooms in zoom in a couple of clicks, the campgrounds are no longer clustered and individual campgrounds locations can be seen. While working on this update, we spent a good amount of our time tweaking and troubleshooting the optimal clustering behavior to provide the most benefit to those searching for a campground. &lt;a href=&#34;https://docs.mapbox.com/mapbox-gl-js/api/&#34;&gt;Mapbox GL JS&lt;/a&gt; works in parallel with &lt;a href=&#34;https://reactjs.org/&#34;&gt;ReactJS&lt;/a&gt;, and runs with a Ruby on Rails back-end.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/08/campendium-updates/map-non-clusters.jpg&#34; alt=&#34;Campendium map non-clustering of campground locations after zooming in&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;advanced-filtering&#34;&gt;Advanced Filtering&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/08/campendium-updates/map-filtering.jpg&#34; alt=&#34;Campendium advanced filtering&#34;&gt;&lt;/p&gt;
&lt;p&gt;Another exciting was the introduction of advanced filtering in the search interface, presented in combination with map display. Users can filter campgrounds by category (e.g. Public Land, RV Parking, Parking, Dump Station), filter by price (with a slider), hookups, campground policy (e.g. age or pet restrictions), discounts, recreation, and facilities. All of this search filtering is driven by &lt;a href=&#34;https://github.com/sunspot/sunspot&#34;&gt;Sunspot&lt;/a&gt;, a Ruby on Rails gem for working with the popular &lt;a href=&#34;https://lucene.apache.org/solr/&#34;&gt;Solr&lt;/a&gt; search engine. Results can be sorted by user provided reviews, price or distance from a specific GPS location. Here, much care was given to provide the best user interface for presenting this valuable functionality.&lt;/p&gt;
&lt;h3 id=&#34;supporters-only-features&#34;&gt;“Supporters Only” Features&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/08/campendium-updates/supporters.jpg&#34; alt=&#34;Campendium Supporters only, Subscriptions&#34;&gt;&lt;/p&gt;
&lt;p&gt;Another recent update to Campendium includes functionality to offer user subscriptions. Registered users can sign up to support Campendium on a monthly or annual basis, and subscriptions are set to auto-renew at the end of their subscription period. This paid support hides advertisements throughout the site (advertisements are controlled by a third party), and advanced filtering on cell reception. There are plans to expand supporter features in the future. Ruby on Rails combined with &lt;a href=&#34;https://stripe.com/docs/stripe-js/reference&#34;&gt;StripeJS&lt;/a&gt; is used to manage subscription payments, and Ruby on Rails also serves as a backend for &lt;a href=&#34;https://developer.apple.com/in-app-purchase/&#34;&gt;In-App Purchases&lt;/a&gt; of subscriptions from the App store.&lt;/p&gt;
&lt;h3 id=&#34;always-responsive-and-latency-aware&#34;&gt;Always Responsive and Latency-Aware&lt;/h3&gt;
&lt;p&gt;Because a large portion of the Campendium visitors are on the road, it’s important to have both a responsive design and to build for bandwidth limitations for users. Throughout the development of these new features, responsive and mobile friendly designs were implemented leveraging &lt;a href=&#34;https://sass-lang.com/&#34;&gt;Sass&lt;/a&gt;, sometimes requiring help from the rest of the knowledgeable &lt;a href=&#34;/team/&#34;&gt;End Point team&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Many of the pages throughout the site are fully cached including the homepage, search result pages, and campground detail page, and cookies are used to indicate user status. In some cases, user submitted campground images are lazy-loaded to mitigate bandwidth limitations.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/08/campendium-updates/mobile.jpg&#34; alt=&#34;Mobile, responsive design for Campendium&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;whats-next&#34;&gt;What’s Next?&lt;/h3&gt;
&lt;p&gt;While I didn’t go into much technical depth on these updates, I am happy that the updates represent a broad spectrum of full-stack development skills featuring nginx, Ruby on Rails, 3rd party integration including StripeJS, MapboxGL and IAP (Apple), a JavaScript framework with ReactJS, and working with Ruby gems to leverage other tools, for example, Solr (Sunspot) and Sass.&lt;/p&gt;
&lt;p&gt;In the future, Campendium plans to continue using these tools to see a more interactive, social campground detail page, and has plans to expand outside of North America. You can visit Campendium &lt;a href=&#34;https://www.campendium.com/&#34;&gt;here&lt;/a&gt;, or find them on Instagram &lt;a href=&#34;https://www.instagram.com/campendium/?hl=en&#34;&gt;here&lt;/a&gt; to follow their exciting announcements!&lt;/p&gt;

      </content>
    </entry>
  
</feed>
