Webpack dev server throws error - Refused to execute script because its MIME type ('text/html') is not executable

16,450

Solution 1

Looking into Webpack further we should be clear about what Webpack is and what it is used for. Webpack is front end tool, it will build front end projects and has the capability of managing tasks similar to gulp/grunt. It can be a server to serve static content. But what it is not is a full fledged back end server. You can't easily build back end API and manage complex routing. This includes things like login functionality. Instead of reinventing the wheel, use Webpack as a dev tool to easily modify and see the updated result for web design. And if you need more functionality integrate Webpack by running it in watch mode and run the back end server at the same time and setup a proxy so that Webpack will defer to the back end server for complex routing. You can use any back end technology, though Webpack is built on Common.js library so integrating it into node.js and express seems to be the easiest because they are part of a javascript ecosystem.

If I could comment I would, anyhow, I was reading through the webpack docs for the DevServer and I Think that the server is responding with the incorrect MIME type possibly because it isn't finding the bundle.js script where it is expecting it. I noticed the console output being 'http://localhost:8090/auth/bundle.js' and in the documentation the dev server expects it in the root. I think that if bundle.js is really in the auth directory that you may need to tell the server where it is with the publicPath option.

output: {
  filename: 'bundle.js',
  sourceMapFilename: '[file].map',
  path: path.resolve('build/js/),// moves the bundle.js out of the root
  publicPath: '/auth/' // it is recommended that the publicPath is declared in both output and devServer
  // publicPath links the path of bundle.js to this path in the html.
},
devServer: {
  contentBase: path.resolve(__dirname), // New
  historyApiFallback: true,
  publicPath: "/auth/" // Both publicPath options should be the same as what is in your html loading the scripts
},

As I understand the webpack dev server, the bundle.js is not written to disc. It is served virtually.

Now with all of this there is a need to either proxy the already built node.js server or build one to handle just the api you need to use. Webpack provides a dev middleware module to use as middleware in a basic node.js express server. You can see the basics of the middleware here. What you really need to start with from the documentation is installing via npm webpack-dev-middleware and express

npm install --save-dev webpack-dev-middleware express

Then create a new server file like index.js in the root of the project because you already have a server.js. Now create the basic server that you need with only the routing and packages you need to handle the api calls.

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
  publicPath: config.output.publicPath
}));

// Serve the files on port 3000.
app.listen(3000, function () {
  console.log('Example app listening on port 3000!\n');
});

This is from the webpack website and you will need to do your own api routing. And you would run the project like a normal node project and it should handle the bundle.js requests.

And let's not forget that there is a plubin for koa koa-webpack-dev.I haven't personally used koa, but if you need it you can see how to use it here.

Solution 2

i had a similar issue and thought i'd post my solution incase anyone had the same. basically, i was trying to refresh my app on a dynamic subroute, localhost:3000/route/dynamicRoute, and it was throwing a similar error to what's mentioned in the question. i solved my issue by adding publicPath: '/' to my output settings in my webpack config. the following is my webpack.config.js for reference.

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

const outputDirectory = 'dist';

module.exports = {
 entry: ['babel-polyfill', './src/client/index.js'],
 output: {
  path: path.join(__dirname, outputDirectory),
  filename: 'bundle.js',
  publicPath: '/'
 },
 module: {
  rules: [
   {
    test: /\.js$/,
    exclude: /node_modules/,
    use: {
     loader: 'babel-loader'
    }
  },
  {
   test: /\.css$/,
   use: ['style-loader', 'css-loader']
  },
  {
   test: /\.(pdf|jpg|png|gif|svg|ico)$/,
    use: [
     {
      loader: 'url-loader'
     },
    ]
   }
 ]
},
devServer: {
  port: 3000,
  open: true,
  proxy: {
   '/api': 'http://localhost:8080'
  },
  historyApiFallback: true,
  contentBase: './public/index.html',
  hot: true
 },
 plugins: [
  new CleanWebpackPlugin([outputDirectory]),
  new HtmlWebpackPlugin({
   template: './public/index.html',
   favicon: './public/favicon.ico'
  })
 ]
};
Share:
16,450
Matt
Author by

Matt

Updated on June 09, 2022

