├── .github └── workflows │ ├── links.yml │ ├── release.yml │ └── toc.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── start_with_react.md /.github/workflows/links.yml: -------------------------------------------------------------------------------- 1 | name: Links Checker 2 | 3 | on: 4 | repository_dispatch: 5 | workflow_dispatch: 6 | schedule: 7 | - cron: "00 09 * * *" 8 | 9 | jobs: 10 | linkChecker: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Link Checker 16 | id: lychee 17 | uses: lycheeverse/lychee-action@v1.3.0 18 | env: 19 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 20 | 21 | - name: Create Issue From File 22 | if: ${{ steps.lychee.outputs.exit_code != 0 }} 23 | uses: peter-evans/create-issue-from-file@v3 24 | with: 25 | title: Link Checker Report 26 | content-filepath: ./lychee/out.md 27 | labels: report, automated issue -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Generate GH release 2 | on: 3 | push: 4 | tags: 5 | - "*" 6 | env: 7 | MODE: "dev" 8 | jobs: 9 | build: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | - name: Get latest git tag 15 | run: git describe --tags --abbrev=0 16 | id: get_latest_tag 17 | - name: Release 18 | uses: softprops/action-gh-release@v1 19 | -------------------------------------------------------------------------------- /.github/workflows/toc.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: TOC Generator 3 | jobs: 4 | generateTOC: 5 | name: TOC Generator 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: technote-space/toc-generator@v4 -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | - Fork this repository. 4 | - Make a change on the `main` branch. 5 | - For new URLs please provide the "more stable" URL of the project to add. E.g. for `npm` packages use the `https://www.npmjs.com` project path, for Drupal modules use the `https://www.drupal.org` projects path, for several tools use the `https://www.github.com` project path etc. 6 | - Consider using [conventional commit messages](https://www.conventionalcommits.org). 7 | - Create a Pull Request on branch `main`. 8 | - Do not update the Table of Contents manually, it is auto-updated through a GitHub Action. 9 | - For discussions please use the [Project Issues](https://github.com/eworx-org/drupal-js/issues). 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 EWORX S.A. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Drupal decoupled backend with JS frontend 2 | 3 | Best practices, basic steps, lists of tools and tips to help you integrate a Drupal 8.x+ backend with a JavaScript frontend. 4 | 5 | _Note: Some examples below refer only to React development and are not JS agnostic. See also the [Start with React](start_with_react.md) short guide._ 6 | 7 | --- 8 | 9 | 10 | 11 | **Table of Contents** 12 | 13 | - [JS](#js) 14 | - [Popular JS frontend frameworks](#popular-js-frontend-frameworks) 15 | - [Compare JS frameworks](#compare-js-frameworks) 16 | - [Things to consider when selecting a frontend framework (in no particular order)](#things-to-consider-when-selecting-a-frontend-framework-in-no-particular-order) 17 | - [Tools for JS development](#tools-for-js-development) 18 | - [JS terminology](#js-terminology) 19 | - [Learn JS frameworks basics](#learn-js-frameworks-basics) 20 | - [JS app structure](#js-app-structure) 21 | - [Styling a JS app](#styling-a-js-app) 22 | - [Drupal](#drupal) 23 | - [About Drupal decoupled solutions](#about-drupal-decoupled-solutions) 24 | - [Drupal slack channels](#drupal-slack-channels) 25 | - [Drupal modules](#drupal-modules) 26 | - [JSON API (core)](#json-api-core) 27 | - [GraphQL](#graphql) 28 | - [Other](#other) 29 | - [Drupal Distributions](#drupal-distributions) 30 | - [Drupal starter-kits with JS frameworks](#drupal-starter-kits-with-js-frameworks) 31 | - [npm packages for Drupal](#npm-packages-for-drupal) 32 | - [Drupal common issues with decoupled](#drupal-common-issues-with-decoupled) 33 | - [Implementation matrix](#implementation-matrix) 34 | - [Framework: React](#framework-react) 35 | - [Learn React](#learn-react) 36 | - [Drupal + React](#drupal--react) 37 | - [Articles for React](#articles-for-react) 38 | - [Framework: NextJS](#framework-nextjs) 39 | - [Why choose NextJS](#why-choose-nextjs) 40 | - [Learn NextJS](#learn-nextjs) 41 | - [Drupal + NextJS](#drupal--nextjs) 42 | - [NextJS popular tools](#nextjs-popular-tools) 43 | - [Articles for NextJS](#articles-for-nextjs) 44 | - [Framework: Nuxt.js](#framework-nuxtjs) 45 | - [Why choose Nuxt.js](#why-choose-nuxtjs) 46 | - [Drupal + Nuxt.js = Druxt](#drupal--nuxtjs--druxt) 47 | - [Druxt Quick-start templates](#druxt-quick-start-templates) 48 | - [Final tips](#final-tips) 49 | - [Similar resources](#similar-resources) 50 | - [CONTRIBUTING](#contributing) 51 | - [LICENSE](#license) 52 | 53 | 54 | 55 | ## JS 56 | 57 | ### Popular JS frontend frameworks 58 | 59 | - [React](https://reactjs.org) 60 | - [Gatsby](https://www.gatsbyjs.com) 61 | - [Next](https://nextjs.org) 62 | - [Remix](https://remix.run) 63 | - [Blitz](https://blitzjs.com) 64 | - [Inferno](https://www.infernojs.org) 65 | - [Angular](https://angular.io) 66 | - [Vue](https://vuejs.org) 67 | - [Nuxt](https://nuxtjs.org) 68 | - [WebComponents](https://www.webcomponents.org) (not a pure JS solution) 69 | 70 | ### Compare JS frameworks 71 | 72 | Online services to use when comparing frameworks (trends, popularity, usage, downloads, benchmarks etc). 73 | 74 | - **Questionnaires** 75 | - https://2021.stateofjs.com/en-US/libraries/front-end-frameworks 76 | - https://www.jetbrains.com/lp/devecosystem-2021/javascript 77 | - https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-web-frameworks 78 | - **Trends** 79 | - https://trends.google.com/trends/explore?cat=733&date=today%205-y&q=React,Vue,Angular,Next 80 | - https://insights.stackoverflow.com/trends?tags=reactjs%2Cvue.js%2Csvelte%2Cvuejs3%2Cangular 81 | - https://www.npmtrends.com/next-vs-react-vs-svelte-vs-vue 82 | - **Popularity** 83 | - https://www.githubcompare.com/vercel/next.js+facebook/react+angular/angular.js+vuejs/vue 84 | - https://star-history.com/#facebook/react&vuejs/vue&angular/angular&vercel/next.js&Timeline 85 | - https://www.hntrends.com/2020/dec-year-unlike-any-other-tech-tools-didnt-change-much.html?compare=AngularJS&compare=Ember&compare=React&compare=Vue 86 | - https://frontpagemetrics.com/r/reactjs#compare=vuejs+angular2+sveltejs+nextjs 87 | - **Usage** 88 | - https://trends.builtwith.com/javascript/javascript-library 89 | - https://www.wappalyzer.com/technologies/javascript-libraries/react/ 90 | - https://www.datanyze.com/market-share/frameworks-and-libraries--66/react-market-share 91 | - https://www.similartech.com/technologies/react-js 92 | - **Analysis & dependencies** 93 | - https://npmgraph.js.org 94 | - https://bundlephobia.com 95 | - https://packagephobia.com 96 | - **Benchmarks** 97 | - https://krausest.github.io/js-framework-benchmark 98 | - **Browser Support** 99 | - https://kangax.github.io/compat-table/es6 100 | - https://caniuse.com 101 | 102 | ### Things to consider when selecting a frontend framework (in no particular order) 103 | 104 | - Performance 105 | - Stability 106 | - Development experience 107 | - Documentation and support 108 | - Vendors behind 109 | - Complexity and learning curve 110 | - CRUD requirements 111 | - Serving multiple platforms and consumers 112 | - Existing in-house knowledge 113 | 114 | ### Tools for JS development 115 | 116 | Note: Before using these tools try to use the built-in, bundled tools you get from each framework. 117 | 118 | - [VSCode](https://code.visualstudio.com) 119 | - [nvm](https://github.com/nvm-sh/nvm), [npm](https://www.npmjs.com) (no need to use `yarn` over `npm` in 2022) 120 | - [Typescript](https://www.typescriptlang.org) 121 | - [Storybook](https://storybook.js.org) 122 | - [Babel](https://babeljs.io) 123 | - [PostCSS](https://postcss.org) 124 | - [husky](https://github.com/typicode/husky) 125 | - [JSX](https://reactjs.org/docs/introducing-jsx.html) 126 | - [JSON](https://www.json.org/json-en.html), [JSON API](https://jsonapi.org) 127 | - Bundlers: [Webpack](https://webpack.js.org), [esbuild](https://esbuild.github.io) 128 | - Code linting etc: [EditorConfig](http://editorconfig.org), [ESLint](https://eslint.org), [Prettier](https://prettier.io), [JSLint](https://www.jslint.com) 129 | - Code generators: [Hygen](https://www.hygen.io), [nx](https://nx.dev), [ReexJs CLI](https://codingcodax.github.io/reexjs-cli), [generact](https://github.com/diegohaz/generact) 130 | - Testing: [Jest](https://jestjs.io), [Cypress](https://cypress.io), [testing-library](https://testing-library.com), [nightwatchjs](https://nightwatchjs.org), [playwright](https://playwright.dev) 131 | - Data fetch: [axios](https://axios-http.com), [react-query](https://react-query.tanstack.com), [SWR](https://swr.vercel.app), [node-fetch](https://www.npmjs.com/package/node-fetch) 132 | - Data parser: [qs](https://www.npmjs.com/package/qs), [html-react-parser](https://github.com/remarkablemark/html-react-parser) 133 | - Routing: [React Router](https://reactrouter.com), [TanStack Router](https://tanstack.com/router) 134 | - Quality: [danger](https://www.npmjs.com/package/danger) 135 | - Logging: [pino](https://getpino.io) 136 | - Documentation: [jsdoc](https://www.npmjs.com/package/jsdoc) 137 | - Performance: [next-boost](https://github.com/next-boost/next-boost), [react-lazy-load-image-component](https://www.npmjs.com/package/react-lazy-load-image-component), [node-cache](https://www.npmjs.com/package/node-cache), [webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer) 138 | - Security: (npm built-in: `npm-audit, npm-outdated, npm-doctor` [npm-check](https://www.npmjs.com/package/npm-check), [snyk](https://snyk.io), [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) 139 | - State management: [redux](https://redux.js.org), [zustand](https://github.com/pmndrs/zustand), [recoil](https://recoiljs.org), [jotai](https://jotai.org) 140 | - Translations, i18n: [lingui](https://github.com/lingui/js-lingui), [polyglot](https://www.npmjs.com/package/node-polyglot) 141 | - Mocks, faker: [sinon](https://sinonjs.org), [faker](https://fakerjs.dev), [JSON Server fake API](https://www.npmjs.com/package/json-server) 142 | 143 | ### JS terminology 144 | 145 | In order to start with JS you sould be familiar with the basic terms below. Note that some of them may refer to a specific JS framework. 146 | 147 | - CORS 148 | - Cache 149 | - Code splitting 150 | - Components 151 | - Composition 152 | - DOM 153 | - Data fetch 154 | - HMR (Hot Module Reload) 155 | - HOC (Higher Order Components) 156 | - Hook events 157 | - Injection 158 | - Invalidation 159 | - Isomorphic 160 | - PWA 161 | - Props 162 | - Routing 163 | - SEO 164 | - [SSR](https://vuejs.org/guide/scaling-up/ssr.html), [SSG](https://blog.logrocket.com/ssg-vs-ssr-in-next-js), [ISR](https://blog.logrocket.com/incremental-static-regeneration-with-next-js), [DSG](https://www.gatsbyjs.com/docs/how-to/rendering-options/using-deferred-static-generation), [CSR](https://frontend-digest.com/client-side-rendering-vs-server-side-rendering-vs-static-site-generation-2a0702cbb08d) 165 | - SWA 166 | - SideEffect 167 | - State 168 | - Web Vitals (LCP, FID, CLS) 169 | - a11y 170 | - es6/es7 etc 171 | - hydration 172 | - i18n 173 | - library 174 | - module 175 | - node daemon 176 | - package 177 | - virtual DOM 178 | 179 | ### Learn JS frameworks basics 180 | 181 | - https://github.com/sorrycc/awesome-javascript 182 | - https://www.patterns.dev 183 | 184 | ### JS app structure 185 | 186 | - [Move files around until it feels right](https://react-file-structure.surge.sh/) 187 | - Group by file type 188 | - Avoid too much nesting 189 | - Keep with the trends (e.g. use common names like "`src, public, pages, __tests__, docs`" etc 190 | 191 | ``` 192 | ToDo: Add some example structure here.. 193 | ``` 194 | 195 | Sources: [1](https://gist.github.com/literat/4f7c8a4a9b9d113886df77fa34228623), [2](https://hackernoon.com/react-project-structure-best-practices-kh20323x), [3](https://blog.usejournal.com/folder-structure-in-react-apps-c2ae8974d21f), [4](https://hackernoon.com/structuring-projects-and-naming-components-in-react-1261b6e18d76), [5](https://reactjs.org/docs/faq-structure.html) 196 | 197 | ### Styling a JS app 198 | 199 | - Prefer "CSS in files" approach except if there are specific requirements. 200 | - For inline styles you can use utility CSS libraries like [tailwindcss](https://tailwindcss.com) and [Windi CSS](https://windicss.org). 201 | - For UI building isolation and sandboxing use [Storybook](https://storybook.js.org), [React Styleguidist](https://react-styleguidist.js.org), [React Cosmos](https://reactcosmos.org), [React Preview](https://reactpreview.com) etc. 202 | 203 | --- 204 | 205 | ## Drupal 206 | 207 | ### About Drupal decoupled solutions 208 | 209 | - https://www.drupal.org/docs/develop/decoupled-drupal 210 | - [Drupal core ideas: Drupal JavaScript Client Initiative](https://www.drupal.org/node/3277222) 211 | - https://dri.es/headless-cms-rest-vs-jsonapi-vs-graphql 212 | - https://dri.es/how-to-decouple-drupal-in-2019 213 | - https://dri.es/drupal-looking-to-adopt-react 214 | - https://dri.es/advancing-drupal-web-services 215 | - https://www.drupal.org/industries/decoupled 216 | - https://www.lullabot.com/articles/should-you-decouple 217 | - https://www.softescu.com/en/blog/fully-decoupled-or-progressively-decoupled 218 | - https://medium.com/analytics-vidhya/decoupled-drupal-as-a-solution-bd0ec25f39cf 219 | - https://opensenselabs.com/blog/articles/different-options-decoupling-drupal 220 | - https://www.lullabot.com/articles/decoupled-hard-problems-routing 221 | - https://noti.st/brianperry/2Fvgeu/drupal-state-and-the-need-for-a-javascript-sdk 222 | - [My Headless/Decoupled CMS Comparison Matrix, 2017, krynsky.com](https://krynsky.com/my-headless-decoupled-content-management-software-and-services-comparison-matrix) 223 | 224 | ### Drupal slack channels 225 | 226 | - [#decoupled](https://app.slack.com/client/T06GX3JTS/C1AKSFBEW) 227 | - [#headless](https://app.slack.com/client/T06GX3JTS/C8ZK4VDMW) 228 | - [#graphql](https://app.slack.com/client/T06GX3JTS/C6LMJ0ZAT) 229 | - [#contenta](https://app.slack.com/client/T06GX3JTS/C5A70F7D1) 230 | - [#react](https://app.slack.com/client/T06GX3JTS/CUW94TUBX) 231 | - [#nextjs](https://app.slack.com/client/T06GX3JTS/C01E36BMU72) 232 | - [#gatsby](https://app.slack.com/client/T06GX3JTS/CDQC1MDU6) 233 | - [#druxt (NuxtJS)](https://app.slack.com/client/T06GX3JTS/C01ALFZ8459) 234 | - [#vue](https://app.slack.com/client/T06GX3JTS/C9SR65F6K) 235 | - [#custom-elements](https://app.slack.com/client/T06GX3JTS/C01G23CS86Q) 236 | - [#api-client](https://app.slack.com/client/T06GX3JTS/C05BP6659U0) 237 | 238 | ### Drupal modules 239 | 240 | Note: Modules in emphasis are the most used across the Drupal universe. 241 | 242 | #### JSON API (core) 243 | 244 | [jsonapi.org](https://jsonapi.org), [JSON API: Drupal core module documentation](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module), [Ecosystem modules for JSON:API](https://www.drupal.org/project/jsonapi/ecosystem) 245 | 246 | - **Basic** 247 | - **[decoupled_kit](https://drupal.org/project/decoupled_kit)** 248 | - **[decoupled_menus](https://drupal.org/project/decoupled_menus)** 249 | - **[drupal_jsonapi_params](https://drupal.org/project/drupal_jsonapi_params)** 250 | - [entity_view_mode_normalize](https://drupal.org/project/entity_view_mode_normalize) 251 | - [fieldable_path](https://drupal.org/project/fieldable_path) 252 | - [jsonapi_aliases](https://drupal.org/project/jsonapi_aliases) 253 | - [jsonapi_comment](https://drupal.org/project/jsonapi_comment) 254 | - [jsonapi_embed](https://drupal.org/project/jsonapi_embed) 255 | - **[jsonapi_extras](https://drupal.org/project/jsonapi_extras)** 256 | - **[jsonapi_menu_items](https://drupal.org/project/jsonapi_menu_items)** 257 | - **[jsonapi_views](https://drupal.org/project/jsonapi_views)** 258 | - [jsonapi_pathauto_breadcrumbs](https://www.drupal.org/project/jsonapi_pathauto_breadcrumbs) 259 | - [jsonrpc](https://drupal.org/project/jsonrpc) 260 | - [pager_serializer](https://drupal.org/project/pager_serializer) 261 | - [rest_absolute_urls](https://drupal.org/project/rest_absolute_urls) 262 | - [rest_menu_detail](https://drupal.org/project/rest_menu_detail) 263 | - [rest_menu_items](https://drupal.org/project/rest_menu_items) 264 | - [rest_normalizer](https://drupal.org/project/rest_normalizer) 265 | - [jsonapi_hypermedia](https://www.drupal.org/project/jsonapi_hypermedia) 266 | - [jsonapi_bulk_exclude](https://www.drupal.org/project/jsonapi_bulk_exclude) 267 | - [jsonapi_example](https://www.drupal.org/project/jsonapi_example) 268 | - [transform_api](https://www.drupal.org/project/transform_api) 269 | - [contextual_aliases](https://github.com/pmelab/contextual_aliases) 270 | - **Data** 271 | - [config_pages](https://drupal.org/project/config_pages) 272 | - **Subrequests, nesting** 273 | - [jsonapi_include](https://drupal.org/project/jsonapi_include) 274 | - [rest_entity_recursive](https://drupal.org/project/rest_entity_recursive) 275 | - [rest_export_nested](https://drupal.org/project/rest_export_nested) 276 | - **[subrequests](https://drupal.org/project/subrequests)** 277 | - **Routing** 278 | - **[decoupled_router](https://drupal.org/project/decoupled_router)** 279 | - [entity_router](https://drupal.org/project/entity_router) 280 | - **Collections** 281 | - [jsonapi_cross_bundles](https://drupal.org/project/jsonapi_cross_bundles) 282 | - [decoupled_pages](https://drupal.org/project/decoupled_pages) 283 | - [jsonapi_resources](https://drupal.org/project/jsonapi_resources) 284 | - [jsonapi_field_formatter](https://www.drupal.org/project/jsonapi_field_formatter) 285 | - [page_manager](https://drupal.org/project/page_manager) 286 | - [jsonapi_user_resources](https://drupal.org/project/jsonapi_user_resources) 287 | - **Search** 288 | - **[jsonapi_search_api](https://www.drupal.org/project/jsonapi_search_api)** 289 | - **Preview** 290 | - **[decoupled_preview](https://www.drupal.org/project/decoupled_preview)** 291 | - **[dpl](https://drupal.org/project/dpl)** 292 | - **[jsonapi_node_preview](https://drupal.org/project/jsonapi_node_preview)** 293 | - **[jsonapi_node_preview_tab](https://drupal.org/project/jsonapi_node_preview_tab)** 294 | - **Performance** 295 | - [jsonapi_earlyrendering_workaround](https://drupal.org/project/jsonapi_earlyrendering_workaround) 296 | - **[jsonapi_boost](https://drupal.org/project/jsonapi_boost)** 297 | - **[warmer](https://drupal.org/project/warmer)** 298 | - **Images/Files** 299 | - **[jsonapi_image_styles](https://drupal.org/project/jsonapi_image_styles)** 300 | - **[consumer_image_styles](https://drupal.org/project/consumer_image_styles)** 301 | - [image_derivatives_selection](https://drupal.org/project/image_derivatives_selection) 302 | - [image_derivatives_base64_representation](https://drupal.org/project/image_derivatives_base64_representation) 303 | - [filefield_sources_jsonapi](https://www.drupal.org/project/filefield_sources_jsonapi) 304 | - [jsonapi_flysystem_uploader](https://www.drupal.org/project/jsonapi_flysystem_uploader) 305 | - [nplowman/jsonapi-reusable-images](https://github.com/nplowman/jsonapi-reusable-images) 306 | - **Rate limits** 307 | - [rate_limiter](https://drupal.org/project/rate_limiter) 308 | - **[rate_limits](https://drupal.org/project/rate_limits)** 309 | - **API Documentation** 310 | - [schemata](https://drupal.org/project/schemata) 311 | - [openapi_ui_swagger](https://drupal.org/project/openapi_ui_swagger) 312 | - **[openapi](https://drupal.org/project/openapi)** 313 | - [openapi_ui](https://drupal.org/project/openapi_ui) 314 | - **[openapi_jsonapi](https://drupal.org/project/openapi_jsonapi)** 315 | - [openapi_rest](https://drupal.org/project/openapi_rest) 316 | - **[openapi_ui_redoc](https://drupal.org/project/openapi_ui_redoc)** 317 | - [swagger_ui_formatter](https://drupal.org/project/swagger_ui_formatter) 318 | - [jsonapi_schema](https://drupal.org/project/jsonapi_schema) 319 | - [social_json_api](https://drupal.org/project/social_json_api) 320 | - **Authentication** 321 | - [api_proxy](https://drupal.org/project/api_proxy) 322 | - **[simple_oauth](https://drupal.org/project/simple_oauth)** 323 | - **[consumers](https://drupal.org/project/consumers)** 324 | - **[cors_ui](https://drupal.org/project/cors_ui)** 325 | - [rest_api_authentication](https://drupal.org/project/rest_api_authentication) 326 | - [key_auth](https://drupal.org/project/key_auth) 327 | - [api_key_manager](https://drupal.org/project/api_key_manager) 328 | - [access_filter](https://drupal.org/project/access_filter) 329 | - [jsonapi_access](https://drupal.org/project/jsonapi_access) 330 | - [rest_password](https://drupal.org/project/rest_password) 331 | - [jsonapi_role_access](https://drupal.org/project/jsonapi_role_access) 332 | - [simonbaese/consumer_permissions](https://github.com/simonbaese/consumer_permissions) 333 | - **Administration** 334 | - **[restui](https://drupal.org/project/restui)** 335 | - [jsonapi_explorer](https://drupal.org/project/jsonapi_explorer) 336 | - [jsonapi_node_preview_tab](https://drupal.org/project/jsonapi_node_preview_tab) 337 | - [restuiextention](https://drupal.org/project/restuiextention) 338 | - [api_proxy](https://drupal.org/project/api_proxy) 339 | - [decoupled_toolbox](https://drupal.org/project/decoupled_toolbox) 340 | - [jsonapi_query_builder](https://www.drupal.org/project/jsonapi_query_builder) 341 | - **Forms** 342 | - **[webform_rest](https://drupal.org/project/webform_rest)** 343 | - [webform_jsonschema](https://drupal.org/project/webform_jsonschema) 344 | - [rjsf](https://drupal.org/project/rjsf) 345 | - [next_webform](https://www.drupal.org/project/next_webform) 346 | - **Logging** 347 | - **[http_client_log](https://drupal.org/project/http_client_log)** 348 | - [request_logger](https://drupal.org/project/request_logger) 349 | - [rest_log](https://drupal.org/project/rest_log) 350 | - [restfullogger](https://drupal.org/project/restfullogger) 351 | - **Translations** 352 | - [decoupled_interface_translations](https://www.drupal.org/project/decoupled_interface_translations) 353 | 354 | #### GraphQL 355 | 356 | - **[graphql](https://drupal.org/project/graphql)** 357 | - [graphql_compose](https://www.drupal.org/project/graphql_compose) 358 | - [graphql_directives](https://github.com/AmazeeLabs/graphql_directives) 359 | - [graphql_entity_by_object](https://drupal.org/project/graphql_entity_by_object) 360 | - [graphql_entity_definitions](https://drupal.org/project/graphql_entity_definitions) 361 | - [graphql_extras](https://drupal.org/project/graphql_extras) 362 | - [graphql_formatters](https://drupal.org/project/graphql_formatters) 363 | - [graphql_menu](https://drupal.org/project/graphql_menu) 364 | - [graphql_metatag](https://drupal.org/project/graphql_metatag) 365 | - [graphql_node_preview](https://drupal.org/project/graphql_node_preview) 366 | - [graphql_redirect](https://drupal.org/project/graphql_redirect) 367 | - [graphql_redirect_entity](https://drupal.org/project/graphql_redirect_entity) 368 | - [graphql_search_api](https://drupal.org/project/graphql_search_api) 369 | - [graphql_views](https://drupal.org/project/graphql_views) 370 | - [graphql_webform](https://drupal.org/project/graphql_webform) 371 | - [preview_graphql](https://drupal.org/project/preview_graphql) 372 | 373 | #### Other 374 | 375 | - [api_client](https://www.drupal.org/project/api_client) 376 | - [services](https://www.drupal.org/project/services) 377 | - [pdb](https://drupal.org/project/pdb) 378 | - **[relaxed](https://drupal.org/project/relaxed)** 379 | - [jdrupal](https://drupal.org/project/jdrupal) 380 | - [js_component](https://drupal.org/project/js_component) 381 | - [gdwc](https://www.drupal.org/project/gdwc) 382 | - [api_toolkit](https://www.drupal.org/project/api_toolkit) 383 | - [decoupled](https://www.drupal.org/project/decoupled) 384 | 385 | ### Drupal Distributions 386 | 387 | - https://www.contentacms.org 388 | - https://www.drupal.org/project/tide 389 | - https://github.com/systemseed/falcon 390 | - https://github.com/codingsasi/acephalous 391 | - https://www.drupal.org/project/ezcontent (using REST, not a decoupled example) 392 | 393 | ### Drupal starter-kits with JS frameworks 394 | 395 | - https://next-drupal.org (Next) 396 | - https://druxtjs.org (Nuxt) 397 | - https://stack.lupus.digital (Nuxt) 398 | - https://github.com/acquia/next-acms (Next) 399 | - https://github.com/octahedroid/drupal-remix (Remix) 400 | - https://github.com/rbeach/drupal-remix (Remix example) 401 | 402 | ### npm packages for Drupal 403 | 404 | - [d8-jsonapi-querystring](https://www.npmjs.com/package/d8-jsonapi-querystring) 405 | - [d8-subrequests](https://www.npmjs.com/package/d8-subrequests) 406 | - [drupal-jsonapi-extractor](https://www.npmjs.com/package/drupal-jsonapi-extractor) 407 | - [drupal-jsonapi-params](https://www.npmjs.com/package/drupal-jsonapi-params) 408 | - [drupal-sdk](https://www.npmjs.com/package/drupal-sdk) 409 | - [drupal-state](https://www.npmjs.com/package/@gdwc/drupal-state) (see docs at [drupalcode.org/drupal_state](https://project.pages.drupalcode.org/drupal_state) 410 | - [jsonapi-parse](https://www.npmjs.com/package/jsonapi-parse) 411 | - [react-drupal-json-api](https://www.npmjs.com/package/react-drupal-json-api) 412 | - [drupal-kit](https://www.npmjs.com/package/@pantheon-systems/drupal-kit) 413 | - [drupal-js-sdk](https://www.npmjs.com/package/drupal-js-sdk) 414 | 415 | ### Drupal common issues with decoupled 416 | 417 | - Displaying embedded entities on CKEditor (eg Media) inside JS components 418 | - Multilingual 419 | - Subrequets and relationships in data 420 | - Customizing of responses like filtering, quering and altering 421 | - Routing and path aliases 422 | - Non entities data (e.g. metatags, redirects, path aliases, image styles) 423 | - Workflows (Content Moderation) and revisions 424 | - Node preview 425 | - Authentication 426 | - Invalidate partial cache 427 | - Forms 428 | 429 | ### Implementation matrix 430 | 431 | An **example matrix for common requirements** of a decoupled Drupal backend with JS frontend. 432 | 433 | The table show which part of the app should take care of each functionality. 434 | 435 | For example, we could get the site logo from Drupal but we could also use a static image on the JS side as a logo. 436 | 437 | Notice that, in some cases, there may be a combination of the two parts or a 3rd party solution (eg an external CDN for image assets). 438 | 439 | | Requirement | Drupal backend | JS frontend | 440 | | --- | :---: | :---: | 441 | | access and permissions | ⬜ |⬜| 442 | | authentication | ⬜ | ⬜ | 443 | | basic site settings (eg logo, site name, site slogan etc) | ⬜ | ⬜ | 444 | | breadcrumbs | ⬜ | ⬜ | 445 | | caching | ⬜ | ⬜ | 446 | | collections (views VS JSON API entity queries) | ⬜ | ⬜ | 447 | | CORS | ⬜ | ⬜ | 448 | | CRUD requirements | ⬜ | ⬜ | 449 | | embedded HTML on CKEditor | ⬜ | ⬜ | 450 | | file attachments | ⬜ | ⬜ | 451 | | forms | ⬜ | ⬜ | 452 | | image styles | ⬜ | ⬜ | 453 | | menus | ⬜ | ⬜ | 454 | | metatags | ⬜ | ⬜ | 455 | | mocking data | ⬜ | ⬜ | 456 | | modifying JSON response | ⬜ | ⬜ | 457 | | multilingual | ⬜ | ⬜ | 458 | | multisite | ⬜ | ⬜ | 459 | | partial cache invalidation | ⬜ | ⬜ | 460 | | path aliases | ⬜ | ⬜ | 461 | | preview | ⬜ | ⬜ | 462 | | redirects | ⬜ | ⬜ | 463 | | relationships and field references | ⬜ | ⬜ | 464 | | revisions | ⬜ | ⬜ | 465 | | routing | ⬜ | ⬜ | 466 | | search_api | ⬜ | ⬜ | 467 | | sub-requests | ⬜ | ⬜ | 468 | | third party scripts (eg gtag) | ⬜ | ⬜ | 469 | | UI translations | ⬜ | ⬜ | 470 | | workflows (content moderation) | ⬜ | ⬜ | 471 | | xml sitemap | ⬜ | ⬜ | 472 | 473 | --- 474 | 475 | ## Framework: React 476 | 477 | - https://reactjs.org 478 | - https://github.com/enaqx/awesome-react 479 | - https://github.com/brillout/awesome-react-components 480 | 481 | ### Learn React 482 | 483 | - [Thinking in React - reactjs.org](https://reactjs.org/docs/thinking-in-react.html) 484 | - [Complete guide React + Drupal - drupalize.me](https://drupalize.me/series/drupal-8-and-reactjs) 485 | - [React in patterns](https://krasimir.gitbooks.io/react-in-patterns) 486 | - [30 Days of React - GitHub](https://github.com/Asabeneh/30-Days-Of-React) 487 | - [Functional Components](https://programmingwithmosh.com/react/react-functional-components) 488 | - React Components: https://reactjs.org/docs/react-component.html, https://github.com/brillout/awesome-react-components 489 | - React Hooks: https://reactjs.org/docs/hooks-intro.html, https://usehooks.com 490 | - React Props: https://akd3257.medium.com/what-are-props-in-react-2f822330e3a7 491 | 492 | ### Drupal + React 493 | 494 | - Guide: https://reactfordrupal.com 495 | - Starter: https://github.com/systemseed/drupal_reactjs_boilerplate 496 | - Example: https://github.com/DrupalizeMe/react-and-drupal-examples 497 | 498 | ### Articles for React 499 | 500 | - https://www.smashingmagazine.com/2021/11/maintain-large-nextjs-application 501 | 502 | --- 503 | 504 | ## Framework: NextJS 505 | 506 | - https://nextjs.org 507 | - https://github.com/unicodeveloper/awesome-nextjs 508 | 509 | ### Why choose NextJS 510 | 511 | - Better SEO. Supports SSR, SSG, ISR. 512 | - Built in solutions for common requirements (routing, head/metatags, images, links, font optimization, data fetching, injected scripts, i18n, AMP) 513 | - Built in tools (Typescript, Sass, ESLint, Webpack, env variables, preview mode, polyfills) 514 | - Better Development Experience (DX) (zero config, built in tools, fast refresh) 515 | - Based on React (can use all the React goodies) 516 | 517 | ### Learn NextJS 518 | 519 | - [nextjs.org/learn/basics/create-nextjs-app](https://nextjs.org/learn/basics/create-nextjs-app) 520 | - [nextjstips.com](https://nextjstips.com) 521 | 522 | ### Drupal + NextJS 523 | 524 | - [next-drupal.org](https://next-drupal.org) 525 | - [TallerWebSolutions/next-on-drupal](https://github.com/TallerWebSolutions/next-on-drupal) 526 | - [About Drupal, Gatsby and Next](https://gist.github.com/colorfield/22b1a451d90b2a159c7d3d679197812f) 527 | - [Next.js and Headless CMS - GitHub issue](https://github.com/vercel/next.js/discussions/33087) 528 | 529 | ### NextJS popular tools 530 | 531 | - https://swr.vercel.app (React Hooks for Data Fetching) 532 | - https://next-auth.js.org (Authentication for Next.js) 533 | - https://github.com/atilafassina/next-g11n (Translate and localize your Next.js app smoothly) 534 | - https://github.com/next-boost/next-boost (Adds a cache layer to your SSR applications) 535 | 536 | ### Articles for NextJS 537 | 538 | - https://www.smashingmagazine.com/2021/11/maintain-large-nextjs-application 539 | - https://stackabuse.com/guide-to-getting-started-with-nextjs-create-a-nextjs-app 540 | 541 | --- 542 | 543 | ## Framework: Nuxt.js 544 | 545 | - https://druxtjs.org 546 | - https://nuxtjs.org 547 | - https://github.com/nuxt-community/awesome-nuxt 548 | 549 | ### Why choose Nuxt.js 550 | 551 | - Better SEO. Suppports SSR and SSG. 552 | - Built in solutions for common requirements (routing, head/metatags, images, links, font optimization, data fetching, injected scripts, i18n, AMP) 553 | - Built in tools (Typescript, Sass, ESLint, Webpack, env variables, preview mode, polyfills) 554 | - Better Development Experience (DX) (zero config, built in tools, fast refresh) 555 | - Based on Vue (can use all the Vue goodies) 556 | 557 | ### Drupal + Nuxt.js = Druxt 558 | 559 | > Druxt = DRUpal + nuXT 560 | 561 | - [druxtjs.org](https://druxtjs.org) 562 | - Fully Decoupled Drupal, with Nuxt.js in the frontend. 563 | - Drupal JSON:API Client with Vuex caching. 564 | - Modular Vue.js component library system. 565 | - Slot and Wrapper theming system. 566 | - API and File proxy. 567 | 568 | ### Druxt Quick-start templates 569 | 570 | - [DruxtSite](https://github.com/druxt/quickstart-druxt-site) 571 | - [DruxtSite w/tome sync](https://github.com/druxt/quickstart-druxt-site-tome) 572 | - [Serverless Druxt](https://github.com/druxt/quickstart-druxt-serverless) 573 | - [DruxtModule (template)](https://github.com/druxt/module-template) 574 | 575 | --- 576 | 577 | ## Final tips 578 | 579 | - Make it really "decoupled" (except if other requirements) 580 | - Keep it simple. Use the basic tools and extend when needed. 581 | - Less JS packages and less Drupal modules is prefferable. 582 | - Work only with NodeJS LTS versions. 583 | - Think in Components 584 | - Create enough Components 585 | - Modify the state directly 586 | - Add keys on the lists (inside JS Components) 587 | - Declare types, validate functions 588 | - Always test your Components and app 589 | - Dockerize your JS app 590 | - For security updates of npm packages prefer to update the main JS library used (eg Next, React etc) and not the several npm packages independently. 591 | - Drupal: Prefer Drupal modules from core (e.g. JSON API instead of GraphQL) 592 | - Drupal: Do not override the default Drupal field machine names on JSON 593 | - Drupal: prefer quering the `search_api` to get search results on the JS App when using 3rd party search engines like SOLR. 594 | - Start with the official starter kits (e.g [create-react-app](https://create-react-app.dev/)) 595 | 596 | --- 597 | 598 | ## Similar resources 599 | 600 | - [d34dman/awesome-drupal-jsonapi](https://github.com/d34dman/awesome-drupal-jsonapi) 601 | 602 | --- 603 | 604 | ## CONTRIBUTING 605 | 606 | [Contribution guide](CONTRIBUTING.md) 607 | 608 | --- 609 | 610 | ## LICENSE 611 | 612 | [MIT](LICENSE) - Copyright (c) 2022 [EWORX S.A.](https://github.com/eworx-org) 613 | -------------------------------------------------------------------------------- /start_with_react.md: -------------------------------------------------------------------------------- 1 | > There is always an [enaqx/awesome-react](https://github.com/enaqx/awesome-react) for reference! 2 | 3 | Last updated 2023-01-10 4 | 5 | ## JS basics 6 | - https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript 7 | - https://kentcdodds.com/blog/javascript-to-know-for-react 8 | - https://nextjs.org/learn/foundations/from-javascript-to-react/essential-javascript-react 9 | - https://www.digitalocean.com/community/tutorials/understanding-javascript-promises 10 | 11 | ## React Basics 12 | - https://reactjs.org/docs/glossary.html (may prefer to read from the new https://react.dev) 13 | - https://reactjs.org/docs/hello-world.html 14 | - https://reactpatterns.com 15 | 16 | ## React Hooks - learn 17 | - https://reactjs.org/docs/hooks-intro.html 18 | - https://reactbyexample.github.io/hooks 19 | - https://wattenberger.com/blog/react-hooks 20 | - https://testdriven.io/blog/react-hooks-primer 21 | 22 | ## React Hooks - collections 23 | - https://github.com/rehooks/awesome-react-hooks 24 | - https://nikgraf.github.io/react-hooks 25 | - https://antonioru.github.io/beautiful-react-hooks 26 | - https://usehooks.com 27 | - https://github.com/streamich/react-use 28 | - https://react-hooks.org/docs/hooks-list 29 | - https://github.com/alibaba/hooks 30 | 31 | ## React Patterns 32 | - https://www.patterns.dev 33 | - https://krasimir.gitbooks.io/react-in-patterns/content 34 | - https://medium.com/walmartglobaltech/make-your-react-components-pretty-a1ae4ec0f56e 35 | 36 | ## React Cheatsheets 37 | - https://www.freecodecamp.org/news/the-react-cheatsheet 38 | 39 | ## React Best Practices 40 | - https://alexkondov.com/tao-of-react 41 | 42 | ## React props 43 | - https://www.freecodecamp.org/news/react-props-cheatsheet 44 | 45 | ## Rendering methods 46 | - https://developers.google.com/web/updates/2019/02/rendering-on-the-web 47 | - https://medium.com/@nashedandrew5/data-fetching-in-next-js-with-examples-dac69745ed17 48 | - https://biondifabio.medium.com/quick-animated-introduction-to-pre-rendering-ssr-and-ssg-in-nextjs-ecb5920100c7 49 | - https://theodorusclarence.com/blog/nextjs-fetch-method 50 | - (**CSR**) https://frontend-digest.com/client-side-rendering-vs-server-side-rendering-vs-static-site-generation-2a0702cbb08d 51 | - (**SSG**) https://dev.to/matfrana/server-side-rendering-vs-static-site-generation-17nf 52 | - (**SSG**) https://blog.logrocket.com/ssg-vs-ssr-in-next-js 53 | - (**ISR**) https://blog.logrocket.com/incremental-static-regeneration-with-next-js 54 | - (**DSG**) https://www.gatsbyjs.com/docs/how-to/rendering-options/using-deferred-static-generation 55 | --------------------------------------------------------------------------------