Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to build preact in one index.html file? #923

Closed
bratukh opened this issue Dec 7, 2019 · 28 comments
Closed

How to build preact in one index.html file? #923

bratukh opened this issue Dec 7, 2019 · 28 comments
Labels

Comments

@bratukh
Copy link

bratukh commented Dec 7, 2019

Hey. I use preact to create interactive pages that are hosted in the memory of the microcontroller. The preact size and features are really impressive, but for my use case it is still overloaded.

What can I do so that when I run the npm run build command, I get 1 file - index.html, where will all the styles and scripts be inside?

I used to have a working version, but when updating webpack and preact, it turned out to be not working:

package.json
"build": "preact build --no-prerender --no-service-worker"

preact.config.js

export default (config, env, helpers) => {
    const chunks = helpers.getPluginsByName(config, 'CommonsChunkPlugin')[0]
    config.plugins[chunks.index].minChunks = 1
}

Thanks!

@bratukh bratukh changed the title How to minimize preact build? How to build preact in one index.html file? Dec 7, 2019
@marvinhagemeister
Copy link
Member

I used to have a working version, but when updating webpack and preact, it turned out to be not working

What's the error message your getting?

@developit
Copy link
Member

Try replacing your preact.config.js with this:

export default (config, env, helpers) => {
    config.optimization.splitChunks.minChunks = 1;
}

@developit
Copy link
Member

Should this issue be migrated to the preact-cli repo?

@marvinhagemeister marvinhagemeister transferred this issue from preactjs/preact Dec 10, 2019
@bsecker
Copy link

bsecker commented Jun 17, 2020

Hey @braga96 did you end up making any progress with this? I am in the exact situation using a microcontroller, and am also interested in condensing the build files into a single html file

@sebasjm
Copy link

sebasjm commented Jun 29, 2021

I made this but it was not so easy as a one liner

https://gist.github.com/sebasjm/087df4b0b0a611ce409fe30a67a1d0d9

Any improvement would be greatly appreciated.

@caxapexac
Copy link

Any solution yet? @sebasjm's solution doesnt look like a good way of doing this

@caxapexac
Copy link

I just need to inline scripts and styles, nothing more than that

@caxapexac
Copy link

Tried to use react-dev-utils/InlineChunkHtmlPlugin and my preact.config.js looks like this:

import HtmlWebpackPlugin from "html-webpack-plugin";
import InlineChunkHtmlPlugin from "react-dev-utils/InlineChunkHtmlPlugin";

export default (config, env, helpers) => {
    config.plugins.push(
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/.+[.]js/])
    );
}

Build goes:

 0% (0.0s) compiling× ERROR TypeError: this.htmlWebpackPlugin.getHooks is not a function
