2016-07-12 5 views
7

クライアントは、機能豊富なクライアントサイドのレンダリングされたウェブアプリを要求しています。同時に、Google PageSpeed Insightsで100/100を獲得し、最初のロード時に空のキャッシュで非常に高速にレンダリングされます。彼女は同じサイトをウェブアプリとランディングページの両方として使用したいと考えていて、良いSEOでサイト全体を簡単にクロールする検索エンジンを持っています。Meteorを使用したGoogle PageSpeed Insights(つまりウェブアプリのランディングページ)

これは流星を使って可能ですか?どのようにそれを行うことができますか?

答えて

23

はい、これはMeteor 1.3、いくつかの特別なパッケージ、マイナーハックを使用することで可能です。

例としてbc-real-estate-math.comを参照してください。 (このサイトは画像のサイズが決まっていないため97点、AnalyticsとFBのトラッキングはキャッシュ寿命が短い)

伝統的に、Meteorのようなクライアント側のレンダリングされたプラットフォームは、大きなJavascriptペイロード。最初のページのサーバー側のレンダリング(Reactを使用)は、これをほぼ解決しています。ただし、Meteorはすぐに非同期のJavascriptやインラインCSSをサポートしていないため、最初のレンダリングが遅くなり、Google PageSpeed Insightsのスコアが低下しますそのメトリックについては、クライアントのAdWord価格に影響するため、最適化します)。

この

は、あなたがこの回答のセットアップでは達成できるものである。

  • 500msの
  • いいえ「スタイル付きコンテンツのフラッシュ」
  • のように、空のキャッシュに最初のレンダリング時間に、非常に高速
  • スコア100/100 on Google PageSpeed Insights
  • PageSpeedスコアを殺すことなくウェブフォントを使用する
  • ページタイトルとメタを含む完全なSEOコントロール
  • が正確
  • Googleの検索ボットやその他のクローラをレンダリングかかわらず、サーバ - または クライアント側のすべてのページビューを記録したことをGoogleアナリティクスとFacebookのピクセルとの完全な統合は、スクリプトを実行せずにすぐにあなたのページに本当のHTMLのすべてを見る
  • はシームレスimpactinなしのJavascriptの任意のサイズに
  • スケールアップを獲得リクエストを追加したり、スピードを傷つけることなく、アイコンフォント 文字の数が少ない(のような< 30)を使用し
  • ページの部分にスクロールする#hash URLを処理しますこの設定は、達成することはできませんどのような経験
  • フル流星のWebアプリケーションのすべての定期的な素晴らしさ

グラムのランディングページ:

  • 大モノリシックCSSフレームワークは、あなたのページスピードのスコアを殺すために開始し、最初のレンダリングまでの時間を短縮します。ブートストラップはあなたが問題を見始める前に行くことができるくらい大きいです
  • フォントの誤りを避けて、100/100 PageSpeedを維持することはできません。最初のレンダリングはクライアントのWebセーフフォント、2番目のレンダリングは以前に延期したフォントを使用します。あなたが実現することができます基本的に何

は次のとおりです。

  • クライアントは、サイト内の任意のURLを要求し
  • サーバーはJavascript非同期(async)、インラインCSSと 完全なHTMLファイルを送り返し、および を延期フォント
  • クライアントは、画像(もしあれば)を要求し、サーバはクライアントが現在のページをレンダリングすることができ
  • それらを送信
  • 繰延フォント(もしあれば)到着し、ページが
  • Javascriptの母船ペイロードが バックグラウンドで
  • 流星が起動到着再レンダリング可能性があり、あなたが すべての添えものと完全に機能するウェブアプリを持っています無最初の負荷ペナルティ
  • 限り、あなたはで 外観にユーザーに読むためのテキストときれいな絵の数行を与える として、彼らは本格WEB-に静的なHTML ページからの移行に気づくことはありませんアプリ

達成するために、どのようにこの

私は流星1.3とこれらの追加パッケージを使用:

  • が反応を
  • 反応-DOM
  • 反応し、ルータ
  • 反応-ルータSSR
  • が反応-ヘルメット
  • postcss
  • autoprefixer
  • 流星ノード・スタブ

私は、他のレンダリングエンジンを試していない、サーバー側のレンダリングとの素敵なプレーを反応します。反応-ヘルメットを簡単に追加して、各ページの<head>を変更するために使用され、両方のクライアント側およびサーバ側(例えば各ページのタイトルを設定するために必要)。私はオートプレフィクサーを使用して、ベンダー固有のプレフィックスをすべてCSS/SASSに追加します。

ほとんどのサイトは、反応ルータ、reac-router-ssr、および反応するヘルメットのドキュメントの例に従って、かなり簡単です。それらのパッケージの詳細については、それらのパッケージのドキュメントを参照してください。

