Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

isomorphic reactjs cdn assets

So I'm almost done with my first (isomorphic) ReactJS and when we deployed it, it was kinda slow to finish build.js. One suggestion was to use CDN to separate asset fetching (cdn0, cdn1, cdn2...) and I was wondering how I'd do that in my site. Locally my structure is

- build/
- config/
  - webpack-development.config.js
  - webpack-production.config.js
- node_modules/
- package.json
- public/
  - assets/ // (this is where my assets are)
    - css/
    - img/
  - build.js
- README.md
- src/
- views/

and my index.ejs is like this now

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <base href="/" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
    <link rel="shortcut icon" type="image/x-icon" href="assets/img/ico-a-brain.png" />
    <link rel="stylesheet" href="assets/css/normalize.css">
    <link rel="stylesheet" href="assets/css/all.css">
    <!-- bunch more assets here -->
  </head>

  <body>
    <script type="text/javascript">
      window.__INITIAL_STATE__ = <%- JSON.stringify(initialState) %>;
    </script>

    <div id="app"><%- markup %></div>
    <script src="build.js"></script>
  </body>
</html>

and some components that has images

import React from 'react';

export default class HiwComponent extends React.Component {
  render() {
    return (
      <main className="box-960 box-center"> 

        <h1 className="mt-64">How It Works</h1>

        <ul id="how">
          <li>
            <img src="assets/img/ico-how-time.svg" onError={() => { this.onerror=null; this.src='assets/img/ico-how-time.png' }} alt="Pick" />
            <p><b>Pick</b> a time</p>
          </li>
          <li>
            <img src="assets/img/ico-how-plane.svg" onError={() => { this.onerror=null; this.src='assets/img/ico-how-plane.png' }} alt="Send" />
            <p><b>Send</b> request</p>
          </li>
        </ul>
      </main>
    )
  }
}

How do I start changing this to use CDN? Do you guys use some package to handle it? Basically I think it should be like locally it would still be using ./assets/css/some.css and ./assets/img/some.jpg and when in production it would look at maybe http://cdn0.amazon.com/assets/css/some.css or http://cdn1.amazon.com/assets/img/some.jpg

like image 941
index Avatar asked Oct 18 '22 09:10

index


1 Answers

UPDATE 2:

if you want to randomly replace path with a cdn url (as per your question below) you could easily modify the path replace plugin script to allow that feature.

I created a quick example for you, based on the path-replace-plugin source code

var fs = require('fs');
var fileExists = require('file-exists');
var loaderUtils = require('loader-utils');
var CDNs = [
  '//cdn0.amazon.com',
  '//cdn1.amazon.com',
  '//cdn2.amazon.com',
];

module.exports = function(source) {
this.cacheable && this.cacheable();
var options = loaderUtils.parseQuery(this.query);

    if (this.resourcePath.indexOf(options.path) > -1) {
        var cdn = CDNs[Math.floor(Math.random()*CDNs.length)];
        var newPath = this.resourcePath.replace(options.path, cdn + options.replacePath);
        if (fileExists(newPath)) {
            // Introduce file to webpack in order to make them watchable
            this.dependency(newPath);
            return fs.readFileSync(newPath);
        }
    }

    return source;
};

module.exports.raw = true;

UPDATE:

An even simpler way is to use the path replace plugin in Webpack. That way you don’t have to add any complexity to your JS code

module.exports = {
  module: {
    loaders: [
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loader: 'path-replace?path=assets&replacePath=//cdn.amazon.com/assets'
      }
    ]
  }
};

I hope that helps.

--

(original answer)

If you use Webpack then your prod build can inject a flag (variable) that you can use in the app to know if you're in prod or develop.

Even this:

new webpack.DefinePlugin({
  'process.env': {
    NODE_ENV: '"production"'
  },
  __DEV__: false,

Now that you know that you can use it in your custom function getImageUrl() that you can share via JS modules.

environment.js

function getImageUrl() {
    return __DEV__ ? '/' : '//cdn.amazon.com/';
}

export const imgUrl = getImageUrl();

HiwComponent.js

import React from 'react';
import { imgUrl } from './environment';

export default class HiwComponent extends React.Component {
  render() {
    return (
      <main className="box-960 box-center"> 

        <h1 className="mt-64">How It Works</h1>

        <ul id="how">
          <li>
            <img src={`${imgUrl}assets/img/ico-how-time.svg`} onError={() => { this.onerror=null; this.src=`${imgUrl}assets/img/ico-how-time.png` }} alt="Pick" />
            <p><b>Pick</b> a time</p>
          </li>
          <li>
            <img src={`${imgUrl}assets/img/ico-how-plane.svg`} onError={() => { this.onerror=null; this.src=`${imgUrl}assets/img/ico-how-plane.png` }} alt="Send" />
            <p><b>Send</b> request</p>
          </li>
        </ul>
      </main>
    )
  }
}
like image 96
Grgur Avatar answered Oct 21 '22 05:10

Grgur