質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

2990閲覧

webpack-dev-serverでCORSが回避できない。

yu-imu

総合スコア35

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/05/19 15:58

編集2020/05/20 01:14

実現したいこと

webpack-dev-serverで開発できるように環境を構築したい。
webpackへ置き換えてwebpack --progress --mode=developmentでは正常に動作するが、
webpack-dev-serverでassetsを取得するとCORSが発生し画面ロードが途中で消えてしまう。

背景

CORS対策として、webpack.config.jsに'Access-Control-Allow-Origin': '*',等を記入しても効果がなく
調べても良さそうなアイディアがなかったので質問しました。

構成

元々webpackerをベースにしたruby on rails × reactで動くアプリケーションを
http://localhost:3000/ にrailsのアプリケーションを起動
http://localhost:3035/ にwebpack-dev-serverを起動

発生している問題・エラーメッセージ

chromeでhttp://localhost:3000/をアクセスした場合です。
http://localhost:3035/には、CORSを対策したheaderが付与されリクエストは通るのですが、
rails側のhttp://localhost:3000/にアクセスすると headerが付与されず失敗となります。(※添付画像参照)

scheduler.development.js:178 Uncaught Error: A cross-origin error was thrown. React doesn't have access to the actual error object in development. See https://fb.me/react-crossorigin-error for more information.

原因画像
※webpackおよびrails側のログにはエラーはありません。

ソースコード

webpack.config.js
→devServer箇所を追記

const path = require('path') const glob = require('glob') const webpack = require('webpack') const ManifestPlugin = require('webpack-manifest-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') let entries = {} glob.sync('./frontend/**/*.{js,jsx,css,scss,sass}').map(function (file) { let name = file.split('/')[2].split('.')[0] entries[name] = file }) module.exports = (env, argv) => { const IS_DEV = argv.mode === 'development' return { entry: entries, output: { filename: 'javascripts/[name]-[hash].js', path: path.resolve(__dirname, 'public/assets') }, plugins: [ new MiniCssExtractPlugin({ filename: 'stylesheets/[name]-[hash].css' }), new ManifestPlugin({ writeToFileEmit: true }), new webpack.HotModuleReplacementPlugin(), ], module: { rules: [ { test: /.(c|sc)ss$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { publicPath: path.resolve(__dirname, 'public/assets/stylesheets') } }, 'css-loader', 'sass-loader' ] }, { test: /.jsx$/, use: [ { loader: 'babel-loader?cacheDirectory', query: { presets: [ "@babel/preset-env", "@babel/preset-react", ] } } ], exclude: /node_modules/, }, { test: /.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, loader: 'file-loader', options: { name: '[name]-[hash].[ext]', outputPath: 'images/', publicPath: function (path) { return 'images/' + path } } } ], }, resolve: { extensions: ['.js', '.scss', 'css', '.jsx', '.jpg', '.png', '.gif', ' '] }, devServer: { host: 'localhost', port: 3035, publicPath: 'http://localhost:3035/public/assets/', contentBase: path.resolve(__dirname, 'public/assets'), hot: true, disableHostCheck: true, historyApiFallback: true, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS", "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization" } } } }

/app/helpers/webpack_bundle_helper.rb
→manifest.jsonを修正

require "open-uri" module WebpackBundleHelper class BundleNotFound < StandardError; end def javascript_bundle_tag(entry, **options) path = asset_bundle_path("#{entry}.js") options = { src: path, defer: true }.merge(options) # async と defer を両方指定した場合、ふつうは async が優先されるが、 # defer しか対応してない古いブラウザの挙動を考えるのが面倒なので、両方指定は防いでおく options.delete(:defer) if options[:async] javascript_include_tag '', **options end def stylesheet_bundle_tag(entry, **options) path = asset_bundle_path("#{entry}.css") options = { href: path }.merge(options) stylesheet_link_tag '', **options end def image_bundle_tag(entry, **options) raise ArgumentError, "Extname is missing with #{entry}" unless File.extname(entry).present? image_tag asset_bundle_path(entry), **options end private def asset_server port = Rails.env === "development" ? "3035" : "3000" "http://#{request.host}:#{port}" end def pro_manifest File.read("public/assets/manifest.json") end def dev_manifest OpenURI.open_uri("#{asset_server}/public/assets/manifest.json").read end def manifest return @manifest ||= JSON.parse(pro_manifest) if Rails.env.production? return @manifest ||= JSON.parse(dev_manifest) if Rails.env.development? end def valid_entry?(entry) return true if manifest.key?(entry) raise BundleNotFound, "Could not find bundle with name #{entry}" end def asset_bundle_path(entry, **options) valid_entry?(entry) asset_path("#{asset_server}/public/assets/" + manifest.fetch(entry), **options) end end

補足情報(FW/ツールのバージョンなど)

railsにcors対策でgem 'rack-cors'を入れたこともありますが、効果がなかったです。

参考にした資料
Rails環境でJS , CSSをwebpackで完全に管理する

フロントエンド原理主義者が目論んだ脱webpacker

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

Rails側でdev-serverへプロキシを通す実装を行いました。
実装は、「フロントエンド原理主義者が目論んだ脱webpacker」を参考にmiddlwareを作成しました。

自分の場合は、jsとimageと lazy loadしたjsの3つがlocalhost:3000からlocalhost:3035の任意のパスにアクセスできるように力技で実装しました。(※lazy loadしたreactがうまくproxyを通らず別実装にしましたがそこに気づくまでが大変でした。)

ruby

1require "rack/proxy" 2 3class DevServerProxy < Rack::Proxy 4 5 def initialize(app) 6 @app = app 7 end 8 9 def perform_request(env) 10 if env["PATH_INFO"].include?("/images/") 11 #画像関連 12 change_http_host(env) 13 env["PATH_INFO"] = "/images/" + env["PATH_INFO"].split("/").last 14 super 15 elsif env["PATH_INFO"].include?("/packs/") 16 #通常のReactコード 17 change_http_host(env) 18 super 19 elsif env["PATH_INFO"].match("/.+\-.+.js") 20 #lazy loadしているReactコード 21 change_http_host(env) 22 env["PATH_INFO"] = "/packs/" + env["PATH_INFO"].split("/").last 23 super 24 else 25 @app.call(env) 26 end 27 end 28 29 private 30 31 def change_http_host(env) 32 dev_server = env["HTTP_HOST"].gsub(":3000", ":3035") 33 env["HTTP_HOST"] = dev_server 34 env["HTTP_X_FORWARDED_HOST"] = dev_server 35 env["HTTP_X_FORWARDED_SERVER"] = dev_server 36 end 37end

投稿2020/05/23 09:18

編集2020/05/23 09:24
yu-imu

総合スコア35

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問