React+Router+GitHub Pages+Google Analytics踩坑之路

blank

React+Router+GitHub Pages+Google Analytics踩坑之路

我用React製作了一個單頁應用(SPA),在後來的發佈在GitHub Pages(或Coding Pages、Gitee Pages)上、引入React Router (v4)、使用Google Analytics分析用戶瀏覽量,乃至用Google AdSense發布廣告的過程遇到了許多問題(主要與React Router有關),並且很少看到有人討論這些問題(可能是這個做法很奇葩吧),於是有了這篇文章記錄踩坑之路。

這篇文章並不是教程,許多中間的步驟被省略。如果你略懂這些技術,想採用同樣的方法建網站,也許會對你有所幫助。

PS我的網站地址為https://lemonjing.com ,歡迎訪問。

創建React應用

(這部分借鑒了教程serverless stack

初始化React應用

使用create-react-app腳手架初始化react應用。

npx create-react-app my-app --use-npm

運行react應用。

cd my-app npm start

在git託管平台(如GitHub)上,新建一個repo,得到repo url,如 github.com/username/my-

將本地的react應用與遠程倉庫連接。

git init git add . git commit -m "First commit" git remote add origin https://github.com/username/my-app.git git remote -v git push -u origin master

處理路由

我的網站裡有不同的頁面,如App1、App2。進入網站後是有一個主頁,提供到App1、App2的鏈接。所以需要用到路由React Router。

安裝React Router v4。

npm install [email protected] --save

修改src/index.js

import { BrowserRouter as Router } from 'react-router-dom';​ // ...​ ReactDOM.render( <Router> <App /> </Router>, document.getElementById('root') );

新建src/Routes.js

import React from "react"; import { Route, Switch } from "react-router-dom"; // Home.js的内容在后文import Home from "./containers/Home"; // 假设我有App1、App2在src/containers/ 文件夹中import App1 from "./containers/App1"; import App2 from "./containers/App2";​ export default function Routes() { return ( <Switch> <Route path="/" exact component={Home} /> <Route path="/app1" exact component={App1} /> <Route path="/app2" exact component={App2} />f { /* 路径不存在,则回到主页。 */ } <Route component={Home} /> </Switch> ); }

src/App.js中使用Routes

// ...​ function App(props) { return ( <div> <h1>我的应用</h1> <Routes /> </div> ); }

主頁有鏈接指向App1和App2。 src/containers/Home.js可以是下面這個樣子:

import React from "react"; import { Link } from "react-router-dom";​ export default function Home() { return ( <div className="Home"> <h1>主页</h1> <Link to="/app1">应用1</Link> <Link to="/app2">应用1</Link> </div> ); }

發佈在GitHub Pages

安裝gh-pages

npm install gh-pages --save-dev

修改package.json

//..."homepage":"https://username.github.io/reponame",//..."scripts":{//..."predeploy":"npm run build","deploy":"gh-pages -d build"}

部署到github pages。

npm run deploy

實際上運行這行命令發生的就是:

  1. 運行predeploy ,也就是npm run build
  2. gh-pages (命令)將指定路徑(在這裡也就是build文件夾)下的內容複製到git分支gh-pages (分支的名字),並push。 gh-pages分支是GitHub Pages的默認發布源。

使用自己的域名

package.json裡的homepage改為自己的域名。

新建一個文件public/CNAME ,在裡面輸入自己的域名,如mydomain.com

使用其他Pages

根據需要更改package.json的scripts - deploy對應的命令。

例如,我要部署在Coding Pages上,使用的命令如下:

gh-pages -d build -b master -o coding -r https://e.coding.net/xxx.git

-d表示路徑,默認為'.'

-b表示分支名,默認為gh-pages

-o表示remote名,默認為origin

-r表示repo url,默認為url for the origin remote of the current dir。

詳見npm_gh-pages

問題來了:無法通過路徑直接訪問頁面

通過 mydomain.com進入頁面,點擊主頁中的鏈接後可以進入 mydomain.com/app1

但是如果此時刷新,結果會是404;或者直接訪問 mydomain.com/app1 ,結果同樣是404。因為React Router是前端的路由,由JavaScript處理的,GitHub Pages並不知道 mydomain.com/app1有一個頁面。

解決方法1:使用HashRouter而不是BrowserRouter

index.js中的router改為:

import { HashRouter as Router } from 'react-router-dom';

這樣鏈接就變為 mydomain.com/# ,可以直接訪問。原因是#號後面的內容會被忽略。

優點

  1. 簡單,原生。

缺點

  1. URL不好看
  2. 搜索引擎和Google Analytics等不會記錄,他們會認為 mydomain.com/# mydomain.com/是同一個頁面

解決方法2:使用404.html

當GitHub Pages無法找到頁面的時候,如果你的repo裡有一個404.html,GitHub Pages會返回你的404.html。

你可以直接將index.html複製一份, 改名為404.html,問題就解決了。

還有一個同樣原理但是複雜一些的做法: spa-github-pages

優點

  1. URL好看

缺點

  1. 當你直接訪問 mydomain.com/app1時,返回的狀態碼是404。不利於SEO。 Google Analytics和Google AdSense也會誤解。

解決方法3:為每個路徑創建一個文件夾

這個方法是從LoeiFy的一個issue看到的。

例如我有/app1,/app2兩個路徑,我就在build之後在build文件夾里新建app1,app2兩個文件夾,並將index.html拷貝進去。

這樣一來當我訪問 mydomain.com/app1的時候,GitHub Pages就會去/app1文件夾下找index.html,返回回來。

每次都複製一遍未免有些複雜,我們可以自動化這個過程。

在項目根目錄新建deploy.js

// deploy.js // 根据你的路径修改routes const routes = [ 'app1' , 'app2' , ] // 给每个route都新建一个文件夹,把index.html拷贝进去const fs = require ( 'fs-extra' ) const path = require ( 'path' ) routes . forEach (( route ) => { fs . copySync ( path . join ( 'build' , 'index.html' ), path . join ( 'build' , route , 'index.html' )) })

然後修改package.json

//..."scripts":{//每次build的时候自动执行deploy.js"build":"react-scripts build && node deploy.js",//...}

這樣每次build的時候就會自動執行deploy.js

使用Google Analytics

註冊谷歌賬號,到Google Analytics按提示操作即可。

但是這樣有一個問題,就是在從主頁點擊鏈接進入子頁面(如 mydomain.com/app1 )的時候,analytics並不知道,因為這只是用JavaScript控制的頁面變化。

關於這個問題, react-ga的一個issue裡有很多討論,其中一個解決方式起作用了,我寫在了這篇部落格里。

使用Google AdSense

AdSense的審核不容易通過,我在我的網站只有一頁的時候(儘管瀏覽量很高)申請了幾次都沒有通過,後來有了多個頁面的內容時才通過。然後兩天后就因為非法流量被限制了廣告投放,兩個星期後還沒有恢復。

index.html中添加(如果有的話不需要重複):

<scriptasyncsrc="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

在你需要放廣告的組件中,根據你的client和slot:

export default class AdComponent extends React.Component { componentDidMount () { (window.adsbygoogle = window.adsbygoogle || []).push({}); }​ render () { return ( <div> { /* ... */ } <ins className='adsbygoogle' style={{ display: 'block' }} data-ad-client='ca-pub-12121212' data-ad-slot='12121212' data-ad-format='auto' /> { /* ... */ } </div> ); } }

What do you think?

Written by marketer

blank

6個妙招教你如何升級谷歌廣告

blank

手把手教你使用Google Analytics 創建高級自定義受眾群體!