at \node_modules\react-dev-utils\InlineChunkHtmlPlugin.js:43:44
at SyncHook.eval [as call] (eval at create (\node_modules\tapable\lib\HookCodeFactory.js:19:10), <anonymous>:27:1)
at SyncHook.lazyCompileHook (\node_modules\tapable\lib\Hook.js:154:20)
at Compiler.newCompilation (\node_modules\webpack\lib\Compiler.js:631:26)
at \node_modules\webpack\lib\Compiler.js:667:29
at AsyncSeriesHook.eval [as callAsync] (eval at create (\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
at AsyncSeriesHook.lazyCompileHook (\node_modules\tapable\lib\Hook.js:154:20)
at Compiler.compile (\node_modules\webpack\lib\Compiler.js:662:28)
at \node_modules\webpack\lib\Compiler.js:321:11
at Compiler.readRecords (\node_modules\webpack\lib\Compiler.js:529:11)
at \node_modules\webpack\lib\Compiler.js:318:10
at AsyncSeriesHook.eval [as callAsync] (eval at create (\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
at AsyncSeriesHook.lazyCompileHook (\node_modules\tapable\lib\Hook.js:154:20)
at \node_modules\webpack\lib\Compiler.js:315:19
at AsyncSeriesHook.eval [as callAsync] (eval at create (\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:15:1)
at AsyncSeriesHook.lazyCompileHook (\node_modules\tapable\lib\Hook.js:154:20)

@caxapexac
Copy link

So jantimon/html-webpack-plugin#1068 says 'getHooks is new in html-webpack-plugin 4.0.0.alpha-2'

and you have "html-webpack-plugin": "^3.2.0",

and I mentioned is #1629 that you can't install another version

What should I do?

@rschristian
Copy link
Member

@caxapexac You installed the latest version of html-webpack-plugin which isn't compatible, yes. You can try an older version, and you may need to downgrade whatever utility that is as well.

Is there anything about the above solution that makes you think it is a poor way of going about this (assuming it works as you'd like it to)?

@caxapexac
Copy link

@rschristian it uses grep, I use windows
It uses something strange while webpack plugins just casually exist

@rschristian
Copy link
Member

Nothing strange about a post-build script, and I'd argue that is the correct way to go about this. Way less fragile than depending on Webpack plugins, that depend on specific versions of other dependencies, Webpack features, and our configuration.

You could swap grep and sed out for a Node script, fs.readFile and whatnot, it'd be just as effective.

@caxapexac
Copy link

html-webpack-inline-source-plugin@1.0.0-beta.2 doesn't work either cuz of html-webpack-plugin (https://stackoverflow.com/a/60473584/9398364)

html-webpack-inline-source-plugin ^0.0.10 doesn't work cuz its for webpack4

@rschristian
Copy link
Member

We are using Webpack 4

@caxapexac
Copy link

@caxapexac
Copy link

Nothing strange about a post-build script, and I'd argue that is the correct way to go about this. Way less fragile than depending on Webpack plugins, that depend on specific versions of other dependencies, Webpack features, and our configuration.

@rschristian its just so essential task (bundling 3 files into 1 file) so writing regexp with string replace looks like writing array sorting by hand, whats wrong if I want to write 1 string inside webpack config instead of remembering sick syntax of regexp?

@caxapexac
Copy link

Ouf this is building with "html-webpack-inline-source-plugin": "^0.0.10",:

import HtmlWebpackPlugin from "html-webpack-plugin";
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');

export default (config, env, helpers) => {
    config.plugins.push(new HtmlWebpackPlugin({
        inlineSource: '.(js|css)$'
    }))
    config.plugins.push(new HtmlWebpackInlineSourcePlugin())
}

@rschristian
Copy link
Member

Nothing's wrong with with that, but the fact of the matter is that you have a lot more moving pieces with Webpack plugins. As you've already encountered, you have a reliance upon not only your plugin version, but webpack, html-webpack-plugin, and preact-cli versions. Scripts remain static. Grep, for comparison, has remained the same for decades, and that's why I'd recommend that over plugins which may or may not work in the future, especially when it's as small and isolated as what's needed here. That's just my opinion though, you're free to do whatever you choose of course.

This likely isn't something we're looking to support out-of-the-box, as it's quite a bad practice if you can avoid it, so you'll need to do a bit of stitching things together if you cannot find a webpack plugin that'll work with our current dependencies.

There is #1608 in the pipeline which will upgrade us to html-webpack-plugin v4, but there's no ETA on when that might be ready or released.

@caxapexac
Copy link

Okay I've re-read #923 (comment) and it seems legit, sorry for all this stuff Ive said.

So if I use this solution, to what should I replace 'something.woff' and 'base64-inline-loader' on the 15-20th line to not to break everything and have truly single-file bundle (I can have js, css, png, svg in the project)? (it is good to inline js as base64? How to inline as plain text?)

@caxapexac
Copy link

@rschristian my pipeline is updated and now its legit to use multiple files in build. Whats the best command for build then? I use preact for rendering game overlay gui so no need for prerendering and other stuff:

I suupose its preact build --no-sw --no-esm but maybe there is more to add?

I.e. css dedupe (#1631) - I can't fully disable inlined css cuz its needed for loading screen
What about --prerender also?

The aim is to having folder:
assets/
favicon.ico
index.html (with inlined loading screen css)
bundle.css (without loading screen css)
index.min.js

P.S. is there anything wrong making game interface with react? Honestly I don't know, is there other legit solutions? (I've seen vue used for game ui only)

@rschristian
Copy link
Member

Disabling prerendering would mean very little CSS could be inlined. Critters needs to be able to detect what styles you use in order to inline those CSS rules. If you don't prerender, you're handing Critters an empty doc; it will only end up inlining generic rules for body and html.

@caxapexac
Copy link

@rschristian its okay about css and prerender, got it, thanks. What about 3-files build? There are still files I'd like to get rid off, is it possible?:
image

I mean:
prerender data now only contain {"url":"/"} and doesn't look useful
push manifest and ssr doesn't look like used at all, what is it?

@rschristian
Copy link
Member

ssr-build/ is used to prerender your app, push-manifest.json is beneficial with http2 push, see: https://github.com/GoogleChromeLabs/http2-push-manifest#whats-a-push-manifest

You can just run a post-build delete script for anything you don't want. I doubt you want the manifest.

@caxapexac
Copy link

Oh I see, push manifest feels much useful now, thanks

@rschristian
Copy link
Member

rschristian commented Dec 17, 2021

Sorry, push-manifest you could want, manifest.json is what I was referring to with that last comment. They're for PWAs, but seeing as how you've disabled the rest of the PWA stuff, you don't want it.

@caxapexac
Copy link

What kinds of pwa stuff had I disabled? I really need manifest.json so I thought service worker is optional for it

@rschristian
Copy link
Member

There's no hard requirement, though it'd be quite odd.

@rschristian
Copy link
Member

Going to close out, this will never be supported out-of-the-box. Users can configure via preact.config.js if they require this.

@rschristian rschristian closed this as not planned Won't fix, can't repro, duplicate, stale Dec 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants