How do you configure a Webpack dev server to serve a specific folder while running the rest of the site through a different server?
Asked Answered
E

3

7

Some quick background:

My company's site runs off a CMS with the CMS handling all routing. There are no html files, only razor files (.cshtml). While redoing the site from scratch is what I'd prefer to do, it's not an option, so I'm attempting to modernize the site slowly over time by integrating vue.js with a webpack development workflow piecemeal on a page-by-page basis.

I've spent considerable time setting up webpack in a manner that allows it to process files found in the /dist/ folder only - everything else is served via http://my.server/ and handled by the CMS and backend.

Through trial & error I managed to get webpack-dev-server serving files in the /dist/ folder while allowing the rest of the server to serve everything else (via http://my.server/). Unfortunately, this ONLY works when the file paths for the webpack-dev-server part are specifically referencing "http://localhost:8080/" which is obviously unacceptable.

The dev environment code must be exactly like the production environment code, therefore <script src="http://localhost:8080/dist/build.js"></script> is simply unacceptable.

However, if I simply write <script src="/dist/build.js"></script> the server resolves this to <script src="http://my.server/dist/build.js"></script> which is obviously incorrect and results in a 404 (because those files are being served only from the dev server).

My question is, "how do I configure the webpack-dev-server to serve everything in the /dist/ folder from itself, while allowing everything else on the site to be served via "http://my.server"?

Here's my webpack.config.js file for reference:

var path = require('path')
var webpack = require('webpack')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'build.js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
            // the "scss" and "sass" values for the lang attribute to the right configs here.
            // other preprocessors should work out of the box, no loader config like this nessessary.
            'scss': 'vue-style-loader!css-loader!sass-loader',
            'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
          }
          // other vue-loader options go here
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.common.js'
    }
  },
  devServer: {
    publicPath: '/dist/',
    historyApiFallback: true,
    noInfo: false,
    proxy: [{
      context: function(pathname, req) {
        // exclude /src/ and /dist/
        return !pathname.match("^/(src|dist)/");
      },
      target: {
        "host": "my.server",
        "protocol": 'http:',
        "port": 80
      },
      ignorePath: false,
      changeOrigin: true,
      secure: false
    }]
  },
  performance: {
    hints: false
  },
  devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}

While likely unnecessary to answer this question, if you'd like additional background, my initial problem (and solution to that problem) are located here: Using a simple vue.js/webpack setup, how does one configure the dev server to proxy everything EXCEPT a few .js and .vue files?

Eldest answered 2/2, 2017 at 23:49 Comment(2)
this question would be greatly improved if all the background information was removed. Is the fact that you company has a CMS, etc. relevant? No. Just state what you want and what you've tried etc. Forget all the motivation etc. no one cares.Twicetold
@david-vasquez I careEstabrook
K
2

I've mostly got this working with a .NET app. It still serves the dev files from localhost:8080 but takes care of modifying the template files for you during dev and adjusting them back for production. Not sure if it would solve your problem entirely, that way, but it's working for us, for now and may help others, so I'll leave it here anyway.

In package.json I've got a start (dev) and build (prod) script:

"start": "webpack --config webpack.dev.js && webpack-dev-server --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"

webpack.prod.js just sets mode: "production" and merges with webpack.config.js which does most of the webpack stuff, including injecting the files into the .net _Layout_React.cshtml file including the productions scripts from the Scripts folder:

const HtmlWebPackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const path = require('path');

module.exports = {
  entry: {
    main: './src/index.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
          },
        ],
      },
      {
        test: /\.scss$/,
        use: [
          'style-loader', // creates style nodes from JS strings
          'css-loader', // translates CSS into CommonJS
          'sass-loader', // compiles Sass to CSS, using Node Sass by default
        ],
      },
    ],
  },
  plugins: [
    new HtmlWebPackPlugin({
      template: '../../../Views/Shared/_Layout_Template.cshtml',
      filename: '../../Views/Shared/_Layout_React.cshtml',
    }),
    new webpack.HashedModuleIdsPlugin(),
  ],
  output: {
    path: path.resolve(__dirname, '../../../Scripts/React/'),
    publicPath: '/Scripts/React/',
    filename: '[name].[contenthash].production.js',
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
      },
    },
  },
};

When I run npm run build this builds the production _Layout_React.cshtml template which is used in the app and includes files from the filesystem. However, when I run npm start it changes the _Layout_React.cshtml template to include files from localhost:8080 which is where the webpack-dev-server is running and serving watched files from:

webpack.dev.js:

const merge = require('webpack-merge');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const webpack = require('webpack');
const baseConfig = require('./webpack.config.js');

module.exports = merge(baseConfig, {
    mode: "development",
    devtool: 'eval-source-map',
    devServer: {
        open: false,
    },
    output: {
        filename: '[name].development.js',
        publicPath: 'http://localhost:8080/dist/',
    },
});

Now when I run npm start then run the .NET app, I get .NET app on localhost:33401 but it's getting it's react files from localhost:8080 and auto-compiling them on save and when it's time to push to the repo I run npm run build and it builds the files into hard files in the .NET Scripts folder and updates the template to reflect this.

Kreda answered 10/10, 2018 at 12:54 Comment(2)
Thanks for this -- I wish I could upvote it twice.Estabrook
@Estabrook no problem. Hope it was helpful.Kreda
D
0

Change the publicPath: '/dist/' of webpack config to match your actual product path and then change the script SRC in index.html to point to the new public path.. i.e basically virtual path... Not necessarily need to be present on actual file system.. I have achieved the same in my project..

Diarmuid answered 3/2, 2017 at 4:19 Comment(1)
Thanks for the response Ravi. I'm not quite sure what you're suggesting, though, as the files on the server are served at /dist/. I would assume my virtual path would be exactly the same whether it's localhost/dist or my.server/dist as I set them up to use those folders specifically to ensure everything was equal, unless you're suggesting I use the filesystem path (\\server\some\folder\sitefolder\dist\file.js), but I doubt that's what you meant.Eldest
B
0

Think the issue is caused by using this host: http://my.server instead of the default http://localhost:8080

Try to start webpack-dev-server with the flag --host 0.0.0.0 and --port 80

`--host <hostname/ip>`: hostname or IP. `0.0.0.0` binds to all hosts.

https://webpack.github.io/docs/webpack-dev-server.html#webpack-dev-server-cli

Bac answered 3/2, 2017 at 10:3 Comment(2)
Thanks for the response chimurai. I tried doing this, but the result ends up the same: the resources 404 at my.server/dist . I also ran into a problem running on port 80 - as OSX does not allow that without sudo. I tried it anyways, even though I understand the risks, just to see what would happen, and it still failed with the same issue. I'm not sure why I would want to bypass my.server, though, as the entire backend runs off of that, and I cannot run my app without it. Keep in mind, I'm not running the backend locally, only the front-end (stuff in the /dist/ folder).Eldest
Just to clarify the server setup: Backend is running on parallels on my Mac, setup on an IIS server, running razor/.Net/etc. All Windows. This is the hand I was dealt, and I cannot change it (as much as I would like to). I have my mac hosts file set to point to the backend's IP address at "my.server". The webpack-dev-server and vue.js front-end runs on the Mac (localhost:8080), and I'm trying to serve everything together as one.Eldest

© 2022 - 2024 — McMap. All rights reserved.