まず、共有されているMeteorディレクトリ(つまり、サーバまたはクライアントフォルダにない)にある非常に重要なファイル。このコードが反応サーバー側のレンダリング、<head>タグ、Googleアナリティクス、Facebookの追跡、およびアンカーを#hashするスクロールを設定します。

import { Meteor } from 'meteor/meteor'; 
import { ReactRouterSSR } from 'meteor/reactrouter:react-router-ssr'; 
import { Routes } from '../imports/startup/routes.jsx'; 
import Helmet from 'react-helmet'; 

ReactRouterSSR.Run(
    Routes, 
    { 
    props: { 
     onUpdate() { 
     hashLinkScroll(); 
     // Notify the page has been changed to Google Analytics 
     ga('send', 'pageview'); 
     }, 
     htmlHook(html) { 
     const head = Helmet.rewind(); 
     html = html.replace('<head>', '<head>' + head.title + head.base + head.meta + head.link + head.script); 
     return html;  } 
    } 
    }, 
    { 
    htmlHook(html){ 
     const head = Helmet.rewind(); 
     html = html.replace('<head>', '<head>' + head.title + head.base + head.meta + head.link + head.script); 
     return html; 
    }, 
    } 
); 

if(Meteor.isClient){ 
    // Google Analytics 
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 

    ga('create', 'UA-xxxxx-1', 'auto', {'allowLinker': true}); 
    ga('require', 'linker'); 
    ga('linker:autoLink', ['another-domain.com']); 
    ga('send', 'pageview'); 

    // Facebook tracking 
    !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod? 
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n; 
    n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0; 
    t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window, 
    document,'script','https://connect.facebook.net/en_US/fbevents.js'); 

    fbq('init', 'xxxx'); 
    fbq('track', "PageView"); 
    fbq('trackCustom', 'LoggedOutPageView'); 
} 


function hashLinkScroll() { 
    const { hash } = window.location; 
    if (hash !== '') { 
    // Push onto callback queue so it runs after the DOM is updated, 
    // this is required when navigating from a different page so that 
    // the element is rendered on the page before trying to getElementById. 
    setTimeout(() => { 
     $('html, body').animate({ 
      scrollTop: $(hash).offset().top 
     }, 1000); 
    }, 100); 
    } 
} 

ルートの設定方法は次のとおりです。後で<head>内容を設定するため、ヘルメットを反応させるために供給されているタイトルの属性に注目してください。

import React from 'react'; 
import { Router, Route, IndexRoute, browserHistory } from 'react-router'; 

import App from '../ui/App.jsx'; 
import Homepage from '../ui/pages/Homepage.jsx'; 
import ExamTips from '../ui/pages/ExamTips.jsx'; 

export const Routes = (
    <Route path="/" component={App}> 
    <IndexRoute 
     displayTitle="BC Real Estate Math Online Course" 
     pageTitle="BC Real Estate Math Online Course" 
     isHomepage 
     component={Homepage} /> 
    <Route path="exam-preparation-and-tips"> 
     <Route 
     displayTitle="Top 3 Math Mistakes to Avoid on the UBC Real Estate Exam" 
     pageTitle="Top 3 Math Mistakes to Avoid on the UBC Real Estate Exam" 
     path="top-math-mistakes-to-avoid" 
     component={ExamTips} /> 
    </Route> 
); 

App.jsx --the外側アプリケーションコンポーネント。一部のメタタグを設定する<Helmet>タグ、および特定のページコンポーネントの属性に基づいてページタイトルを確認します。

import React, { Component } from 'react'; 
import { Link } from 'react-router'; 
import Helmet from "react-helmet"; 

export default class App extends Component { 

