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

inject <script type="module"> into <head> instead of <body> #881

Closed
dominikg opened this issue Oct 5, 2020 · 9 comments
Closed

inject <script type="module"> into <head> instead of <body> #881

dominikg opened this issue Oct 5, 2020 · 9 comments

Comments

@dominikg
Copy link
Contributor

dominikg commented Oct 5, 2020

Is your feature request related to a problem? Please describe.
vite buildHtmlPlugin injects <script type="module"> tags at the end of <body>

This has 2 potential issues with generic SSR (eg. headless chrome with puppeteer crawling a regular vite build)

  1. If the initial html is large, it may take longer for the browser to start downloading the scripts.
  2. If you run code that completely replaces the content of body, SSR result will no longer contain the scripts

Describe the solution you'd like
Inject module scripts in <head>
they are only executed after parse per spec: https://html.spec.whatwg.org/multipage/scripting.html#attr-script-defer

Describe alternatives you've considered
rewrite index.html after vite is done, before SSR

Additional context
Ran into this when i tried to build a simple export feature in svite, where the svelte app is mounted to document.body by default. Not an issue when you don't use sveltes hydratable compiler option. But when you do, 2) above happens

@underfin
Copy link
Member

underfin commented Oct 9, 2020

  1. If you run code that completely replaces the content of body, SSR result will no longer contain the scripts

Can you give a specific description for this? Why ssr result will no longer contain the scripts?

@dominikg
Copy link
Contributor Author

dominikg commented Oct 9, 2020

Rough example just to demonstrate the point
index.js

//...
document.body.innerHTML='Hello'
alert('World')
//...

index.html

<body>
<script type="module" src="index.js"></script>
</body>

If you run that index.html through a generic prerenderer, it turns into

<body>
Hello
</body>

Now the script is gone and so serving that to the client won't work

@underfin
Copy link
Member

underfin commented Oct 9, 2020

<body>Hello</body> is html code compiled by ssr, if you want client work, you should add your client code instead of remove client code, the client code will hydration with the responsed html.

@dominikg
Copy link
Contributor Author

dominikg commented Oct 9, 2020

I'm not sure i understand you correctly. In this scenario there is a single vite build dist output, served on localhost, crawled by puppeteer and the prerendered output written back to dist and the final result is then deployed to be served to the user.

Is there a legitimate reason for vite build to write script tags at the end of body instead of head?

Besides rewriting index.html before prerender there is another workaround for my usecase, but i really would like to not add this extra element.

//...
const target = document.querySelector('#target');
target.innerHTML='Hello';
alert('world');
//...
<body>
<div id="target" style="display: contents;"></div>
<script src="index.js"></script>
</body>

which would then be prerendered as

<body>
<div id="target" style="display: contents;">Hello</div>
<script src="index.js"></script>
</body>

@haoqunjiang
Copy link
Member

haoqunjiang commented Oct 10, 2020

Good to know about this feature!
Does that mean link rel="modulepreload" is no longer necessary? We have these tags in Vue CLI modern mode, I'm wondering if we can safely remove them after moving script tags to head.

@underfin
Copy link
Member

underfin commented Oct 10, 2020

@dominikg. I know your mean with issues :)

Is there a legitimate reason for vite build to write script tags at the end of body instead of head?

Said as https://stackoverflow.com/questions/38407962/when-to-use-the-script-tag-in-the-head-and-body-section-of-a-html-page/38408000

<body>
<div id="target" style="display: contents;">Hello</div>
<script src="index.js"></script>
</body>

I think it should be better than put index.js into head.The brower will show the html before hydration, this is main reason of use ssr.

Edit: The module script is execute after html parsed.So put module script into head is also worked fine.

@underfin
Copy link
Member

@sodatea The modulepreload (it don't run code) is not equal moving script tags to head (it will run code), you can have a look with https://developers.google.com/web/updates/2017/12/modulepreload

@haoqunjiang
Copy link
Member

haoqunjiang commented Oct 10, 2020

@underfin According to the spec link in the issue, <script type="module">s are deferred by default.

According to the resource hints spec (w3c/resource-hints#13, https://www.w3.org/TR/preload/#early-fetch-and-application-defined-execution), if I understand correctly, <link rel="preload" as="script"> or <link rel="modulepreload"> work essentially the same as <script defer>.

@isaacl
Copy link
Contributor

isaacl commented Nov 10, 2020

See comment in #882

isaacl added a commit to isaacl/vite that referenced this issue Nov 11, 2020
- injectPreload for entry chunk
- move script injection back to end of body (reverts vitejs#882)
- fix indentation of injectPreload, injectCSS and injectScript

Fixes vitejs#1050, see also vitejs#881.
isaacl added a commit to isaacl/vite that referenced this issue Nov 11, 2020
- injectPreload for entry chunk
- move script injection back to end of body (reverts vitejs#882)
- fix indentation of injectPreload, injectCSS and injectScript

Fixes vitejs#1050, see also vitejs#881.
@github-actions github-actions bot locked and limited conversation to collaborators Jul 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants