Generate single physical javascript file using create-react-app

前端 未结 3 1073
眼角桃花
眼角桃花 2021-01-04 06:06

This is perhaps a newbie question. I have created a small reactjs app using create-react-app and I see that the bundle.js file is being served from http://localhost:3000/sta

相关标签:
3条回答
  • 2021-01-04 06:16

    I had the same exact problem and the short answer is NO. At least with the standard "npm run build" that is currently shipped up to the date of this writing.

    I will however show you how to accomplish your goals by helping you understand what is going on. First, you need to realize that create-react-app is based on the webpack module builder:

    https://webpack.github.io

    So the canonical way to do this would probably be learning webpack and contributing to create-react-app so that instead of generating a static index.html version of your app, it could generate one or more javascript files that you could drop into a Wordpress page. I imagine something like "npm run build -js-only" or something like that. But AFAICT that is not currently possible.

    The good news is that you can still accomplish your goal of "registering" your react app into WP but first you need to understand some concepts:

    1. About create-react-app

    a. When you scaffold your app with create-react-app, it's using webpack under the hood to do this. It's doing this in a pre-defined way defined by create-react-app, so from the start, your app is already structured to be served as an index.html file.

    b. When you are developing with "npm start" it is actually webpack serving your app from RAM.

    c. When you build you app, it is actually webpack (amongst other things) that is used to create that build directory.

    2. Disect your Generated App

    If you view source while you are testing your app with the embedded Webserver (npm start) you will notice that it's a very short html file with the typical structure:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <link rel="shortcut icon" href="/favicon.ico">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta name="theme-color" content="#000000">
        <link rel="manifest" href="/manifest.json">
        <!--
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
        integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
        crossorigin="anonymous">
        -->
        <link rel="stylesheet" href="./bootstrap.min.css">
    
        <title>React App</title>
      </head>
      <body>
        <noscript>
          You need to enable JavaScript to run this app.
        </noscript>
        <div id="root"></div>
      <script src="/static/js/bundle.js"></script><script src="/static/js/0.chunk.js"></script><script src="/static/js/main.chunk.js"></script></body>
    </html>
    

    So basically, you have some header code that loads manifests and stylesheets. Then you have a single container with id "root" and THEN you have the Javascript files you're looking for.

    3. Create a Proof of Concept HTML File on the Worpress Side

    So here is the actual answer to your question. As I said above, this is probably far from ideal but it does solve the problem you are having. I do suspect however that there is an easier and more formal way of accomplishing this, but as you, I'm also a newbie in React and related technologies, so hopefully some expert will eventually weigh in to this thread eventually and propose a more canonical way.

    First you need to serve you React app under some domain, suppose it's being served at myreactapp.local.

    Test that you can access your app by going to http://myreactapp.local/index.html and your app should work just as it did with "npm start". If something breaks, it's probably related to your stylesheets.

    Once you get the static version of your React app to work, just do this:

    1. Look into the build/index.html file and you will notice 3 script tags. One of them has actual code in there, so just copy that code and create a new script on the ROOT of of your react app called loadme.js (at the same level as index.html).

    2. Copy the complete index.html file and create a static HTML file in the root of your wordpress called myreactappskel.html (just for testing the POC). This file will will serve as the basis for your templates and registering of the CSS and JS files into Wordpress ;-)

    3. Edit the file and format it neatly, replacing all relative paths with the URL of the server fo the react app (e.g. myreactapp.local).

    You should end up with a file similar to this:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <link rel="shortcut icon" href="http://myreactapp.local/favicon.ico">
        <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
        <meta name="theme-color" content="#000000">
        <link rel="manifest" href="http://myreactapp.local/manifest.json">
        <link rel="stylesheet" href="http://myreactapp.local/bootstrap.min.css">
        <title>My React App POC Static Page in Wordpress</title>
        <link href="http://myreactapp.local/static/css/1.7fbfdb86.chunk.css" rel="stylesheet">
        <link href="http://myreactapp.local/static/css/main.ebeb5bdc.chunk.css" rel="stylesheet">
      </head>
    
        <title>React App</title>
      </head>
      <body>
        <noscript>
          You need to enable JavaScript to run this app.
        </noscript>
        <div id="someotherid"></div>
        <script src="http://myreactapp.local/loadme.js"></script>
        <script src="http://myreactapp.local/static/js/1.b633dc93.chunk.js"></script>
        <script src="http://myreactapp.local/static/js/main.8958b7bb.chunk.js"></script>
    
    </html>
    

    And that's it! It sounds complicated but it's really not. Notice some important points and caveats:

    1. Rename the "root" to some other ID because "root" will likely collide with something in the HTML where this is embedded. You need to change this in your React source code in both index.html and index.js sources.

    2. Notice how the scripts are AFTER the container div. This is exactly how the packed HTML looks like.

    3. Notice the loadme.js file which you created in a step above by taking the contents of the first tag.

    4. The rest of the file is almost identical to the generated file.

    The rest of the integration to Wordpress should be pretty obvious to you.

    Hope this helps.

    References

    https://facebook.github.io/create-react-app/docs/deployment

    https://webpack.github.io

    0 讨论(0)
  • 2021-01-04 06:34

    An alternative solution, as suggested here, is to use the rewire package to manipulate Create React App's webpack config, e.g.

    Create a new file scripts/build.js

    // npm install rewire
    const rewire = require('rewire');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const defaults = rewire('react-scripts/scripts/build.js');
    const config = defaults.__get__('config');
    
    // Consolidate chunk files instead
    config.optimization.splitChunks = {
      cacheGroups: {
        default: false,
      },
    };
    // Move runtime into bundle instead of separate file
    config.optimization.runtimeChunk = false;
    
    // JS
    config.output.filename = 'static/js/[name].js';
    // CSS remove MiniCssPlugin
    config.plugins = config.plugins.filter(plugin =>
        !(plugin instanceof MiniCssExtractPlugin));
    // CSS replaces all MiniCssExtractPlugin.loader with style-loader
    config.module.rules[2].oneOf = config.module.rules[2].oneOf.map(rule => {
        if (!rule.hasOwnProperty('use')) return rule;
        return Object.assign({}, rule, {
            use: rule.use.map(options => /mini-css-extract-plugin/.test(options.loader)
                ? {loader: require.resolve('style-loader'), options: {}}
                : options)
        });
    });
    

    Edit package.json

    {
      "scripts": {
        ...
        "build": "npx ./scripts/build.js",
        ...
      }
    }
    
    0 讨论(0)
  • 2021-01-04 06:34

    Yes it can be possible by below webpack configuration:

    create file webpack.config.js in your root directory

    const path = require("path")
    const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
    const glob = require("glob")
    
        module.exports = {
          entry: {
            "bundle.js": glob.sync("build/static/?(js|css)/main.*.?(js|css)").map(f => path.resolve(__dirname, f)),
          },
          output: {
            filename: "build/static/js/bundle.min.js",
          },
          module: {
            rules: [
              {
                test: /\.css$/,
                use: ["style-loader", "css-loader"],
              },
            ],
          },
          plugins: [new UglifyJsPlugin()],
        }
    

    In package.json

    ...
        "build": "npm run build:react && npm run build:bundle", 
        "build:react": "react-scripts build", 
        "build:bundle": "webpack --config webpack.config.js", 
    ...
    

    Reference from here

    0 讨论(0)
提交回复
热议问题