{"id":55764,"date":"2022-11-10T10:22:27","date_gmt":"2022-11-10T04:52:27","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=55764"},"modified":"2022-12-30T12:33:49","modified_gmt":"2022-12-30T07:03:49","slug":"progressively-decoupled-app-with-react-on-drupal","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/progressively-decoupled-app-with-react-on-drupal\/","title":{"rendered":"Progressively Decoupled App With React on Drupal"},"content":{"rendered":"<h1>Decoupled Architecture<\/h1>\n<p>To understand the term \u201cDecoupled\u201d we need to understand what \u201cCoupled\u201d is. A coupled (also known as \u201ctraditional\u201d or \u201cmonolithic\u201d) CMS knits together the front- and back-ends. Working off the same application, developers and content managers make adjustments to the back-end while users interact with the front-end, but both are experiencing, viewing, and interacting with the same system.<\/p>\n<p>While in a decoupled CMS, the front-end and back-end are separated. The CMS handles the back-end, and a delivery system handles the front with an application programming interface (API) that connects them for publishing.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-56274 size-medium\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/12\/drupalCoupledecouple-300x134.png\" alt=\"\" width=\"300\" height=\"134\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/12\/drupalCoupledecouple-300x134.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/12\/drupalCoupledecouple-624x278.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/12\/drupalCoupledecouple.png 720w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<h1>Introduction to React &amp; Drupal<\/h1>\n<h2>React JS<\/h2>\n<p>React is a JavaScript library for building user interfaces. Started in 2013, React has quickly grown in popularity due to its declarative style and lack of assumptions about your technology stack. In the last few years, a large ecosystem has grown around React. This includes high-quality libraries, conferences, and increased demand for developers with React skills.<\/p>\n<h2>Drupal<\/h2>\n<p>Drupal is an open-source content management system with robust tools for modeling data, implementing editorial workflows, and coding custom application logic. There is also excellent support for JSON API or GraphQL web services, making it a good choice as the backend for your React application.<\/p>\n<p>With a multitude of benefits, ReactJS has become a popular front-end framework. Unfortunately, embedding React into a Drupal site is not straightforward. In this article, I hope to show you one relatively simple method of how to do so.<\/p>\n<p>The method I will demonstrate in this article makes a few assumptions that you know Drupal. Drupal 8\/9 is already installed at your local. I won\u2019t be demonstrating how to use React for a headless Drupal experience. Instead, I\u2019ll be demonstrating what has been called a loosely-decoupled experience. This method\u2019s approach will render your React app within a Drupal block. Another assumption is that we have a way of detecting our local environment. My example is one way, but there are other ways of doing this.<\/p>\n<p>Let\u2019s dig deeper into the technical details of how progressively decoupled apps can be created using React on a Drupal 8\/9 website.<\/p>\n<h3>Why Opt For This Approach<\/h3>\n<p>With the increasing popularity of ReactJS, JavaScript libraries and frameworks prove to be useful in building complex applications by seamlessly getting embedded on a Drupal site, thus combining the robustness of an API-first CMS with a slick and quick React frontend to collectively give way to amazing digital experiences along with future-proof builds.<\/p>\n<h3>Don\u2019t Use create-react-app<\/h3>\n<p>If you\u2019re unfamiliar with create-react-app, it is a nice tool that generates scaffolding for a React application. It is also not great for building to React blocks that you plan to embed in Drupal since these React applications are less complex. For instance, you do not need the public folder that create-react-app provides, nor do you need many of its dependencies. Some of these can interfere with being able to use React developer tools and can cause other confusion too.<\/p>\n<h3>What to do<\/h3>\n<p>It is not very difficult to generate your react project with just the dependencies you need. First, decide where your React component will live in your codebase. I usually put it into a custom module because we need to write server-side code to embed the component. You could also put the React component into the theme.<\/p>\n<h4>What follows is a step-by-step method for creating a React app and integrating it to a Drupal custom module.<\/h4>\n<h2>Step 1 : Create a custom module in Drupal<\/h2>\n<p>In your custom module folder (usually web\/modules\/custom) create a new folder for the custom module. Let&#8217;s call it\u00a0react_example.<br \/>\nIn the new folder, add an info.yml file to register your module. Since our module is\u00a0react_example, this will be named\u00a0react_example.info.yml.<br \/>\nPopulate your\u00a0info.yml\u00a0file with at least the minimum information. Here&#8217;s an example:<\/p>\n<div style=\"color: black:;\">\n<pre>name: 'React Example App'\r\n\r\ntype: module\r\n\r\ndescription: 'React framework for Drupal 9.'\r\n\r\ncore_version_requirement: ^8.8.0 || ^9.0\r\n\r\npackage: 'React'<\/pre>\n<\/div>\n<h2>Step 2 : Create a basic react app<\/h2>\n<p>Now create js\/react\/ folder in this custom react_example module. I usually make a js\/react\/appname folder. Do this as you see fit, and move to that folder using the CLI. Then, let\u2019s get started by initializing a new project.<\/p>\n<div style=\"color: black:;\">\n<pre>npm init<\/pre>\n<\/div>\n<p>This will generate a basic package.json and some scaffolding.<\/p>\n<p>Next, you\u2019ll want to set a node version. For this, I recommend nvm. You probably want the latest stable version of node.<\/p>\n<div style=\"color: black:;\">\n<pre>npm install node\r\n\r\nnode -v &gt; .nvmrc<\/pre>\n<\/div>\n<p>Now it\u2019s time to install the required packages. Here is a summary of what you\u2019ll need:<\/p>\n<table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Package name<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">ID<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">Description<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">Dependency Type<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Babel Core<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">@babel\/core<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">Babel is a JavaScript transpiler that converts the JavaScript that you write (e.g. React) into JavaScript that can run in any browser.<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">dev<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Babel CLI<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">@babel\/cli<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">CLI package for Babel.<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">dev<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Babel Preset Env<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">@babel\/preset-env<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">The basic Babel JavaScript transpilation package<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">dev<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Babel Preset React<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">@babel\/preset-react<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">Babel transpilation for React JavaScript<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">dev<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Babel Loader<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">babel-loader<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">Allows webpack to use Babel as a transpiler.<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">dev<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Webpack<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">webpack<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">A tool for bundling JavaScript so that a browser can use it.<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">dev<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">Webpack CLI<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">webpack-cli<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">Allows npm to run webpack commands<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">dev<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">React<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">react<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">The React JavaScript library<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">prod<\/span><\/td>\n<\/tr>\n<tr valign=\"top\">\n<td width=\"84\"><span style=\"color: #2c2c3e;\">React Dom<\/span><\/td>\n<td width=\"99\"><span style=\"color: #2c2c3e;\">react-dom<\/span><\/td>\n<td width=\"363\"><span style=\"color: #2c2c3e;\">The entry point to the DOM for React<\/span><\/td>\n<td width=\"96\"><span style=\"color: #2c2c3e;\">prod<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Dependency type refers to whether the module is needed for the actual production build that end users will be interacting with.<\/p>\n<p>To install these packages, start with dev dependencies:<\/p>\n<div style=\"color: black:;\">\n<pre>npm install --save-dev @babel\/cli @babel\/core @babel\/cli @babel\/preset-env @babel\/preset-react babel-loader webpack webpack-cli<\/pre>\n<\/div>\n<p>Then, install production dependencies<\/p>\n<div style=\"color: black:;\">\n<pre>npm install react react-dom<\/pre>\n<\/div>\n<h2>Step 3: Add a webpack config<\/h2>\n<p>If you\u2019ve worked with React before, you\u2019ve likely used webpack to build your project. The webpack config needed here is pretty basic:<\/p>\n<div>\n<pre>const path = require('path');\r\nconst config = {\r\n  entry: '.\/src\/index.js',\r\n  devtool: (process.env.NODE_ENV === 'production') ? false : 'inline-source-map',\r\n  mode: (process.env.NODE_ENV === 'production') ? 'production' : 'development',\r\n  output: {\r\n    path: path.resolve(__dirname, 'dist'),\r\n    filename: 'app.bundle.js'\r\n  },\r\n  module: {\r\n    rules: [\r\n      {\r\n         test: \/\\.js$\/,\r\n         exclude: \/(node_modules)\/,\r\n         use: {\r\n           loader: 'babel-loader'\r\n         }\r\n      }\r\n   ]\r\n },\r\n};\r\n\r\nmodule.exports = config;<\/pre>\n<\/div>\n<p>This goes in a file called webpack.config.js. I\u2019ll explain the important parts:<\/p>\n<p><strong>Entry<\/strong> : In webpack, the entry point is the file that imports all of your other packages, at the top of your application\u2019s tree. If you\u2019re dealing with React, this is the file where you use react-dom to attach your react script to a DOM element.<\/p>\n<p><strong>Devtool<\/strong> : We tell the bundle to use a source map based on whether we\u2019re doing a production or development build. This bloats the bundle a lot, so you don\u2019t want to add a source map to the prod build. The NODE_ENV comparison comes into play later when we have npm run our webpack script.<\/p>\n<p><strong>Output<\/strong> : The path to your bundle, containing the whole app (e.g., all the React components and imports you need). Usually, this is in a \u201cdist\u201d folder.<\/p>\n<p><strong>Module<\/strong> : This tells webpack to use babel for transpiling your JS so that the browser can run React.<\/p>\n<p>There are\u00a0two things you need to do:<\/p>\n<h3>Set up your scripts<\/h3>\n<p>You\u2019ll need to add the following to the top level of package.json:<\/p>\n<div>\n<pre>\"scripts\": {\r\n\"build\": \"NODE_ENV=production webpack\",\r\n\"watch\": \"webpack --watch --progress\"\r\n},<\/pre>\n<\/div>\n<p>This tells webpack to either do a development (watch) or a production (build) build. As we noted earlier, we use an environment variable to establish whether to use a source map (which bloats the package but facilitates debugging).<\/p>\n<h3>Set up Babel<\/h3>\n<p>Another role that package.json plays is to let you configure how Babel works. You have to add this:<\/p>\n<div>\n<pre>\"babel\": {\r\n\r\n\"presets\": [\r\n\r\n[\r\n\r\n\"@babel\/preset-env\",\r\n\r\n{\r\n\r\n\"targets\": {\r\n\r\n\"browsers\": [\r\n\r\n\"IE &gt;= 11\",\r\n\r\n\"last 3 versions\"\r\n\r\n]\r\n\r\n}\r\n\r\n}\r\n\r\n],\r\n\r\n\"@babel\/preset-react\"\r\n\r\n]<\/pre>\n<\/div>\n<h2>Step 5 : Build a \u201cHello World\u201d React App<\/h2>\n<p>Below is a simple React app that will let you test things. Put this in src\/index.js:<\/p>\n<div>\n<pre>import React from 'react';\r\n\r\nimport { render } from 'react-dom';\r\n\r\nconst Root = () =&gt; {\r\n\r\nreturn (\r\n\r\n&lt;&gt;Hi there&lt;\/&gt;\r\n\r\n)\r\n\r\n}\r\n\r\nrender(&lt;Root\/&gt;, document.querySelector('#my-app-target'));<\/pre>\n<\/div>\n<h2>Step 6 : Define a library for React app in Drupal<\/h2>\n<p>In our react_example module, create a react_example.libraries.yml file with this content:<\/p>\n<div>\n<pre>my-app:\r\n\r\nversion: 1.x\r\n\r\njs:\r\n\r\njs\/react\/my-app\/dist\/app.bundle.js: { minified: true }<\/pre>\n<\/div>\n<p>We have multiple ways to attach this library in drupal, which is mentioned in step 7.<\/p>\n<h2>Step 7 (A): Include on twig template<\/h2>\n<p>Include the React app\u2019s target markup on a page \/ Include the React app\u2019s Drupal library on a page<\/p>\n<p>This will let us load the library in an #attached property or in a Twig template.<\/p>\n<p>There are quite a few ways to do this. I think the absolute simplest way is to put the following in the twig template where you want to load your React app:<\/p>\n<div>\n<pre>{{ attach_library('react_example\/my-react-app') }}\r\n\r\n&lt;div id=\"my-app-target\"&gt;&lt;\/div&gt;<\/pre>\n<\/div>\n<p>If we do this, the React app will put itself within the my-app-target div.<\/p>\n<h2>Step 7 (B): Include on the form element<\/h2>\n<p>You can also use a render array to embed the app if you want to do things from a form alter for instance:<\/p>\n<div>\n<pre>$form['my_react_app'] = [\r\n\r\n  '#markup'=&gt; '&lt;div id=\"my-app-target\"&gt;&lt;\/div&gt;',\r\n\r\n  '#attached'=&gt; [\r\n\r\n    'library'=&gt; [\r\n\r\n      'mymodule\/my-react-app'\r\n\r\n    ],\r\n\r\n  ],\r\n\r\n];<\/pre>\n<\/div>\n<h2>Step 7 (C): Create a custom block<\/h2>\n<p>Let&#8217;s start by creating a file in our custom module at\u00a0src\/Plugin\/Block\/ReactExampleBlock.php<br \/>\nIn the build method of our block class, we will create an empty container with the default ID (root) for mounting the React app. To that container, we&#8217;ll attach our custom library.<\/p>\n<div>\n<pre>&lt;?php\r\n\r\nnamespace Drupal\\react_example\\Plugin\\Block;\r\n\r\nuse Drupal\\Core\\Block\\BlockBase;\r\n\r\n\/**\r\n\r\n* Provides a 'ReactExampleBlock' block.\r\n\r\n*\r\n\r\n* @Block(\r\n\r\n* id = \"react_example_block\",\r\n\r\n* admin_label = @Translation(\"React Example Block\"),\r\n\r\n* )\r\n\r\n*\/\r\n\r\nclass ReactExampleBlock extends BlockBase {\r\n\r\n\/**\r\n\r\n* {@inheritdoc}\r\n\r\n*\/\r\n\r\npublic function build() {\r\n\r\n$build = [];\r\n\r\n$build[] = [\r\n\r\n'#type'=&gt; 'container',\r\n\r\n'#attributes'=&gt; [\r\n\r\n'id'=&gt; 'root',\r\n\r\n],\r\n\r\n'#attached'=&gt; [\r\n\r\n'library'=&gt; [\r\n\r\n'react_example\/react_example_dev',\r\n\r\n],\r\n\r\n],\r\n\r\n];\r\n\r\nreturn $build;\r\n\r\n}\r\n\r\n}<\/pre>\n<\/div>\n<p>At this point, you should be able to add your new block to a page and see the default content, saying &#8220;Edit\u00a0src\/App.js\u00a0and save to reload.&#8221; If you see this message, you&#8217;ve successfully attached the React app to your Drupal block and can continue development.<\/p>\n<h2>Step 8: Run npm<\/h2>\n<p>If you are following this as a tutorial, this is a good time to test things out. First, let\u2019s test a production build:<\/p>\n<p>Run the below command in your react app<\/p>\n<div>\n<pre>npm run watch<\/pre>\n<\/div>\n<p>OR<\/p>\n<div>\n<pre>npm run build<\/pre>\n<\/div>\n<p>In the browser, load the page that is running your twig template or block from the 7 step. You should see the \u201cHi there\u201d text in the target div.<\/p>\n<h2>Conclusion<\/h2>\n<p>I hope this post has helped you add an embedded Progressively Decoupled React App to your Drupal 8\/9 site!<\/p>\n<div class=\"ap-custom-wrapper\"><\/div><!--ap-custom-wrapper-->","protected":false},"excerpt":{"rendered":"<p>Decoupled Architecture To understand the term \u201cDecoupled\u201d we need to understand what \u201cCoupled\u201d is. A coupled (also known as \u201ctraditional\u201d or \u201cmonolithic\u201d) CMS knits together the front- and back-ends. Working off the same application, developers and content managers make adjustments to the back-end while users interact with the front-end, but both are experiencing, viewing, and [&hellip;]<\/p>\n","protected":false},"author":1511,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":92},"categories":[3602],"tags":[4862,4064],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55764"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1511"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=55764"}],"version-history":[{"count":5,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55764\/revisions"}],"predecessor-version":[{"id":56279,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55764\/revisions\/56279"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=55764"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=55764"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=55764"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}