Сервер разработки Webpack выдает ошибку - отказался выполнить скрипт, потому что его тип MIME ('text / html') не является исполняемым

Я использую сборщик Webpack и сервер разработки Webpack для локальной разработки. Внешний интерфейс находится на React.js + Redux, а серверный - на Node.js и koajs.

В бэкэнде я использую библиотеку паспортов для аутентификации пользователей и другие библиотеки koa-паспорт, паспорт -facebook, паспорт-google-auth для аутентификации через Facebook или Google. По сути, я реализовал пример паспорта koa .

Если мое приложение хочет перенаправить пользователя на страницу входа в Facebook или Google, сервер разработки Webpack выдает ошибку:

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.

Если я создаю пакет с помощью Webpack и размещаю его на сервере Node.js, я не получаю эту ошибку. Мне нужно узнать, как настроить сервер разработки Webpack, чтобы избавиться от этого сообщения об ошибке.

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

person Matt    schedule 27.12.2017    source источник
comment
Вы не опубликовали конфигурацию своего приложения node.js. Проблема может быть в app.use() настройках шаблонизатора и т. Д.   -  person Nah    schedule 27.12.2017
comment
Я добавил свой server.js, который использовался в серверной части. Учтите, что ошибку выдает сервер Webpack dev, а не сервер Node.js.   -  person Matt    schedule 27.12.2017


Ответы (2)


При дальнейшем изучении Webpack мы должны четко понимать, что такое Webpack и для чего он используется. Webpack - это интерфейсный инструмент, он будет создавать клиентские проекты и может управлять задачами, подобными gulp / grunt. Это может быть сервер для обслуживания статического контента. Но это не полноценный сервер. Вы не можете легко создать серверный API и управлять сложной маршрутизацией. Это включает в себя такие вещи, как функциональность входа в систему. Вместо того, чтобы изобретать колесо, используйте Webpack в качестве инструмента разработки, чтобы легко изменять и видеть обновленные результаты для веб-дизайна. А если вам нужна дополнительная функциональность, интегрируйте Webpack, запустив его в режиме просмотра и одновременно запустите внутренний сервер и настройте прокси, чтобы Webpack передавал внутреннему серверу сложную маршрутизацию. Вы можете использовать любую внутреннюю технологию, хотя Webpack построен на библиотеке Common.js, поэтому интегрировать его в node.js и express кажется самым простым делом, поскольку они являются частью экосистемы javascript.

Если бы я мог прокомментировать, я бы все равно читал документы webpack для DevServer и думаю, что сервер отвечает неправильным типом MIME, возможно, потому, что он не находит сценарий bundle.js там, где он его ожидает. Я заметил, что вывод консоли - «http://localhost:8090/auth/bundle.js» и в документации dev-сервер ожидает его в корне. Я думаю, что если bundle.js действительно находится в каталоге auth, вам может потребоваться сообщить серверу, где он находится, с помощью параметра 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
},

Насколько я понимаю, сервер webpack dev, bundle.js не записывается на диск. Обслуживается виртуально.

Теперь со всем этим необходимо либо проксировать уже построенный сервер node.js, либо создать его, чтобы обрабатывать только тот api, который вам нужно использовать. Webpack предоставляет модуль промежуточного программного обеспечения разработчика для использования в качестве промежуточного программного обеспечения на базовом экспресс-сервере node.js. Вы можете ознакомиться с основами промежуточного программного обеспечения здесь. Что вам действительно нужно для начала из документации, так это установка через npm webpack-dev-middleware и экспресс

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

Затем создайте новый файл сервера, например index.js, в корне проекта, потому что у вас уже есть server.js. Теперь создайте базовый сервер, который вам нужен, только с маршрутизацией и пакетами, которые вам нужны для обработки вызовов 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');
});

Это с веб-сайта webpack, и вам нужно будет выполнить собственную маршрутизацию api. И вы бы запустили проект как обычный проект узла, и он должен обрабатывать запросы bundle.js.

И давайте не будем забывать, что есть plubin для koa koa-webpack-dev. Я лично не использовал koa, но если он вам нужен, вы можете увидеть, как его использовать здесь.

person RickyM    schedule 02.01.2018
comment
Спасибо за ответ. Я понимаю что ты имеешь ввиду. Я не знаю, почему выходной пакет находится на пути http://localhost:8090/auth/bundle.js, когда происходит перенаправление. Когда я пробую ваше предложение и запускаю свой проект без входа в систему, я получаю такое же сообщение об ошибке для http://localhost:8090/bundle.js. Я думаю, мне нужно настроить publicPath для root и /auth/, но я не уверен, возможно ли это. - person Matt; 02.01.2018
comment
Я думаю, что проблема со сторонним входом в систему связана с тем, как webpack обрабатывает эти вызовы api. Возможно, вам придется создать свой собственный сервер разработки веб-пакетов, чтобы имитировать сервер узла для обработки этих ответов. А пока вы можете попробовать проксировать их на свой уже построенный сервер узла. - person RickyM; 02.01.2018
comment
Это было добавление publicPath к output в конфигурации веб-пакета, которое исправило это для меня. - person Alan P.; 05.06.2018
comment
Как бы хороша ни была эта информация, на самом деле она не отвечает на вопрос в исходном сообщении. Проблема в том, что браузер прерывает запрос, а не сервер, не отправляющий данные по заданному URL-адресу. - person monokrome; 13.07.2019

У меня была аналогичная проблема, и я подумал, что опубликую свое решение, если у кого-то будет аналогичная проблема. в основном, я пытался обновить свое приложение на динамическом подмаршруте localhost:3000/route/dynamicRoute, и он выдавал аналогичную ошибку. Я решил свою проблему, добавив publicPath: '/' к своим output настройкам в конфигурации моего веб-пакета. Ниже приводится мой webpack.config.js для справки.

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'
  })
 ]
};
person Ryan DuShane    schedule 18.07.2018