Gatsby: Question: Putting Assets in a Different Folder

Created on 5 Oct 2018  路  14Comments  路  Source: gatsbyjs/gatsby

Summary

I'm a growth engineer @DataCamp, and I'm running an experiment that involves rewriting our home page in Gatsby to measure gains in performance and conversion metrics.

We plan to reverse proxy the homepage on datacamp.com to split 50% of traffic between our current application and our new Gatsby application.

The problem we're running into is that every JS, CSS, and other file that Gatsby generates would also need to be reverse proxied in order for this to work.

So far as I've been able to see, Gatsby does not provide a mechanism to store such files in a separate directory (which would make it easy to reverse proxy all of the traffic there).

Does Gatsby (or a plugin) provide a way to store all of these files in a single directory?

Alternatively, does Gatsby provide a way to prefix calls to these assets if they are being hosted elsewhere (i.e. on a separate subdomain)?

Relevant information

Potentially relevant past issues, PRs, and plugins: #6346, https://github.com/madecomfy/gatsby-plugin-asset-path

Most helpful comment

@siddv Yup! Here's part of the code we're currently using in gatsby-node.js. It's pretty bad and makes a lot of assumptions. I'm hoping not to have to refactor it though and am waiting to see what happens with #10933 馃槀

The string that we use to identify a file that should be routed to AWS rather than our server is marketingasset. It's just hardcoded in there for now.

Note: I'm assuming this is very brittle and has the potential to break in surprising ways with little to no warning.

const path = require('path');

exports.onCreateWebpackConfig = ({
  stage,
  rules,
  loaders,
  plugins,
  actions,
  getConfig,
  setWebpackConfig,
}) => {
  if (stage === 'build-javascript') {
    let config = getConfig();
    config.output.filename = 'marketingasset-[name]-[contenthash].js';
    config.output.chunkFilename = 'marketingasset-[name]-[contenthash].js';

    function replaceFilePathsInOptions(options) {
      if (options.name) {
        options.name = 'static/marketingasset-[name]-[hash].[ext]';
      } else if (options.localIdentName) {
        options.localIdentName =
          'marketingasset--[name]--[local]--[hash:base64:5]';
      }
    }

    config.module.rules.map(rule => {
      if (rule.oneOf) {
        rule.oneOf.map(one => {
          if (one.use) {
            one.use.map(use => {
              if (use.options) {
                replaceFilePathsInOptions(use.options);
              }
              return use;
            });
          }
          return one;
        });
      } else if (rule.use) {
        rule.use.map(use => {
          if (use.options) {
            replaceFilePathsInOptions(use.options);
          }
          return use;
        });
      }
      return rule;
    });

    config.plugins.map(plugin => {
      if (plugin.options) {
        if (plugin.options.filename) {
          plugin.options.filename = 'marketingasset-[name].[contenthash].css"';
        }
        if (plugin.options.chunkFilename) {
          plugin.options.chunkFilename =
            'marketingasset-[name].[contenthash].css';
        }
      }
    });

    actions.replaceWebpackConfig(config);
  }
};

All 14 comments

