Correctly linking to webpack-dev-server bundle in php site

2k views Asked by At

I am currently trying to get a better understanding of webpack and webpack-dev-server.

I have the following setup: A php site serves a react app and I want hot module replacement (HMR) for development purposes, while being on this site. Because I don't want my webpack-dev-server to serve my whole page, I tried to have it serve my bundle.js, which I then include in my php file manually at the moment:

<script src="https://localhost:8877/dist/elements.bundle.js"></script>

The problem is that for production I have to change this url by hand to something like /dist/elements.bundle.js, because the bundle will not be served by the dev-server on the server.

I read a lot about webpack-dev-server/client?https://localhost:8877 and webpack/hot/only-dev-server and if I understood it corretly, those entries will redirect to the webpack-dev-server url?

If I run my npm start-script with webpack-dev-server --config webpack.dev.js, this will not build my elements.bundle.js in the filesystem, but only serve it from the dev-server's memory. In this case, I cannot include the local bundle.js but have to use the one from localhost:8877. But how can I have webpack compile the entry point and webpack-dev-server do it's job at the same time with one command?

If I run webpack --config webpack.dev.js and webpack-dev-server --config webpack.dev.js in two terminals, then I can include /dist/elements.bundle.js in my php file, but HMR is not working anymore, as it tells me it has to reload the whole page.

I am really trying to understand the concepts and I would be very glad, if someone could give me some advice and help me setting up my project correctly.

How can I switch between development and production without changing the script tag in my php file and with support of HMR and react-hot-loader?

This is my webpack.dev.js:

const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const development = process.env.NODE_ENV !== "production";

module.exports = merge(common, {
    devtool: 'inline-source-map',
    watch: development
});

This is my webpack.common.js:

const path = require('path');
const webpack = require('webpack');
require("babel-polyfill");

const development = process.env.NODE_ENV !== "production";

module.exports = {
    context: path.resolve(__dirname, "webroot"),
    devtool: 'cheap-eval-source-map',
    entry: {
        elements: [
            'babel-polyfill',
            'react-hot-loader/patch',
            'webpack-dev-server/client?https://localhost:8877',
            'webpack/hot/only-dev-server',
            './js/elements.client.js'
        ]
    },
    output: {
        path: path.resolve(__dirname, "webroot", "js", "dist"),
        filename: "[name].bundle.js",
        publicPath: "https://localhost:8877/dist/"
    },
    plugins: [
        new webpack.DefinePlugin({
            DEVELOPMENT: JSON.stringify(development)
        }),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NamedModulesPlugin()
    ],
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader',
                query: {
                    presets: ['react', 'es2015', 'stage-0'],
                    plugins: ['react-hot-loader/babel','react-html-attrs', 'transform-decorators-legacy', 'transform-class-properties'],
                }
            }
        ]
    },
    devServer: {
        hot: true,
        https: true,
        inline: true,
        host: 'localhost',
        port: 8877,
        contentBase: path.resolve(__dirname, "webroot"),
        headers: {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
            "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
        }
    }
};
1

There are 1 answers

2
felixmosh On

Actually it is not a matter of webpack or webpack-dev-server but of you php.

I had the same problem, and similar setup. I ended up with php variable that will contain /dist/bundle.js on production and http://localhost:3000/bundle.js on development.

The conditional was if the site is served from the production domain or not.

$path_to_js = $_SERVER["HTTP_HOST"] === 'localhost' ? 'http://localhost:3000/bundle.js' : 'dist/bundle.js';

Then with that variable you can concat the location of your js file on your main template php file.

<html>
   <head> ... </head>
   <body>
      <script src="<?=$path_to_js?>"></script>
   </body>
</html>

Hope that helps