我可以使用Svelte以某种方式生成“初始” HTML文件吗?
我正在使用Django,Webpack和Tailwindcss。我想在前端使用Svelte,但是我不想放弃仅使用服务器端渲染(Django模板)所带来的速度。如果我最初介绍的是一个引导HTML页面,该页面引入了bundle.js,而Svelte在客户端构建了DOM,那么浏览器仅在加载JS文件之后才开始下载图像。
将其与已经包含图像链接的最初呈现的HTML进行比较,浏览器开始将它们与JS一起下载,以更快地感知页面加载。
我不想将Sapper用作我的应用程序服务器,我想继续使用Django。
答案 0 :(得分:2)
挑战在于在Django应用和Svelte组件之间共享状态(道具)。
要从组件获取HTML代码:
class Book {
public String title;
public int year;
public Book(String title, int year) {
this.title = title;
this.year = year;
}
public String getTitle() {
return title;
}
public int getYear() {
return year;
}
}
class MyLinkedList {
public List < Book > getTitleBook(List < Book > allBooks, int maxYear) {
LinkedList < Book > book = new LinkedList < > ();
book.add(new Book("Ogniem i Mieczem", 1884));
book.add(new Book("Krzyżacy", 1897));
book.add(new Book("Thinking in Java", 1998));
book.add(new Book("Czysty kod", 2008));
for (Book myBook: book) {
if (myBook.getYear() <= maxYear)
System.out.println("Nazwa książki " + myBook.getTitle());
}
}
}
如果组件没有道具,则可以编译和缓存HTML模板(甚至可以在运行时之前)。
如果要动态发送道具(例如基于数据库中的数据),则需要在运行时发送。这意味着在服务器端执行JS。如果您缓存结果,性能不会很差。
如果您不能缓存,那么使用Django来提高性能将被否定,因为无论如何您都将执行Svelte,因此不妨使用Svelte来完成整个服务器端的工作,然后再使用Django作为后端服务器。
答案 1 :(得分:0)
我认为,这没有多大意义。您可以为每个页面定义一个模板,该模板具有一个静态的,预先渲染的部分,然后由一个动态应用程序控制一个动态内容区域。
但是所有导航都将加载一个新模板,它可能不再是单面应用程序。您可能会为不同的页面模板编写不同的svelte应用程序(汇总可以做到)。
我认为,这样做会损失很多性能,在那种情况下,我宁愿选择棱角分明的东西,然后再苗条(或做出反应或发声)。
答案 2 :(得分:-6)
根据this blog post,您执行以下说明:
<块引用>在下面的帖子中,我将展示如何使用服务器端 在 Svelte 中渲染。
大多数情况下,您可能会在客户端运行 Svelte 代码, 但在某些情况下,您可以从服务器端 Svelte 中受益 渲染。
SEO 在我看来,服务器端渲染的主要用例是 搜索引擎优化。在服务器上进行初始渲染将使您的网站 更多的爬虫可访问。爬虫通常支持一些 JavaScript 执行,但复杂的 JavaScript 应用程序不太可能 正确编入索引。
我的经验是应用程序调用 ajax 来获取数据 对索引特别具有挑战性。爬虫可能会成功 呈现应用程序的初始静态部分,但数据将 因为爬虫不会进行必要的 ajax 调用。
在服务器上做初始渲染允许爬虫下载 应用程序作为完全构造的 html。没有必要执行 客户端上的 JavaScript 来组成自视图以来的初始视图 已经在服务器上构建。
服务器端 vs 客户端 从技术上讲,你可以构建一个 Svelte 没有任何客户端组件的应用程序,但它会 完全静态。基本上,该应用程序的行为很像 旧的服务器端 PHP 应用程序。非常适合爬虫,但真正的用户 通常期望更丰富的用户体验。
这是服务器端与客户端相遇的地方。
一旦服务器生成的 html 在浏览器中完全呈现,我们 可以启动应用程序的客户端副本。这 客户端版本选择服务器端应用程序离开的地方 关闭。
两个版本的应用程序可能使用相同的 Svelte 组件, 但重要的是要了解它们的执行独立于 彼此。服务器端版本不知道 客户端版本,反之亦然。
了解没有默认状态也很重要 客户端和服务器之间的共享(例如数据属性)。
文章轮播我决定使用服务器端 Svelte 来构建一个 我博客登陆页面的文章轮播。这个想法是使用一个 Svelte 组件循环浏览我文章中的四篇文章 类别。
轮播应该在页面加载时立即加载,所以我决定 在服务器上呈现初始视图。一旦页面加载我 启动 Svelte 组件的客户端副本以 动态循环浏览文章。
我不擅长 css 或设计技能,所以不要期待漂亮的 UI, 但这是我将所有内容连接起来的方式。
我首先创建一个用于渲染的文章组件 轮播中的文章。该组件可能应该被拆分 分成两个部分,但出于此目的将其保留为一个 博文。
<div class="row">
<span class="slide-show-card col-sm-3">
<h4>Angular</h4>
<h5><a class="slide-show-link" href="{{angularUrl}}">{{angularTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{angular.viewCount}} times</div>
<div>{{angularIntro}}</div>
</span>
<span class="slide-show-card col-sm-3">
<h4>JavaScript</h4>
<h5><a class="slide-show-link" href="{{javascriptUrl}}">{{javascriptTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{javascript.viewCount}} times</div>
<div>{{javascriptIntro}}</div>
</span>
<span class="slide-show-card col-sm-3">
<h4>Svelte</h4>
<h5><a class="slide-show-link" href="{{svelteUrl}}">{{svelteTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{svelte.viewCount}} times</div>
<div>{{svelteIntro}}</div>
</span>
<span class="slide-show-card col-sm-3">
<h4>React</h4>
<h5><a class="slide-show-link" href="{{reactUrl}}">{{reactTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{react.viewCount}} times</div>
<div>{{reactIntro}}</div>
</span>
</div>
<script>
class ArticleService {
constructor() {
this.articles = [];
this.index = {
'angular': -1,
'javascript': -1,
'svelte': -1,
'react': -1
};
}
getArticles() {
return fetch('/full-article-list-json')
.then((data) => {
return data.json();
})
.then((articles) => {
this.articles = articles;
return articles;
});
}
getNextArticle(key) {
this.index[key] = (this.index[key] + 1) % this.articles[key].length;
let a = this.articles[key][this.index[key]];
return a;
}
}
let articleService = new ArticleService();
export default {
onrender() {
let update = () => {
this.set({angular: articleService.getNextArticle('angular')});
this.set({javascript: articleService.getNextArticle('javascript')});
this.set({svelte: articleService.getNextArticle('svelte')});
this.set({react: articleService.getNextArticle('react')});
};
articleService.getArticles()
.then((articles) => {
update();
if(typeof global === 'undefined') {
document.querySelector('#articles').innerHTML = '';
document.querySelector('#articles-client-side').style.display =
"block";
}
})
.then(() => {
setInterval(() => {
articleService.getArticles()
.then((articles) => {
update();
});
}, 5000);
});
},
data () {
return {}
},
computed: {
angularTitle: angular => angular.title || '',
angularIntro: angular => angular.intro || '',
angularUrl: angular => `viewarticle/${angular.friendlyUrl}`,
javascriptTitle: javascript => javascript.title || '',
javascriptIntro: javascript => javascript.intro || '',
javascriptUrl: javascript => `viewarticle/${javascript.friendlyUrl}`,
svelteTitle: svelte => svelte.title || '',
svelteIntro: svelte => svelte.intro || '',
svelteUrl: svelte => `viewarticle/${svelte.friendlyUrl}`,
reactTitle: react => react.title || '',
reactIntro: react => react.intro || '',
reactUrl: react => `viewarticle/${react.friendlyUrl}`,
}
}
</script>
Server 我们来看看服务器代码。
我们要做的第一件事是通过要求激活编译器 苗条/ssr/注册
require( 'svelte/ssr/register' );
接下来我们必须要求组件 html 文件来获取对 组件。
然后我们调用 render 方法并传递给它一个初始数据对象。这 数据对象是标准的 Svelte 数据对象。
app.get('/', function(req, res) {
var component = require('./app/article-show/Articles.html');
var articles = component.render({
angular: articles.angular,
svelte: articles.svelte,
react: articles.react,
javascript: articles.javascript
});
res.render('index.html', {articles: articles});
});
调用 render 后,我们得到一个完全渲染的组件。我们现在 必须将此传递给节点视图引擎。
就我而言,我使用的是带有 Mustache 的 Express,因此我可以通过 组件作为 render 方法的对象。然后在我的 index.html 页面我使用带有三个大括号的 Mustache 视图语法来呈现 页面上的组件像这样。
{{{articles}}} Client 到目前为止我们所拥有的足以呈现 我的组件的初始视图,但它不支持循环通过新的 每隔几秒就会出现一篇文章。
为了实现这一点,我们必须启动客户端版本的 文章组件。
客户端版本作为标准 Svelte 客户端加载 组件。
import articles from './articles';
var articlesSection = new articles({
target: document.querySelector( 'main' ),
data: {angular: {}, javascript: {}, svelte: {}, react: {}}
});
一旦客户端版本被激活,我们将有两个组件 在 DOM 中。一旦客户端版本准备好接管我 删除服务器端版本。
可能有更优雅的方法来做到这一点,但我只是清除 服务器生成 DOM 元素并在客户端翻转样式 版本。
导航除了文章轮播我还建立了我的主要 导航作为 Svelte 服务器端组件。导航是一个纯粹的服务器 没有客户端对应的侧组件。
导航主要是静态的,但它支持动态样式 活动导航项。这是导航组件代码:
<div class="nav col-md-2 hidden-sm hidden-xs">
<a class="navLink" href="/"><div class="navBox {{home}}">Home</div></a>
<a class="navLink" href="/most-popular"><div class="navBox {{mostpopular}}">Most Popular</div></a>
<a class="navLink" href="/most-recent"><div class="navBox {{mostrecent}}">Most Recent</div></a>
<a class="navLink" href="/articleList/angular"><div class="navBox {{angular}}">Angular</div></a>
<a class="navLink" href="/articleList/react"><div class="navBox {{react}}">React</div></a>
<a class="navLink" href="/articleList/aurelia"><div class="navBox {{aurelia}}">Aurelia</div></a>
<a class="navLink" href="/articleList/javascript"><div class="navBox {{javascript}}">JavaScript</div></a>
<a class="navLink" href="/articleList/nodejs"><div class="navBox {{nodejs}}">NodeJS</div></a>
<a class="navLink" href="/articleList/vue"><div class="navBox {{vue}}">Vue</div></a>
<a class="navLink" href="/articleList/svelte"><div class="navBox {{svelte}}">Svelte</div></a>
<a class="navLink" href="/articleList/mongodb"><div class="navBox {{mongodb}}">MongoDB</div></a>
<a class="navLink" href="/articleList/unittesting"><div class="navBox {{unittesting}}">UnitTesting</div></a>
<a class="navLink" href="/articleList/dotnet"><div class="navBox {{dotnet}}">.Net</div></a>
<a class="navLink" href="/questions"><div class="navBox {{questions}}">Q&A</div></a>
<a class="navLink" href="/full-article-list"><div class="navBox {{all}}">All</div></a>
</div>
<script>
export default {
data () {
return {}
},
}
</script>
因为导航是如此静态,所以没有理由重新生成 每个请求的服务器端 html。作为优化,我决定 缓存导航的不同变体。唯一的区别 不同版本的导航之间是“活动”导航 items 样式应用于不同的元素。
这里是一些基本的缓存逻辑,确保我们只生成 每个导航版本一次。
function getNavComponent(key) {
key = key || 'home';
key = key.replace('-', '');
if(!navCache[key]) {
navCache[key] = createNavComponent(key);
}
return navCache[key];
}
function createNavComponent(key) {
var nav = require('./app/article-show/Navigation.html');
var data = {};
data[key] = 'activeNav';
return nav.render(data);
}
Demo 如果你想测试我的服务器端 vs 客户端视图,你 可以找到它here。
我还在 Google 网站管理员工具中加载了我的网站,以比较 爬虫的组件视图到用户的视图
从截图中可以看出,我的组件看起来不错 添加服务器端渲染后的爬虫。
左侧是爬虫视图,右侧是用户视图。
<块引用>