gregberge / loadable-components

The recommended Code Splitting library for React ✂️✨
https://loadable-components.com
MIT License
7.58k stars 376 forks source link

Add query parameter support #998

Open Hacksign opened 4 months ago

Hacksign commented 4 months ago

🚀 Feature Proposal

When accessing some scripts, sometimes we need append a query/search parameter (a.com/?x=1&y=2), but ChunkExtractor do not support this.

Motivation

Think this scenario:

Suppose we have a website which support 2 languages: A and B, there is an nginx reverse proxy which routing accesses by query parameter ?lang=A|B.

In this scenario, we need ChunkExtractor.getScript* generate <script src='xxxxx?lang=A'></scrpt> or <script src='xxxxx?lang=B'></scrpt> DOM elements staticly or dynamicly.

But ChunkExtractor has no such ability for now :(

Example

const clientExtractor = new ChunkExtractor(
  {
    entrypoints: entrypoint,
    statsFile: path.resolve(process.cwd(), './dist/client/loadable-stats.json'),
    search: `?lang=${props.lang}`    // <--- search parameter injection
  }
);
clientExtractor.getScriptTags();

Suppose props.lang = en-US, clientExtractor.getScriptTags() will generate DOM like this:

<script .... src='/some/component/chunks.js?lang=en-US'></script>

NOTE: dynamic loaded component should stick to this rule as well.

Pitch

Now I'm modifing query parameters like this:

clientExtractor.getScriptTags().split('\n').map(
  i => i.replace(
    /(<script.*?src=['"])(.*?)(['"])/,
    `$1$2?lang=${props.lang}$3`
  )
).join('\n'),

But currently I have no idea how to modify dynamicly loaded component. And there is nothing to help by reading the API document.

theKashey commented 4 months ago

Your solution for server-side definitely works, but I am not sure if it can be adapted for client side.

The problem is - loadable is not importing scripts by itself, it's just asking webpack to do so with all script names being hardcoded in the webpack manifest.

So you have the following options:

Hacksign commented 4 months ago

Solution I currently use is adding a routing method, which is by cookie, in nginx proxy server.

Then add response.cookie('lang', language) in request handler (which is server_side_renderer function in my project), so when the first request is responsed, there will be a lang field in the continuing request in HTTP Cookie header.

(⬆️ The hard way)

The easy way, is not that easy actually, because sometimes there may be dynamic language support demand, this is why I said:

NOTE: dynamic loaded component should stick to this rule as well.

As there is dynamic demands, webpack.publicPath is not a perfect solution as well, this can only solve static situations. There will be multi entry scripts which is compiled with different webpack.publicPath, the only difference among these scripts is the webpack.publicPath.

Maybe loadable's webpack plugin can add some hooks to solve this ? I'm not familiar with webpack development (actually I'm not a frontend engineer...).

theKashey commented 4 months ago

Then add response.cookie('lang', language) in request handler

That actually should work out of the box. Just use cookies not extra query parameters

As there is dynamic demands, webpack.publicPath is not a perfect solution as well,

It is, because it can be configured in runtime. And that would be same script, just prefixed with language - something nginx can use instead of query attribute.

Maybe loadable's webpack plugin can add some hooks to solve this

It cannot because it's not only about loadable-stats (server side), but client-side as well, fully managed by webpack