Parcel: Inline javascript

Created on 11 Feb 2018  ·  8Comments  ·  Source: parcel-bundler/parcel

Instead of
How to inline all javascript in index.html?
in a slow 3G Internet, inline everything CSS, javascript in a file will reduce ~600ms
first meaningful paint time.

Feature

Most helpful comment

https://github.com/xingqiao/parcel-plugin-inline-source
https://www.npmjs.com/package/parcel-plugin-inline-source

set attribute inline="inline" to

All 8 comments

Yes please :)
It would also be very useful to be able to inline (minified) css.

Btw, until parcel can do it, I'm using this https://www.npmjs.com/package/inline-assets
Maybe parcel can just do it the same way or use that package like it uses babel..

In theory it should be possible for parcel to do this, but in practise it's rather hard as the packagers are streaming the output js to the actual output file, which would be caught in case of inlining and be put into the html package instead (making the html packager wait for the full js and css packages to finish,...).
Feel free to have a spin at it, it's definitely not gonna be easy but doable non the less.

You can try to use posthtml to inline your scripts with this plugin: https://github.com/jonathantneal/posthtml-inline-assets

Works well for my small project 👍

@flecno that will only work with scripts that exist already, i.e. are not the output of transpilation, since posthtml is run as part of pretransform:

https://github.com/parcel-bundler/parcel/blob/2f7be14aa9eea3fa9e8ee61591c001937d9757a1/src/assets/HTMLAsset.js#L153-L155

I'm also interested in this, since I'm working on a project where I create a html file which would later be included on another page as iframe. So the output must be a single file for production (for development it's OK to have it bundled in a separate file). This is the hacky way of inlining output in HTML:

const Bundler = require('parcel-bundler');
const path = require('path');
const fs = require('fs');
const util = require('util');
const rimraf = require('rimraf');

const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);
const clearPath = glob => rimraf(glob, () => Promise.resolve());

// Use the production environment to trigger a minified build
process.env.NODE_ENV = 'production';

// Paths
const source = path.join(__dirname, './../src/index.js');
const tempDir = path.join(__dirname, './../temp');
const tempFile = 'temp.js';
const tempFilePath = path.join(tempDir, tempFile);
const outDir = path.join(__dirname, './../dist');
const outFilePath = path.join(outDir, 'index.html');

// Parcel config
const options = {
  outDir: tempDir,
  outFile: tempFile,
  sourceMaps: false,
};

const parcel = new Bundler(source, options);

async function build(bundler) {
  try {
    // clear output folder
    await clearPath(`${outDir}/*`);

    // create the bundle
    await bundler.bundle();

    // read the bundle and insert it into script template
    const script = await readFile(tempFilePath, 'utf-8');
    const finalOutput = `<script>${script}</script>`;
    await writeFile(outFilePath, finalOutput, 'utf-8');

    // remove junk
    await clearPath(`${tempDir}/*`);
  } catch (error) {
    // eslint-disable-next-line
    return console.error(error);
  }
}

build(parcel);

@ikovic this is a really newby question but I would like to use the code that you wrote, where would I put that and how do I get it to run with/after parcel build. I'm kinda new to npm thanks.

@dmarshall83 Hi, this was more or less the source of my build script, stored as scripts/build.js. I'd then just run it as any other npm script from package.json under scripts:

"build": "node scripts/build.js",

Disclaimer: I wouldn't call this the preferred way since it flushes the files on disk, reads it to memory and then writes to the final file. It would be much better if a parcel plugin existed which would do everything in-memory.

https://github.com/xingqiao/parcel-plugin-inline-source
https://www.npmjs.com/package/parcel-plugin-inline-source

set attribute inline="inline" to