sveltejs / sapper

The next small thing in web development, powered by Svelte
https://sapper.svelte.dev
MIT License
6.99k stars 434 forks source link

Google Amp Support #1008

Closed btakita closed 3 years ago

btakita commented 4 years ago

Google Amp has performance-related restrictions such as custom tags, all css is inline, no js on page load, no script tags on main page, iframes can have js since it would not block page load, etc.

https://amp.dev/about/how-amp-works/?referrer=ampproject.org

Here are a couple of implications that I noticed.

all css is inline

<style> must be defined within <svelte:head>. Currently, this means there would be no preprocessing, unless a custom preprocessor is used.

no js on page load

This means %sapper.scripts% must be removed from src/template.html.

I'll keep posting to this thread as I discover more issues.

btakita commented 4 years ago

I updated the @ctx-core/sass package to evaluate <svelte:head> tags to preprocess <style> tags containing the attribute type='text/sass' or type='text/scss'.

I can see a few options of handling the no js & no script tags in amp pages.

  1. The most ideal case is to convert template.html to a Svelte component. This would require changes to Sapper. See https://github.com/sveltejs/sapper/issues/374
  2. Handle the GET http request using src/routes/html-path.js & render the html using svelte components. This would allow the default template.html to be kept while using a custom svelte component render chain for the amp pages. One could also extract as much html rendering logic as possible from template.html into svelte components to avoid duplication.
  3. Remove %sapper.scripts% from template.html. This would disable rehydration & the initialization of svelte components for all pages. In the case of using an <iframe> to load dynamic content, one would need to use another sapper app with it's own template.html file.

Is think option #2 is currently the best way to go. It would also apply should sapper use a svelte component as the base component instead of template.html.

btakita commented 4 years ago

https://github.com/sveltejs/sapper/issues/846

btakita commented 4 years ago

Ok, I have further looked into this & found a solution that seems to work without too many invasive changes.

First, I need to point out that the standard <style> already renders the css inside of %sapper.styles% in template.html, so there's no need to have a <style> tag inside <svelte:head>.

So now the solution to remove %sapper.scripts% only for amp pages.

In template.html, I wrapped a <template> tag around %sapper.scripts%.

<template id="sapper-scripts">
%sapper.scripts%
</template>

Now in the top level _layout.svelte, I added a amp prop, which is used like:

_layout.svelte

<script>
export let amp = false
</script>

<svelte:head>
<!--...-->
{#if !amp}
<script>
setTimeout(function() {
    eval(
        document.getElementById('sapper-scripts').content.querySelector('script').innerHTML
    )
})
</script>
{/if}
</svelte:head>

This enables the amp prop to be set in a route component's preload function. Setting amp to true disables the svelte loader javascript on the page.

src/routes/my/amp/route.svelte

<script context=module>
export async preload(req, res) {
    return { amp: true } 
}
</script>
thgh commented 4 years ago

You could consider using an express middleware to override res.end, e.g. https://github.com/ampproject/amp-toolbox/blob/master/packages/optimizer-express/lib/AmpOptimizeMiddleware.js

vipero07 commented 4 years ago

I think sapper / svelte is a perfect use case for AMP's scope the div with %sapper.html% could be placed inside the amp-script tag the scripts have a limit of 150kb, which is a joke to sapper, at usually no more than 10.

rshemant commented 4 years ago

@btakita I am using Tailwind CSS. How could I merge generated CSS on the same page? Example rollup config.

https://github.com/langbamit/sapper-postcss-tailwind-rollup/blob/master/rollup.config.js

@vipero07 I appreciate having a working example for AMP's scope. 👍

maxmilton commented 4 years ago

@rshemant is your question really related to this thread's topic? If you have a new bug or feature request it's best to open a new issue. Or in this case, it sounds like you need some general support, in which case it's better to jump on the Svelte discord chat :)

rshemant commented 4 years ago

@MaxMilton You are right mate. just as am update. I am leaning towards 11ty due to some issues at the Sapper level.

image

romaindurand commented 3 years ago

Here's a (quite hacky) proof of concept for AMP pages : https://github.com/romaindurand/sapper-amp-poc You can clone, npm i and npm run dev to play with it

The basic idea is to create a middleware that handles amp routes before sapper. This middleware is mostly copied from https://github.com/sveltejs/sapper/tree/master/runtime/src/server/middleware especially get_page_handler.ts

I tried to make step-by-step commits if you want to follow along.

Context : I'm working for "France Bleu" (Radio France group) and we want to use sapper for a major technical reengineering. Not being able to handle AMP pages was a deal breaker so we used a similar approach to implement this feature. It would be great if sapper allowed us to do this (inline css, custom template and custom replacements inside the template) natively.

Thanks @JackJack972 who helped a great deal with this issue.

benmccann commented 3 years ago

SvelteKit will have AMP support

benmccann commented 3 years ago

Please use SvelteKit for this: https://github.com/sveltejs/kit/blob/master/documentation/docs/12-configuration.md#amp