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

相關問題