web-dev-qa-db-fra.com

Le serveur de développement Webpack renvoie une erreur - Refus d'exécuter le script car son type MIME ('text / html') n'est pas exécutable

J'utilise Webpack bundler et Webpack dev server pour le développement local. Le front-end est dans React.js + Redux et le back-end dans Node.js et koajs.

En back-end, j'utilise passportjs bibliothèque pour l'authentification des utilisateurs et d'autres bibliothèques koa-passport , passport-facebook , passport- google-auth pour l'authentification via Facebook ou Google. Fondamentalement, j'ai implémenté koa-passport-example .

Si mon application souhaite rediriger l'utilisateur vers la page de connexion Facebook ou Google, le serveur de développement Webpack génère une erreur:

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.

Si je génère un bundle par Webpack et l'héberge sur le serveur Node.js, je ne reçois pas cette erreur. J'ai besoin de savoir comment configurer le serveur de développement Webpack pour se débarrasser de ce message d'erreur.

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');
}
11
Matt

En examinant Webpack plus en détail, nous devons savoir clairement ce qu'est Webpack et à quoi il sert. Webpack est un outil frontal, il créera des projets frontaux et a la capacité de gérer des tâches similaires à gulp/grunt. Il peut s'agir d'un serveur pour servir du contenu statique. Mais ce qu'il n'est pas, c'est un serveur principal à part entière. Vous ne pouvez pas facilement créer une API back-end et gérer un routage complexe. Cela inclut des éléments comme la fonctionnalité de connexion. Au lieu de réinventer la roue, utilisez Webpack comme outil de développement pour modifier facilement et voir le résultat mis à jour pour la conception Web. Et si vous avez besoin de plus de fonctionnalités, intégrez Webpack en l'exécutant en mode veille et exécutez le serveur principal en même temps et configurez un proxy pour que Webpack s'en remette au serveur principal pour un routage complexe. Vous pouvez utiliser n'importe quelle technologie dorsale, bien que Webpack soit construit sur la bibliothèque Common.js, donc son intégration dans node.js et express semble être la plus simple car elle fait partie d'un écosystème javascript.

Si je pouvais commenter, je lirais de toute façon les documents du webpack pour le DevServer et je pense que le serveur répond avec le type MIME incorrect peut-être parce qu'il ne trouve pas le script bundle.js là où il l'attend. J'ai remarqué que la sortie de la console était ' http: // localhost: 8090/auth/bundle.js ' et dans la documentation, le serveur de développement l'attend à la racine. Je pense que si bundle.js est vraiment dans le répertoire auth, vous devrez peut-être dire au serveur où il se trouve avec l'option publicPath.

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
},

Si je comprends bien le serveur de développement webpack, le bundle.js n'est pas écrit sur le disque. Il est servi virtuellement.

Maintenant, avec tout cela, il est nécessaire soit de proxy le serveur node.js déjà construit ou d'en créer un pour gérer uniquement l'API que vous devez utiliser. Webpack fournit un module middleware de développement à utiliser comme middleware dans un serveur express node.js de base. Vous pouvez voir les bases du middleware ici . Ce dont vous avez vraiment besoin pour commencer à partir de la documentation, c'est d'installer via npm webpack-dev-middleware et express

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

Créez ensuite un nouveau fichier serveur comme index.js à la racine du projet car vous avez déjà un server.js. Créez maintenant le serveur de base dont vous avez besoin avec uniquement le routage et les packages dont vous avez besoin pour gérer les appels api.

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');
});

Ceci provient du site Web du webpack et vous devrez faire votre propre routage api. Et vous exécuteriez le projet comme un projet de nœud normal et il devrait gérer les demandes bundle.js.

Et n'oublions pas qu'il existe un plubin pour koa koa-webpack-dev. Je n'ai pas personnellement utilisé koa, mais si vous en avez besoin, vous pouvez voir comment l'utiliser ici .

12
RickyM

j'ai eu un problème similaire et j'ai pensé publier ma solution au cas où quelqu'un aurait un problème similaire. en gros, j'essayais de rafraîchir mon application sur une sous-route dynamique, localhost:3000/route/dynamicRoute, et il lançait une erreur similaire. j'ai résolu mon problème en ajoutant publicPath: '/' à mes paramètres output dans ma configuration webpack. ce qui suit est mon webpack.config.js pour référence.

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'
  })
 ]
};
3
Ryan DuShane