Comments

  • Matt
    Matt almost 2 years

    I use Webpack bundler and Webpack dev server for local development. The front-end is in React.js+Redux and the back-end in Node.js and koajs.

    In back-end, I use passportjs library for user authentication and other libraries koa-passport, passport-facebook, passport-google-auth for authentication through Facebook or Google. Basically, I implemented koa-passport-example.

    If my application wants to redirect user to Facebook or Google login page, Webpack dev server throws error:

    GET http://localhost:8090/auth/bundle.js net::ERR_ABORTED
    
    Refused to execute script from 'http://localhost:8090/auth/bundle.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
    

    If I generate bundle by Webpack and host it on Node.js server, I don't get this error. I need to find out how to set up Webpack dev server to get rid of this error message.

    package.json

        "scripts": {
        "debug": "./node_modules/nodemon/bin/nodemon.js --inspect ./script/server.js",
        "webpack": "npm run serve | npm run dev",
        "start": "node ./script/server.js",
        "serve": "./node_modules/.bin/http-server -p 8080",
        "dev": "webpack-dev-server -d --progress --colors --port 8090 --hot --inline",
      },
            "dependencies": {
            "@koa/cors": "^2.2.1",
            "actions": "^1.3.0",
            "aws-s3-form": "^0.3.5",
            "aws-sdk": "^2.165.0",
            "axios": "^0.16.2",
            "bootstrap": "^3.3.7",
            "bootstrap-timepicker": "github:janzenz/bootstrap-timepicker#feature/compatibility-es6",
            "d3-ease": "^1.0.3",
            "d3-selection": "^1.1.0",
            "d3-shape": "^1.2.0",
            "d3-transition": "^1.1.0",
            "font-awesome": "^4.7.0",
            "http-server": "^0.10.0",
            "immutable": "^3.8.2",
            "jquery": "^3.2.1",
            "jquery-ui": "^1.12.1",
            "jquery.panzoom": "^3.2.2",
            "jsonwebtoken": "^8.1.0",
            "juration": "^0.1.0",
            "knex": "^0.14.2",
            "koa": "^2.3.0",
            "koa-body": "^2.5.0",
            "koa-bodyparser": "^4.2.0",
            "koa-logger": "^3.1.0",
            "koa-passport": "^4.0.1",
            "koa-ratelimit": "^4.0.0",
            "koa-router": "^7.2.1",
            "koa-send": "^4.1.1",
            "koa-session": "^5.5.1",
            "koa-static": "^4.0.2",
            "moment": "^2.18.1",
            "objection": "^0.9.2",
            "oembed-auto": "0.0.3",
            "passport": "^0.4.0",
            "passport-facebook": "^2.1.1",
            "passport-google-oauth": "^1.0.0",
            "passport-jwt": "^3.0.1",
            "pg": "^7.4.0",
            "probe-image-size": "^3.1.0",
            "puppeteer": "^0.12.0",
            "react": "^15.6.1",
            "react-dom": "^15.6.1",
            "react-dropzone": "^4.2.1",
            "react-facebook-login": "^3.6.2",
            "react-google-login": "^3.0.2",
            "react-modal": "^3.1.2",
            "react-redux": "^5.0.6",
            "react-router": "^4.2.0",
            "react-router-dom": "^4.2.2",
            "react-router-redux": "^4.0.8",
            "react-share": "^1.17.0",
            "react-transition-group": "^1.2.1",
            "react-twitter-widgets": "^1.7.1",
            "redux": "^3.7.2",
            "redux-thunk": "^2.2.0",
            "request": "^2.83.0",
            "request-promise-native": "^1.0.5",
            "select2": "^4.0.4",
            "select2-bootstrap-theme": "0.1.0-beta.10",
            "shave": "^2.1.3",
            "sqlite3": "^3.1.13",
            "sugar-date": "^2.0.4",
            "svg-url-loader": "^2.3.0",
            "twitter": "^1.7.1",
            "twitter-widgets": "^1.0.0",
            "unfluff": "^1.1.0"
          },
          "devDependencies": {
            "autoprefixer": "^7.1.4",
            "babel": "^6.23.0",
            "babel-core": "^6.26.0",
            "babel-loader": "^7.1.2",
            "babel-preset-es2015": "^6.24.1",
            "babel-preset-react": "^6.24.1",
            "css-loader": "^0.28.7",
            "duplicate-package-checker-webpack-plugin": "^2.0.2",
            "eslint": "^4.7.2",
            "eslint-config-airbnb": "^15.1.0",
            "eslint-plugin-import": "^2.7.0",
            "eslint-plugin-jsx-a11y": "^5.1.1",
            "eslint-plugin-react": "^7.4.0",
            "favicons-webpack-plugin": "0.0.7",
            "file-loader": "^0.11.2",
            "friendly-errors-webpack-plugin": "^1.6.1",
            "html-webpack-plugin": "^2.30.1",
            "less": "^2.7.2",
            "less-loader": "^4.0.5",
            "node-sass": "^4.5.3",
            "nodemon": "^1.12.1",
            "npm-install-webpack-plugin": "^4.0.5",
            "postcss": "^6.0.11",
            "postcss-loader": "^2.0.6",
            "sass-loader": "^6.0.6",
            "style-loader": "^0.18.2",
            "url-loader": "^0.5.9",
            "webpack": "^3.6.0",
            "webpack-dev-server": "^2.9.1",
            "webpack-merge": "^4.1.0",
            "webpack-notifier": "^1.5.0"
          }
    

    webpack.config.js

    const webpack = require('webpack');
    const webpackMerge = require('webpack-merge');
    const path = require('path');
    const WebpackNotifierPlugin = require('webpack-notifier');
    const autoprefixer = require('autoprefixer');
    
    const TARGET = process.env.npm_lifecycle_event;
    console.log(`target event is ${TARGET}`);
    
    let outputFileName = 'app';
    outputFileName += TARGET === 'prod' ? '.min.js' : '.js';
    
    const common = {
      entry: {
        app: './index.jsx',
      },
      module: {
        rules: [
          {
            test: /\.js[x]?$/,
            exclude: /(node_modules|bower_components)/,
            use: {
              loader: 'babel-loader?presets[]=es2015&presets[]=react',
            },
          },
          {
            test: /\.scss$/,
            loaders: [
              'style-loader',
              'css-loader',
              'sass-loader',
            ],
          },
          {
            test: /\.less$/,
            loaders: ['style-loader', 'css-loader', 'less-loader'],
          },
          {
            test: /\.css$/,
            use: ['style-loader', 'css-loader'],
          },
          {
            test: /\.(eot|ttf|svg|gif|png|jpg|otf|woff|woff2)$/,
            loader: 'url-loader',
          },
        ],
      },
      plugins: [
        new webpack.ProvidePlugin({
          jQuery: 'jquery',
          $: 'jquery',
          jquery: 'jquery',
          'window.jQuery': 'jquery',
        }),
        new webpack.LoaderOptionsPlugin({
          options: {
            postcss: [
              autoprefixer({
                browsers: ['last 3 versions'],
              }),
            ],
          },
        }),
        new WebpackNotifierPlugin(),
      ],
    };
    
    if (TARGET === 'dev' || !TARGET) {
      module.exports = webpackMerge(common, {
        devtool: 'eval-source-map',
        output: {
          filename: 'bundle.js',
          sourceMapFilename: '[file].map',
        },
        devServer: {
          contentBase: path.resolve(__dirname), // New
          historyApiFallback: true,
        },
      });
    }
    

    login.jsx

    ...
        <a href="/auth/facebook" className="btn btn--secondary ut-font-decima">Login</a>
    ...
    

    server.js

    const Koa = require('koa');
    const Router = require('koa-router');
    const logger = require('koa-logger');
    const cors = require('@koa/cors');
    const bodyParser = require('koa-bodyparser');
    const serve = require('koa-static');
    const path = require('path');
    const session = require('koa-session');
    
    const app = new Koa();
    // trust proxy
    app.proxy = true;
    
    const router = new Router();
    
    // sessions
    app.keys = ['your-session-secret'];
    app.use(session({}, app));
    
    app.use(logger());
    app.use(cors());
    app.use(bodyParser());
    
    require('./controllers/auth');
    const passport = require('koa-passport');
    
    app.use(passport.initialize());
    app.use(passport.session());
    
    app.use(serve(path.join(process.env.PWD, '/dist')));
    
    router
      .get('/auth/facebook', passport.authenticate('facebook'))
      .get(
        '/auth/facebook/callback',
        passport.authenticate('facebook', {
          successRedirect: '/podcast',
          failureRedirect: '/',
        }),
      );
    
    app.use(router.routes()).use(router.allowedMethods());
    
    // don't listen to this port if the app is required from a test script
    if (!module.parent) {
      app.listen(process.env.PORT || 1337);
      console.log('app listen on port: 1337');
    }
    
  • Matt
    Matt over 6 years
    Thanks for response. I see, what you mean. I don't know why is output bundle being in path http://localhost:8090/auth/bundle.js, when redirect happens. When I try your suggestion and start my project without login, I get the same error message for http://localhost:8090/bundle.js. I think, I need to set up publicPath for root and /auth/, but I am not sure if it is possible.
  • RickyM
    RickyM over 6 years
    I think that the issue with the third party login has to do with how webpack handles those api calls. You may have to build your own custom webpack dev server to mimic a node server to handle those responses. Until then you can try to proxy those to your already built node server.
  • Alan P.
    Alan P. almost 6 years
    It was adding publicPath to the output in the webpack config that fixed it for me.
  • monokrome
    monokrome almost 5 years
    As nice as this information may be, it doesn't really answer the question in the original post. The issue is the browser aborting the request, not the server not sending the data at the given URL.