Skip to content

Instantly share code, notes, and snippets.

@mootari
Last active March 17, 2024 14:14
Show Gist options
  • Save mootari/333cca8cf708ad886a790e55034fe291 to your computer and use it in GitHub Desktop.
Save mootari/333cca8cf708ad886a790e55034fe291 to your computer and use it in GitHub Desktop.
Content Snippet that bundles the current page's stylesheets and assets into a zip file.
(async()=>{
const customCss = `
#title-heading {clear:left}
`;
const asyncArray = (iter, map) => Promise.all(Array.from(iter, map));
const css = (await asyncArray(
document.querySelectorAll('link[rel="stylesheet"][href^="/"]'),
async n => (await fetch(n.href, {mode: 'no-cors'})).text()
)).join("\n").replace(/\/\*.*?\*\//gs, '');
const paths = new Map();
const pattern = /\burl\((['"]?)(?<url>\/.*?)(?<hash>#.*?)?\1\)/g;
const rewritten = css.replace(pattern, (str, quote, url, hash = '') => {
const name = url.split('?', 2)[0].split('/').at(-1);
if(!paths.has(url)) paths.set(url, `./assets/file-${paths.size}-${name}`);
return `url("${paths.get(url)}${hash}")`;
});
console.log(`Fetching ${paths.size} files ...`);
const files = Object.fromEntries([
['./site.css', new TextEncoder().encode(rewritten + customCss)],
...await asyncArray(
paths,
async ([url, local]) => [local, new Uint8Array(await (await fetch(url)).arrayBuffer())]
)
]);
// Note: CSPs may prevent the module from loading.
const {zipSync} = await import('https://cdn.jsdelivr.net/npm/fflate@0.8.2/+esm');
console.log('Generating archive ...');
const archive = zipSync(files, {level: 9});
const a = document.createElement('a');
a.download = 'styles.zip';
a.href = URL.createObjectURL(new Blob([archive]));
a.click();
})()
@loadx
Copy link

loadx commented Jul 30, 2021

chefs kiss you are my hero, saved me from having to compile a bunch of LESS files. 🤗

@Joshua-Beatty-Pearagon
Copy link

I had to set the fetch mode to 'no-cors' to get it to work. Here is the modified code if this helps anyone:

(()=>{
  const customCss = `
  #title-heading {clear:left}
  `;

  require('https://cdn.jsdelivr.net/npm/jszip@3.2.2/dist/jszip.min.js')
  .then(ret => {
    const zip = new JSZip;

    const css = [];
    for(let n of document.querySelectorAll('link[rel="stylesheet"][href^="/"]')) {
      css.push(new Promise((resolve) => {
        fetch(n.href).then(r => resolve(r.text()));
      }))
    }

    Promise.all(css)
    .then(css => css.join('\n'))
    .then(css => css.replace(/\/\*.*?\*\//gs, ''))
    .then(css => {
      const paths = new Map;
      const pattern = /\burl\((['"])(?<url>\/.*?)(?<hash>#.*?)?\1\)/g;
      const rewritten = css.replace(pattern, (str, quote, url, hash = '') => {
        const name = url.split('?', 2).shift().split('/').pop();
        if(!paths.has(url)) paths.set(url, `./assets/file-${paths.size}-${name}`);
        return `url("${paths.get(url)}${hash}")`;
      })
      return {css: rewritten, paths};
    })
    .then(({css, paths}) => {
      zip.file('site.css', new Blob([css + customCss]));
      console.log('Fetching files ...');
      const p = Array.from(paths).map(([url, local]) => fetch(url, {mode: 'no-cors'})
        .then(r => r.blob())
        .then(blob => zip.file(local, blob)));

      return Promise.all(p);
    })
    .then(() => {
      console.log('Generating archive ...');
      return zip.generateAsync({type: 'blob'});
    })
    .then(blob => {
      const a = document.createElement('a');
      a.download = 'styles.zip';
      a.href = URL.createObjectURL(blob);
      a.click();
    });

  });

  function require(url) {
    return fetch(url, {mode: 'no-cors'})
      .then(res => res.text())
      .then(src => (new Function('var exports={};'+src+';return exports')).call({}).exports);
  }
})()

@mootari
Copy link
Author

mootari commented Aug 10, 2021

@Joshua-Beatty-Pearagon Thanks! Do you happen to have a public link where this change can be tested?

@Ihyun
Copy link

Ihyun commented Mar 10, 2022

@Joshua-Beatty-Pearagon, your code does not work. @mootari 's code works. Thanks all!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment