How do I cache bust imported modules in es6?

后端 未结 7 1010
梦谈多话
梦谈多话 2021-01-31 09:21

ES6 modules allows us to create a single point of entry like so:

相关标签:
7条回答
  • 2021-01-31 09:27

    Just a thought at the moment but you should be able to get Webpack to put a content hash in all the split bundles and write that hash into your import statements for you. I believe it does the second by default.

    0 讨论(0)
  • 2021-01-31 09:32

    You can use ETags, as pointed out by a previous answer, or alternatively use Last-Modified in relation with If-Modified-Since.

    Here is a possible scenario:

    1. The browser first loads the resource. The server responds with Last-Modified: Sat, 28 Mar 2020 18:12:45 GMT and Cache-Control: max-age=60.
    2. If the second time the request is initiated earlier than 60 seconds after the first one, the browser serves the file from cache and doesn't make an actual request to the server.
    3. If a request is initiated after 60 seconds, the browser will consider cached file stale and send the request with If-Modified-Since: Sat, 28 Mar 2020 18:12:45 GMT header. The server will check this value and:
      • If the file was modified after said date, it will issue a 200 response with the new file in the body.
      • If the file was not modified after the date, the server will issue a304 "not modified" status with empty body.

    I ended up with this set up for Apache server:

    <IfModule headers_module>
      <FilesMatch "\.(js|mjs)$">
        Header set Cache-Control "public, must-revalidate, max-age=3600"
        Header unset ETag
      </FilesMatch>
    </IfModule>
    

    You can set max-age to your liking.

    We have to unset ETag. Otherwise Apache keeps responding with 200 OK every time (it's a bug). Besides, you won't need it if you use caching based on modification date.

    0 讨论(0)
  • 2021-01-31 09:35

    A solution that crossed my mind but I wont use because I don't like it LOL is

    window.version = `1.0.0`;
    
    let { default: fu } = await import( `./bar.js?v=${ window.version }` );
    

    Using the import "method" allows you to pass in a template literal string. I also added it to window so that it can be easily accessible no matter how deep I'm importing js files. The reason I don't like it though is I have to use "await" which means it has to be wrapped in an async method.

    0 讨论(0)
  • 2021-01-31 09:38

    There is one solution for all of this that doesn't involve query string. let's say your module files are in /modules/. Use relative module resolution ./ or ../ when importing modules and then rewrite your paths in server side to include version number. Use something like /modules/x.x.x/ then rewrite path to /modules/. Now you can just have global version number for modules by including your first module with <script type="module" src="/modules/1.1.2/foo.mjs"></script>

    Or if you can't rewrite paths, then just put files into folder /modules/version/ during development and rename version folder to version number and update path in script tag when you publish.

    0 讨论(0)
  • 2021-01-31 09:40

    From my point of view dynamic imports could be a solution here.

    Step 1) Create a manifest file with gulp or webpack. There you have an mapping like this:

    export default {
        "/vendor/lib-a.mjs": "/vendor/lib-a-1234.mjs",
        "/vendor/lib-b.mjs": "/vendor/lib-b-1234.mjs"
    };
    

    Step 2) Create a file function to resolve your paths

    import manifest from './manifest.js';
    
    const busted (file) => {
     return manifest[file];
    };
    
    export default busted;
    

    Step 3) Use dynamic import

    import busted from '../busted.js';
    
    import(busted('/vendor/lib-b.mjs'))
      .then((module) => {
        module.default();
    });
    

    I give it a short try in Chrome and it works. Handling relative paths is tricky part here.

    0 讨论(0)
  • 2021-01-31 09:40

    Use of relative path works for me:

    import foo from './foo';
    

    or

    import foo from './../modules/foo';
    

    instead of

    import foo from '/js/modules/foo';
    

    EDIT

    Since this answer is down voted, I update it. The module is not always reloaded. The first time, you have to reload the module manually and then the browser (at least Chrome) will "understand" the file is modified and then reload the file every time it is updated.

    0 讨论(0)
提交回复
热议问题