Roots Discourse

CORS header Browsersync issue

browsersync
sage9

#1

I’m not sure if I’ve set up my Browsersync correctly, or if I’m missing a configuration option, but I’m getting the following error when loading a local page via a jQuery AJAX call:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://palmtree.studios.local/app/plugins/tess-membership-manager/public/partials/view-membership-card-processor.php. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

I’ve got a VHost set up for my local-only site, palmtree.studios.local but my Broswersync is running on localhost:3000 (default config). Below is my config.json file:

{
  "entry": {
    "main": [
      "./scripts/main.js",
      "./styles/main.scss"
    ],
    "customizer": [
      "./scripts/customizer.js"
    ]
  },
  "publicPath": "/app/themes/palmtree-boilerplate",
  "devUrl": "http://palmtree.studios.local",
  "proxyUrl": "http://localhost:3000",
  "cacheBusting": "[name]_[hash:8]",
  "cors": true,
  "headers": {
    "Access-Control-Allow-Origin": "*"
  },
  "watch": [
    "app/**/*.php",
    "config/**/*.php",
    "resources/views/**/*.php"
  ]
}

I know its a BrowserSync issue, because if I actually manually go to the palmtree.studios.local site (instead of localhost:3000) the AJAX call works normally and as intended. It’s as if, because the AJAX load page is called from palmtree.studios.local and the browsersync is loading it on localhost, even though they are technically the same thing, it is being read as a load from a 3rd party website.

Or something like that.

Can I set up my VHost/Browsersync in such a way that this won’t happen?


#2

Hey @cpalm,

That’s correct, since localhost and palmtree.studios.local are different domains, as far as the browser is concerned it’s one website trying to load something from another one.

Browsersync has a CORS option that may be helpful: https://browsersync.io/docs/options#option-cors. Haven’t tested it. Give that a shot and let me know.


#3

Hey @mmirus,

Thanks for the comments. Unfortunately, as listed in my config listed above, I already have both the “cors” and “headers” options enabled. I hope it’s not a syntax thing, I believe I am adding these correctly.

On a possible different end, is there any way to set up browsersync devUrl AND proxyUrl to the same domain?


#4

Sorry about that, totally missed that you had it in there. I think you’ll need to put it in the Browsersync option in your webpack.config.watch.js file, though. In this section:

new BrowserSyncPlugin({
  target,
  open: config.open,
  proxyUrl: config.proxyUrl,
  watch: config.watch,
  delay: 500,
}),

Not sure about using your local dev domain for browsersync. I feel like it would cause problems, but not sure. It would have to at least run on a separate port and that might still violate the cross-origin policy–I haven’t gone into the weeds there before.


#5

Ah alright,

I tried a few things here:

new BrowserSyncPlugin({
      target,
      cors: true,
      open: config.open,
      proxyUrl: config.proxyUrl,
      watch: config.watch,
      delay: 500,
      proxy: {
        target: 'http://palmtree.studios.local',
        proxyRes: [
          function(proxyReq) {
            proxyReq.setHeader('Access-Control-Allow-Origin', '*');
          }
        ]
      }
    }),

Just adding “cors” = true didn’t work. So I did a little more research and added the “proxy” option:
https://browsersync.io/docs/options#option-proxy

Unfortunately, still no luck. :roll_eyes:


#6

Some other devs and me also had this issue for some time,
a workaround finally fixed it for me, see this discussion:


#7

Thanks, @strarsis - I didn’t have time to track down the syntax.

@cpalm give that a try and let us know if it fixes it.


#8

Man… this thing just does not want to work.

webpack.config.watch.js snippet:

module.exports = {
  output: {
    pathinfo: true,
    publicPath: config.proxyUrl + config.publicPath,
  },
  devtool: '#cheap-module-source-map',
  stats: false,
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new BrowserSyncPlugin({
      target,
      open: config.open,
      proxyUrl: config.proxyUrl,
      watch: config.watch,
      delay: 500,
      advanced: {
        browserSync: {
          cors: true
        }
      }
    }),
  ],
};

config.json:

{
  "entry": {
    "main": [
      "./scripts/main.js",
      "./styles/main.scss"
    ],
    "customizer": [
      "./scripts/customizer.js"
    ]
  },
  "publicPath": "/app/themes/palmtree-boilerplate",
  "devUrl": "http://palmtree.studios.local",
  "proxyUrl": "http://localhost:3000",
  "cacheBusting": "[name]_[hash:8]",
  "headers": { "Access-Control-Allow-Origin": "*" },
  "watch": [
    "app/**/*.php",
    "config/**/*.php",
    "resources/views/**/*.php"
  ]
}

#9

Hey @cpalm,

Now that I’ve had a couple of minutes to actually think about this, I believe we’re approaching the problem from the wrong side. You need to enable CORS (set the Access-Control-Allow-Origin header) on whatever is hosting your local dev environment, not on Browsersync.

  1. Your site is running on palmtree.studios.local, served by whatever local dev setup you have running
  2. You’re loading the site at localhost:3000, served by Browsersync
  3. The AJAX request from localhost:3000 hits palmtree.studios.local and palmtree.studios.local says “nope, don’t know you”

The cors Browsersync option tells Browsersync to be more relaxed when requests are made to Browsercync itself. You need the opposite: to tell whatever local hosting setup you’re running to relax, so that when Browsersync asks it for stuff it doesn’t get nervous and say no. For obvious reasons, request originators (Browsersync, in this case) can’t tell servers how secure to be.

So, you’ll need to figure out how to enable that header for whatever local dev setup you’re running.


#10

Got it. :+1:

I recently updated Apache for my WAMP instance. Turns out I didn’t have the headers module on and my vhost configuration wasn’t copied over because of that. Followed this:

And then created a .htaccess in the bedrock/web directory with:

Header set Access-Control-Allow-Origin "*"

Now all is working! Thanks a ton.


#11

Hello,

Found a solution for Access-Control-Allow-Origin.

Add to webpack.config.watch.js

devServer: {
    headers: {
        'Access-Control-Allow-Origin': '*'
    }
},

So the complete module.exports wil be like:

module.exports = {
  output: {
    pathinfo: true,
    publicPath: config.proxyUrl + config.publicPath,
  },
  devServer: {
      headers: {
          'Access-Control-Allow-Origin': '*'
      }
  },
  devtool: '#cheap-module-source-map',
  stats: false,
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new BrowserSyncPlugin({
      target,
      open: config.open,
      proxyUrl: config.proxyUrl,
      watch: config.watch,
      delay: 500,
    }),
  ],
};


#12

Hi @koentjuh1,

I believe that still only adds the headers to the resources served by Browsersync from localhost:3000, not the resources requested from the local server, in which case it wouldn’t solve the problem discussed in this thread.


#13

What about adding

    new BrowserSyncPlugin({
      target,
      open: config.open,
      proxyUrl: config.proxyUrl,
      watch: config.watch,
      delay: 500,
      advanced: {
        browserSync: {
          cors: true,
        },
      },
    }),

?


#14

Hey @strarsis - we looked into that earlier in this thread. Read through the thread for full details, or here for a summary.