javascriptreactjswebpackghost-blog

Bundle React.js project into single js file that can be embedded in Ghost blog post


After building a React.js project, I want to bundle all the files (HTML, js, CSS) into a single js file that can be embedded into a ghost blog post.

Here is an example of how this was done for a ghost blog post.

https://blog.openbloc.com/including-a-js-app-in-a-ghost-post/

My question is how do I bundle the React.js project files into a single file that can be deployed in a ghost blog post?

This can be successfully done for Vue.js but I am not sure if it can be done for React.js

Bundle Vue project into single js file that can be embedded in Ghost blog post

I am using the React v18


Solution

  • Creating a single JS file output

    1. Scaffold a Vite project with the React template:

      npm init vite my-react-project -- --template react
      
    2. Install vite-plugin-css-injected-by-js to automatically inject the app's styles into the document <head>:

      cd my-react-project
      npm i -D vite-plugin-css-injected-by-js
      
    3. Configure Vite to use that plugin via plugins; and to disable CSS code splitting via build.cssCodeSplit:

      // vite.config.js
      import { defineConfig } from 'vite'
      import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
      
      export default defineConfig({
        plugins: [
          cssInjectedByJsPlugin(),
        ],
        build: {
          cssCodeSplit: false,
        },
      })
      
    4. Configure Vite to build a single JavaScript file (i.e., the main.jsx file) via build.rollupOptions.input:

      // vite.config.js
      import { defineConfig } from 'vite'
      
      export default defineConfig({
        build: {
          rollupOptions: {
            input: {
              app: './src/main.jsx',
            },
          },
        },
      })
      
    5. Configure Vite to specify the deployment target's base URL via base:

      // vite.config.js
      import { defineConfig } from 'vite'
      
      export default defineConfig({
        base: 'https://cdn.jsdelivr.net/gh/tony19-sandbox/vite-react-single-js-file/dist/',
      })
      

      The base URL is ideally a CDN link for optimum load performance. For example, if the app files were hosted on GitHub at https://github.com/tony19-sandbox/vite-react-single-js-file/tree/main/dist, the CDN link would be https://cdn.jsdelivr.net/gh/tony19-sandbox/vite-react-single-js-file/dist/.

    6. Build the app:

      cd my-react-project
      npm run build
      

      The build then produces a dist directory containing these files:

      dist/assets/app.d91c60c0.js
      dist/assets/logo.ecc203fb.svg
      

    Usage in Ghost

    1. In your blog page, insert a custom HTML block.
    1. In the HTML block, add a div with an ID that matches the mounting point in src/main.jsx from your app's original source (the default ID is "root").

      <div id="root">App loading...</div>
      
    2. Add a <script> that pulls in the app.js file previously built. For example, if you've hosted the script on GitHub, you could use a CDN link like this:

      <script src="https://cdn.jsdelivr.net/gh/tony19-sandbox/vite-react-single-js-file/dist/assets/app.d91c60c0.js"></script>
      

    The result looks like this:

    GitHub

    Ghost page