One possible solution would be to use the path prefix feature of gatsby. If you go this route, one thing to consider is that any <Link> component you use will be relative to the gatsby site (ie will respect the path prefix when deployed. So if you are linking to other pages you will need to keep that in mind.

The other option is to deploy the gatsby site to a totally separate separate web server, so then your reverse proxy just needs to route to one server or the other.

Old issues will be closed after 30 days of inactivity. This issue has been quiet for 20 days and is being marked as stale. Reply here or add the label "not stale" to keep this issue open!

Thanks, @gatsbot. This will hopefully be addressed in #10933, but leaving it open until then 馃

Also, for anyone who comes across this and is wondering how we solved it in the meantime: we used onCreateWebpackConfig in gatsby-node.js to manually prepend a string to all filenames and chunkfilenames, thus allowing us to reverse proxy on a regular expression including that string. However, this is awful, and I'm hoping #10933 will eliminate the need for us to continue doing it this way 馃槃

Heya @jaredsilver . I'm trying to do something similar. Do you have an example of how you did this?

@siddv Yup! Here's part of the code we're currently using in gatsby-node.js. It's pretty bad and makes a lot of assumptions. I'm hoping not to have to refactor it though and am waiting to see what happens with #10933 馃槀

The string that we use to identify a file that should be routed to AWS rather than our server is marketingasset. It's just hardcoded in there for now.

Note: I'm assuming this is very brittle and has the potential to break in surprising ways with little to no warning.

const path = require('path');

exports.onCreateWebpackConfig = ({
  stage,
  rules,
  loaders,
  plugins,
  actions,
  getConfig,
  setWebpackConfig,
}) => {
  if (stage === 'build-javascript') {
    let config = getConfig();
    config.output.filename = 'marketingasset-[name]-[contenthash].js';
    config.output.chunkFilename = 'marketingasset-[name]-[contenthash].js';

    function replaceFilePathsInOptions(options) {
      if (options.name) {
        options.name = 'static/marketingasset-[name]-[hash].[ext]';
      } else if (options.localIdentName) {
        options.localIdentName =
          'marketingasset--[name]--[local]--[hash:base64:5]';
      }
    }

    config.module.rules.map(rule => {
      if (rule.oneOf) {
        rule.oneOf.map(one => {
          if (one.use) {
            one.use.map(use => {
              if (use.options) {
                replaceFilePathsInOptions(use.options);
              }
              return use;
            });
          }
          return one;
        });
      } else if (rule.use) {
        rule.use.map(use => {
          if (use.options) {
            replaceFilePathsInOptions(use.options);
          }
          return use;
        });
      }
      return rule;
    });

    config.plugins.map(plugin => {
      if (plugin.options) {
        if (plugin.options.filename) {
          plugin.options.filename = 'marketingasset-[name].[contenthash].css"';
        }
        if (plugin.options.chunkFilename) {
          plugin.options.chunkFilename =
            'marketingasset-[name].[contenthash].css';
        }
      }
    });

    actions.replaceWebpackConfig(config);
  }
};

Thanks a lot @jaredsilver! We were trying something similar, but using paths and trying to move the asset files into subfolders. Was causing _a lot_ of issues. Renaming the files seems to work _much_ better. Thanks for this!

Hiya!

This issue has gone quiet. Spooky quiet. 馃懟

We get a lot of issues, so we currently close issues after 30 days of inactivity. It鈥檚 been at least 20 days since the last update here.

If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!

Thanks for being a part of the Gatsby community! 馃挭馃挏

@jaredsilver This looks great - we've been struggling with this recently too, so we're going to give this a try! Thanks :)

鈩癸笍Functionality will be added in https://github.com/gatsbyjs/gatsby/pull/12128. Thanks, @DSchau!

Hey again!

It鈥檚 been 30 days since anything happened on this issue, so our friendly neighborhood robot (that鈥檚 me!) is going to close it.

Please keep in mind that I鈥檓 only a robot, so if I鈥檝e closed this issue in error, I鈥檓 HUMAN_EMOTION_SORRY. Please feel free to reopen this issue or create a new one if you need anything else.

Thanks again for being part of the Gatsby community!

I don鈥檛 seem to have permissions to reopen the issue 馃槩

@DSchau could you reopen it?

Also, is Gatsbot malfunctioning? This issue definitely had activity within the past 30 days!

@jaredsilver Hi Jared, we are having a similar issue and I am trying to put all assets to a different sub-folder like public/assets. I am wondering if this is what you were trying to achieve? Or you wanted to put them into a different folder like /assets? The reason I asked is that it seems to me that my goal could be achieved by doing some custom webpack config but I am trying to confirm that before I start to dig into it. Thanks in advance!

Published and available in [email protected]. Specifically, the following packages have been augmented with assetPrefix functionality.

Soon enough, the documentation will be available at /docs/asset-prefix/ (waiting for the build to complete), but you can get a sneak peek here

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andykais picture andykais  路  3Comments

rossPatton picture rossPatton  路  3Comments

benstr picture benstr  路  3Comments

jimfilippou picture jimfilippou  路  3Comments

ferMartz picture ferMartz  路  3Comments