実現したいこと
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で完全に管理する
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。