    render() { 
    return (
     <div className="site-wrapper"> 
      <Helmet 
      title={this.props.children.props.route.pageTitle} 
      meta={[ 
       {name: 'viewport', content: 'width=device-width, initial-scale=1'}, 
      ]} 
      /> 

      <nav className="site-nav">... 

例のページコンポーネント:繰延フォントを追加する方法

import React, { Component } from 'react'; 
import { Link } from 'react-router'; 

export default class ExamTips extends Component { 
    render() { 
    return (
     <div className="exam-tips blog-post"> 
     <section className="intro"> 
      <p> 
      ... 

これらのフォントは、最初のレンダリングの後に読み込まれるため、最初のレンダリングまでの時間が遅延しません。 PageSpeedスコアを下げずにWebフォントを使用する唯一の方法だと思います。しかし、それは短い間違ったフォントにつながります。あなたは優秀なfontello.comのようなサービスや手ピックあなたが実際に必要なアイコンのみを使用している場合

WebFontConfig = { 
    google: { families: [ 'Open+Sans:400,300,300italic,400italic,700:latin' ] } 
}; 
(function() { 
    var wf = document.createElement('script'); 
    wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js'; 
    wf.type = 'text/javascript'; 
    wf.async = 'true'; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(wf, s); 
})(); 

、あなたはあなたのインライン<head> CSSにそれらを埋め込み、上のアイコンを取得することができます:クライアントに含まれているスクリプトファイルでこれを入れて大きなフォントファイルを待たずに最初にレンダリングします。

、ほぼ十分だが、問題は、私たちのスクリプト、CSS、およびフォントが同期ロードおよびレンダリング遅く、私たちのページスピードのスコアを殺害されていることであるハック

。残念ながら、私が知る限り、Meteor 1.3では、CSSをインライン化する方法や、スクリプトタグに非同期属性を追加する方法は公式にはサポートされていません。コアのボイラープレートジェネレータパッケージの3つのファイルに数行をハックする必要があります。

〜/ .meteor /パッケージ/定型-ジェネレータ/ .1.0.8.4n62e6 ++ OS + web.browser + web.cordova/OS /定型-generator.js

... 
Boilerplate.prototype._generateBoilerplateFromManifestAndSource = 
    function (manifest, boilerplateSource, options) { 
    var self = this; 
    // map to the identity by default 
    var urlMapper = options.urlMapper || _.identity; 
    var pathMapper = options.pathMapper || _.identity; 

    var boilerplateBaseData = { 
     css: [], 
     js: [], 
     head: '', 
     body: '', 
     meteorManifest: JSON.stringify(manifest), 
     jsAsyncAttr: Meteor.isProduction?'async':null, // <------------ !! 
    }; 

    .... 

     if (item.type === 'css' && item.where === 'client') { 
     if(Meteor.isProduction){ // <------------ !! 
      // Get the contents of aggregated and minified CSS files as a string 
      itemObj.inlineStyles = fs.readFileSync(pathMapper(item.path), "utf8");; 
      itemObj.inline = true; 
     } 
     boilerplateBaseData.css.push(itemObj); 
     } 
... 

〜今/.meteor/packages/boilerplate-generator/.1.0.8.4n62e6++os+web.browser+web.cordova/os/packages/boilerplate-generator/boilerplate_web.browser.html

<html {{htmlAttributes}}> 
<head> 
    {{#each css}} 
    {{#if inline}} 
     <style>{{{inlineStyles}}}</style> 
    {{else}} 
     <link rel="stylesheet" type="text/css" class="__meteor-css__" href="{{../bundledJsCssUrlRewriteHook url}}"> 
    {{/if}} 
    {{/each}} 
    {{{head}}} 
    {{{dynamicHead}}} 
</head> 
<body> 
    {{{body}}} 
    {{{dynamicBody}}} 

    {{#if inlineScriptsAllowed}} 
    <script type='text/javascript'>__meteor_runtime_config__ = JSON.parse(decodeURIComponent({{meteorRuntimeConfig}}));</script> 
    {{else}} 
    <script {{../jsAsyncAttr}} type='text/javascript' src='{{rootUrlPathPrefix}}/meteor_runtime_config.js'></script> 
    {{/if}} 

    {{#each js}} 
    <script {{../jsAsyncAttr}} type="text/javascript" src="{{../bundledJsCssUrlRewriteHook url}}"></script> 
    {{/each}} 

    {{#each additionalStaticJs}} 
    {{#if ../inlineScriptsAllowed}} 
     <script type='text/javascript'> 
     {{contents}} 
     </script> 
    {{else}} 
     <script {{../jsAsyncAttr}} type='text/javascript' src='{{rootUrlPathPrefix}}{{pathname}}'></script> 
    {{/if}} 
    {{/each}} 
</body> 
</html> 

カウント編集して入力した2つのファイルの文字数〜/ .meteor /パッケージ/定型-ジェネレータ/ .1.0.8.4n62e6 ++ OS + web.browser + web.cordova/os.json

でこれらのファイルのエントリの長さフィールドに新しい値その後、プロジェクト/ .meteor/localフォルダを削除して、Meteorに新しいコアパッケージを使用させ、アプリを再起動してください(ホットリロードは機能しません)。プロダクションモードでのみ変更が表示されます。

これは明らかにハックであり、Meteorのアップデート時には壊れてしまいます。私はこれを投稿し、興味を持ってほしいと思っています。より良い方法に向かって作業します。改善する

事をする

は次のようになります。

  • はハックを避けてください。
  • がインライン化された粒状JSが同期するようにASYNとするその上にコントロールと を許可延期するインライン化するCSSをきめ細かく制御を許可しているMDGが正式
  • 柔軟な方法で非同期スクリプトとインライン CSSをサポートするには、Get 。
+0

流星が決まり文句に提案された変更を議論するための関連GitHubの問題:https://github.com/meteor/meteor/pull/3860 – Noland

+0

このパッケージはハックを避けることができれば、私も調査しています。https:/ /atmospherejs.com/meteorhacks/inject-initial – Noland

+0

こんにちは@Noland - 興味深い投稿。あなたは反応ルータ-SSRのサブスクリプションのようにあなたのDDPデータをどのように扱うのですか? – TJR

関連する問題