1

我使用Webpack bundler和Webpack dev服务器进行本地开发。前端位于React.js + Redux中,后端位于Node.js和koajs中。Webpack dev服务器抛出错误 - 拒绝执行脚本,因为它的MIME类型('text/html')不可执行

在后端,我使用passportjs库进行用户认证和其他库koa-passportpassport-facebookpassport-google-auth通过Facebook或谷歌认证。基本上,我实施了koa-passport-example

如果我的应用程序需要用户重定向到Facebook或谷歌登录页面,的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 dev服务器来摆脱此错误消息。

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

你没有发布你的node.js应用配置。问题可能出在模板引擎的'app.use()'设置等。 –

+0

我在后端添加了我的'server.js'。考虑到Webpack dev服务器会引发错误,而不是后端使用的Node.js服务器。 – Matt

回答

3

展望的WebPack进一步,我们应该清楚什么是的WebPack并且它的用途。 Webpack是前端工具,它将构建前端项目,并具有管理类似gulp/grunt的任务的能力。它可以是服务器来提供静态内容。但它不是一个完整的后端服务器。您无法轻松构建后端API并管理复杂的路由。这包括登录功能等。使用Webpack作为开发工具来轻松修改并查看网页设计的更新结果,而不是重新发明轮子。如果您需要更多的功能,通过在监视模式下运行它并集成Webpack并同时运行后端服务器并设置代理,以便Webpack将推迟到后端服务器进行复杂的路由。您可以使用任何后端技术,尽管Webpack建立在Common.js库上,因此将它集成到node.js和express中似乎是最简单的,因为它们是javascript生态系统的一部分。

如果我可以发表评论我会,无论如何,我正在阅读DevServer的webpack文档,我认为服务器正在响应不正确的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开发服务器,bundle.js不写入光盘。它几乎服务。

现在,所有这些都需要代理已经构建的node.js服务器或构建一个来处理您需要使用的api。 Webpack提供了一个开发中间件模块,用作基本node.js express服务器中的中间件。你可以看到中间件的基础知识here。你真正需要开始从文档通过NPM的WebPack-DEV-中间件安装和表达

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请求。

我们不要忘记,有一个卡奥koa-webpack-dev plubin。我没有亲自使用koa,但如果你需要它,你可以看到如何使用它here

+0

感谢您的回复。我明白你的意思了。我不知道为什么当重定向发生时,输出包在路径“http:// localhost:8090/auth/bundle.js”中。当我尝试你的建议并开始我的项目而没有登录时,我得到'http:// localhost:8090/bundle.js'的错误信息。我想,我需要为root和'/ auth /'设置publicPath,但我不确定是否可以。 – Matt

+0

我认为第三方登录的问题与webpack如何处理这些api调用有关。您可能必须构建自己的定制webpack dev服务器来模拟节点服务器来处理这些响应。在此之前,您可以尝试将这些代理代理到已经构建的节点服务器。 – RickyM

相关问题