over 1 year ago

必要時,需要依照風格或是設計師不同的風格來配合,所以我們會需要更改 Status Bar
的顏色,至於改的方式有兩種,可以透過設定檔或是直接從 code 裡面動態修改(比方說切換樣式等等)

以下圖來說,是更改後的樣式,如果沒更改就會跟背景一樣是全黑的,完全看不到 Status bar

前置動作

在專案下找到 info.plist 後將 View controller-based status bar appearance 這個設定關閉,如果找不到就自己新建一個然後設定為關閉就可以了。若設定沒關閉就無法改 Status Bar 的顏色,所以這個前置動作一定要記得做。

從設定檔改

在專案目錄下找到 Targets -> General -> Status Bar Style -> Light

從程式碼中改

UIApplication.shared.statusBarStyle = UIStatusBarStyle.lightContent
// 設定 status bar 為白色


UIApplication.shared.statusBarStyle = UIStatusBarStyle.default
// 設定為預設值

參考資源

 
over 1 year ago

Keyboard does not show up in simulator

Xcode 9.1

因為 Xcode 的預設是把你的電腦 keyboard 當作在模擬器裡面用的主選項,所以需要進去設定模擬器的 hard ware 鍵盤打開,如果沒有打開這個選項就會變成你寫了自動彈出 keyboard 卻在模擬器上沒有彈出來。

具體可以操作 Xcode HardWare -> KeyBoard -> Toggle Software Keyboard

也可以直接按下(⌘ + K),這樣一來 simulator 就會跟實機一樣有鍵盤。

以下是在使用者觸碰螢幕之前,也就是打開某功能或某頁面能夠自動加載鍵盤的方法

在 view did load 指定讓某 outlets 後加入 becomeFirstResponder

Usage:

class ViewController: UIViewController {

    // MARK: - View Did Load

    override func viewDidLoad() {
        super.viewDidLoad()
        subtotalTextfield.becomeFirstResponder()
    }
    
    // MARK: - Outlets

    @IBOutlet weak var subtotalTextfield: UITextField!
}

參考資源

 
over 1 year ago

ES6 之後可以使用 Set

var uniqArray = new Set([1, 2, 3])

uniqArray
// Set(3) {1, 2, 3}


uniqArray.add(3)
// Set(3) {1, 2, 3}


uniqArray.add(4)
// Set(4) {1, 2, 3, 4}

Javascript: Remove Duplicates From Array Of Objects

如果 Array 裡面是放 Object 就不適用了,網路上查到比較多的答案是有人寫了一個專門去除重複元素的 function

function removeDuplicates(originalArray, prop) {
     var newArray = [];
     var lookupObject  = {};

     for(var i in originalArray) {
        lookupObject[originalArray[i][prop]] = originalArray[i];
     }

     for(i in lookupObject) {
         newArray.push(lookupObject[i]);
     }
      return newArray;
 }

Usage:

removeDuplicates(arrayWithDuplicates, 'size');

Returns:

[
    {
        "color": "red",
        "size": "small"
    },
    {
        "color": "blue",
        "size": "medium"
    },
    {
        "color": "red",
        "size": "large"
    }
]

And:

removeDuplicates(arrayWithDuplicates, 'color');

Returns:

[
    {
        "color": "red",
        "size": "small"
    },
    {
        "color": "green",
        "size": "small"
    },
    {
        "color": "blue",
        "size": "medium"
    }
]

參考來源

 
over 1 year ago

目標:密碼設置必須要含英文及數字的組合

app/models/user.rb
  validate :password_complexity
  
  def password_complexity
    if password.present?
       if !password.match(/^(?=.*[a-zA-Z])(?=.*[0-9])) 
         errors.add :password, "Password complexity requirement not met"
       end
    end
  end

拿掉位數限制,這部份 devise 本身就有 validation , 甚至必要時可以直接在 devise config 設定 password length

/^(?=.*[a-zA-Z])(?=.*[0-9])/
   |             |          
   |             |          
   |             |          
   |             |
   |             任意字符串后必须要有「数字」
   |                        
   任意字符串后必须要有「英文」

參考資源

 
over 1 year ago

何謂 race condition ?

競爭危害(race hazard)又名競態條件、竞争条件(race condition),它旨在描述一個系統或者進程的輸出依赖于不受控制的事件出现顺序或者出现时机。 此词源自於兩個訊號試著彼此競爭,來影響誰先輸出。 -- wiki - 競爭危害

AASM 中的 race condition

開發 rails project 很常會使用 AASM 來進行狀態管理,好處是你可以不必寫一堆 if else 來判斷狀態該往何處走。

那麼有一種情況是,當兩個用戶同時更新一筆數據的狀況下,造成 race condition 的情況出現

舉例以交易訂單生成來說

  • order_placed: 是當訂單成立後的狀態
  • notify_paid: 是買家通知付款
  • done: 是完成訂單

那麼有種情況是,買家還沒通知付款,我這邊已經收到帳款,所以可以直接將訂單完成。

但有沒有一種可能是,賣家和買家在同一個時間點點擊狀態變更的按鈕

  • 賣家按下訂單完成
  • 買家通知已經付款

雖然在 AASM 很聰明的幫我們限制了能變更狀態的條件,但是卻會出現在被 object 暫存記憶體的時候,產生 race condition。

class Order < ActiveRecord::Base
  include AASM

  aasm do
    state :order_placed, :initial => true
    state :notify_paid
    state :done
  end
  
  event :notify do
    transitions :from => :order_placed, :to => :notify_paid
  end
  
  event :deliver do
    transitions :from => [:order_placed, :notify_paid], :to => :done
  end
end

這時候我們測試

# 這時候 Order 狀態應該是初始化狀態 order_placed

order_1 = Order.last
order_2 = Order.last

order_1.deliver! # true, 狀態變更為 done
order_2.notify! # true, 狀態變更為 notify_paid

order_2 不是應該被 rollback 拒絕存取才對嗎? order 應該已經變成 done, 沒理由又可以變成 notify_paid 才對呀

但在這個案例中的 object 裡面

order_1, order_2 這兩個 object 已經透過暫存記憶體記住訂單的狀態是 order_placed,所以他們合理的可以轉換狀態,但這樣就不符合我們的邏輯了,難不成在每次 order 執行的時候都要 reload 嗎?

其實不必,我們可以用 AASM 中的 Pessimistic Locking (悲觀鎖定) 來解決。

只需要加上 requires_lock: true,就可以避免 race confidtion

class Job < ActiveRecord::Base
  include AASM

  aasm requires_lock: true do
    ...
  end

  ...
end

讓我們在測試一次

order_1 = Order.last
order_2 = Order.last

order_1.deliver! # true, 狀態變更為 done
order_2.notify! # ROLLBACK, AASM::InvalidTransition: Event 'notify' cannot transition from 'done'.

完美了,可以避免同時間操作產生的 race condition。

小結

不過 Pessimistic Locking(悲觀鎖定)要看情況使用,因為他會影響一些 performance , 他的執行原理是如其名,悲觀的認定每一筆資料存取時,其他的客戶端也會存取同一筆資料,因此對相關的資料進行鎖定,直到自己操作完成才解除鎖定。

這樣的好處是

  • 提高隔離層級
  • 避免 race condition

壞處是

  • 存取效能變差,因為每次都要鎖定

如果你的 project 不會有同時改變狀態的可能發生,可以不用強制一定要在 aasm 上加上 Pessimistic Locking,只需要在適當的時機在用就可以了。

參考資源

悲觀鎖定(Pessimistic Locking)
競爭危害

 
over 1 year ago

If you can not restore backup on high version (like iOS 11.2 beta), maybe you can try my solution.

Situation

currently, I have two Iphone devise

  • Iphone 7 Plus, iOS 11.2 beta2
  • Iphone X, iOS 11.1

I want to restore backup from a newer version of iOS 11.2 beta2 to a IphoneX devise using an older version of iOS 11.1, but iOS and iTunes does not support this.

If you try this, you may see the following error messages:

  • You cannot see or select the most recent backup from the list of available backups in iTunes or iCloud.
  • iTunes displays the alert “The backup …. cannot be restored to this …. because of the software on the …. is too old.”
  • iTunes displays the warning “No backups available.”
  • Apple 備份時出現備份已損毀或不相容

Solution

You can update older devise version to latest ios version, but latest ios beta version is not support Iphone X.

So, you can wait it, or try my solution and following this:

  1. backup on your iTunes now.
  2. Use Decipher Backup Repair tool
  3. Fix it and restore to your newer devise.

notice: 29.99 USD can repair 2 backup.

Now, I restore my newer version of iOS to older version of iOS successful now.

 
over 1 year ago

獲得實時更新的方法(Polling, Comet, Long Polling, WebSocket)

在 HTTP 協議上,只能由 Client 發起請求,等候 Server 端回應,然後獲得資料,來讓當前頁面更新。

但 Server 端是無法主動發起回應的,譬如說,當某討論串下面的留言更新了,要發起通知讓所有人的通知欄顯示一則未讀廣播,Server 端無法主動向所有正在線上的使用者進行廣播。

這時候就有幾種方法可以實作

Polling

早期的作法通常都是用 Javascript 來實作輪詢(Polling)的方式獲得 Server 端的最新資料。

利用 Javascript 中的 setIntervalsetTimeout 在固定的時間內向 Server 端發起 Request 以 JSON 或 AJAX(xhr)的方式取得最新的資料。

備註: setTimeout 是較好的選擇,請參考 [javascript] 深入了解 setTimeout() 與 setInterval() 的不同之處

不過這麼做的好處是容易實現,也沒有其他瀏覽器的延伸問題,最主要的缺點就是造成資源的浪費以及負擔,因為你不知道 Server 端的資料何時會有更新,再沒有更新的情況下你一樣要發起 HTTP 請求,就會有浪費網路資源的狀況,如果是效能較差的裝置例如智慧型手機,可能就會有耗電、使用上卡頓的狀況發生。

Comet

Comet 如果要翻譯成中文是「彗星」的意思,他的作法是把發出的 Request 像彗星的尾巴一樣拉的很長(正常的 Request 很快就結束),這樣一來就可以讓伺服器保持連線的狀態,持續讓 Server 端 Response 資料回來,這樣的作法其實就是把 Polling 做在 Server 端。

但這樣的作法會把傳統的 Web Server 如 Apache 的連線給佔住,所以必須要配合 non-Blocking IO 的 Web Server 才能運作。

Long Polling

長時間輪詢的作法是 Comet 演化過後的方式,也是目前 Facebook、Plurk 實現動態更新的方法。

這樣的作法是發一個長時間等待的 Request,當 Server 端有資料 Response 時立刻斷掉、接著在發一個新的 Request。

與 Polling 不同之處的在於他比較有效率,可以等到 Timeout 或拿到新資料的時候在重新發送,相對之下減少很多網路資源的浪費。

加上通常是 Client 在傳遞資料(每次發 Request 時)以及沒有瀏覽器相容性的問題,算是比較常見的解法。

值得注意的是,如果你的 Server 端不支援 non-blocking IO 的話,他其實還是一般的 Polling

例如

(function polling() {
    $.ajax({
        url: "http://server",
        type: "post",
        dataType: "json",
        timeout: 30000,
        success: function(data) {
            /* Do something */
        },
        complete: function() {
            /* Polling here. */
            polling();
        }
    });
})();

在上面的程式碼中,等待三十秒後重複發送 AJAX 請求到 Server 端,而 Long Polling 的作法是

  • Client side 發送 Request 給 Server side
  • Server 收到後 Response 給 Client ,並斷開連線
  • Client 收到 Response 後,執行 Callback ,再次發送 Request 給 Sevrer

這樣的方式是無窮迴圈,但如果後端收到之後並沒有斷開連線,那麼前端就只會每 30 秒斷線重連,其實也就是一般的 Polling 而已。

非 non-blocking IO 的 Server 不行的原因:

假定送一個 AJAX 給 Server side, 事情做完之後,丟一個 Response 給 Client , 一樣會觸發 complete 條件。

但當你的 Server 沒放開連線,你只能等 Client timeout, 並且再次發送 Request 才能繼續動作,而這時候 Server 的資料到底有沒有完成,根本不知道,所以 non-blocking IO 的 Server 多少能避開這種問題。

但這都只是單向的溝通。

WebSocket

WebSocket 的誕生就是為了解決單向請求的問題,可以在一條連線上提供全雙工、雙向的資料傳輸,在這樣的標準下你可以很容易實作一個兼具可擴充性與即時性的網頁應用程式。

他的特點

  • 支援程度高,參考Can I use?
  • 建立於 TCP 協議之上,服務器端實現較容易
  • 與 HTTP 協議有良好的兼容性,默認端口也是 80 與 443 port,並且在握手階段(handshake)採用 HTTP 協議,因此不容易被屏蔽,能通過各種 HTTP 代理服務器
  • 性能較 Polling 好,通信高效

協議標示符號是 ws(若加密則為 wss),服務器網址就是 URL

ws://example.com:80/some/path

WebSocket 算是借用 HTTP 協議來完成一部分的 handshack

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

詳細更多部分請參考

參考資源

 
over 1 year ago

官方圖片解釋

Understanding Vue LifeCycle Hook

beforeCreate

在 Vue Instance、 Component(組件/元件) 初始化之後,數據觀測(data observer)和 event/watcher 事件配置之前被調用。

created

Vue Instance、 Component(組件/元件)創建完成,資料 $data 已經可以取得,屬性已經綁定,但 DOM 還未生成,並且 $el 屬性還不存在。

beforeMount

在掛載開始之前被調用,相關的 render 函數首次被調用。

mounted

el 被新創建的 vm.$el 替換,並掛載到 instance 上去之後調用該 hook。

beforeUpdate

數據更新之前被調用,發生在虛擬 DOM 重新渲染之前,可以在這個 hook 中進一步改變狀態,並不會觸發附加的重新渲染過程,這時還不會描繪 View。

updated

由於數據更改導致虛擬 DOM 重新渲染,這時 DOM 已經更新完成, View 被顯示在畫面上。

activated

有設定 keep-alive 時,這個 hook 會被呼叫。

deactivated

停用 keep-alive 時被呼叫。

beforeDestroy

Instance 被銷毀之前調用,在這一步中,該 instance 完全可以使用。

destroyed

Vue Instance 銷毀後調用,調用後該 instance 的所有東西會解除綁定,也會同時解掉所有 event listener, 所有 child instance 也會清除。

注意

  • 資料在 created 以後才存取的到(別把資料初始化跟 ajax 寫在 beforeCreate)

場景運用

  • beforeCreate: 加入 loading 事件
  • created: 在這結束 loading, 做 initialize 實現函數執行
  • mounted: 在這對 backend 發起請求, get some data 後搭配 hook do something
  • beforeDestroy: 你確認刪除__嗎?
  • destroyed: 當該 component 刪除後清空相關內容

reference

 
over 1 year ago

基本上只要你的國家普遍瀏覽器搜尋資料時是使用 Google 的,在做專案時通常會有 SEO 的需求,SEO的全名是(Search Engine Optimization),也就是將你的網站權重提高,能夠在搜尋業面前幾筆就能被曝光。

SEO的規則基本上一直在變化,權重的給分也隨著技術升級而有了新的規則,像以往的網站只是網站,現在的網站還要能夠支援 RWD 來讓行動裝置瀏覽時能夠更加輕鬆,也免去了做 mobile app 的勞力(有能力兩個都做當然好囉)。

Google 會定時有 bot 來爬網站,爬完之後依照權重進去排名,權重大致上要在乎的就是幾點

  • 善用 Meta Tag / Meta Data 幫網頁劃重點
  • Url 具有意義
  • HTML tag 沒有亂用,例如一大堆 h1
  • 採用 HTTPS 連線
  • 支援 RWD(Responsive Web Design)
  • 網站開啟速度
  • 語系與國家
  • Sitemap
  • 爬蟲
  • 瀏覽量

搞定 Meta Tag / Meta Data

Title Tag: 當前頁面的標題,關鍵字請往前放,字數不宜過長,否則有可能視為權重作弊,建議

  • 英文字數 70 以內
  • 中文字數 40 以內

範例

<title> Rails 網站 SEO 實務技巧 | Nic 的部落格</title>

Meta Description Tag: 每個頁面的敘述,文案好壞間接影響點閱率

  • 含標點符號的英文在 150 字內
  • 中文十二字內,關鍵字往前放

範例:

<meta name="description" content="SEO不是玄學,是一個 Rails Developer 該學會的搜尋引擎優化技巧">

以上兩個標籤非常重要,每一個頁面一定要不一樣,如果過多重複,搜尋引擎會認為你在作弊,是會扣分的哦

Canonical Url: 告訴搜尋引擎關於這個頁面的標準網址,有時候我們一個頁面會帶很多參數,可能是語系、搜尋參數、等等,這個標籤可以讓搜尋引擎只收錄正確的網址就可以了

例如:

https://www.example.com/products?category=dresses&color=green

後面就夾帶了 category 與 color 的參數傳遞,這樣的網址看起來會非常噁心

那麼 Canonical Url 這個 tag 就可以這樣寫

<link rel="canonical" href="https://www.example.com/products" />

這樣子就不會把一些帶有參數的網址收錄到搜尋引擎下了

Facebook Open Graph: 這是專門給 Facebook 抓取用的,可以在這些 meta tag 裡面調整你要分享出去的內容長什麼樣子,如果都沒有設定,他會預設抓取你的 title description tag 來作為參考。

可以用 Facebook debug tools 來作為偵錯改善的工具

Facebook 分享縮圖設定範例:

<meta property="og:image" content="https://example.me/img/about.jpg">

Twitter Cards: 這個就是專門給 Twitter 抓的,一樣可以調整分享後的樣式。

在 Rails 實作部分可以用

讓 URL 具有意義

禁用連結,如果有一些連結你不想被計入SEO,那麼你可以使用 nofollow 標籤。

情況大概會是,付費連結、留言裡的連結,或是登入登出這種沒有必要被收入的連結會用到

範例

link_to "不想被收錄", awesome_path, rel: 'nofollow'

關於 nofollow

在一般 CRUD 出來的網址,通常都會是 http://example.com/products/1

那這個產品的URL是用數據庫的 ID 作為依據,這樣一來光看 URL 是沒有任何意義的,也無法提升權重,比較好的作法是讓網址具有意義

http://example.com/products/aeron-chair
http://example.com/products/xbox-360-white

這樣一來,不僅網址就能夠看得出來這個 product 是什麼,也能提升搜尋的權重。

怎麼做呢?

在 Rails 上面可以使用 friendly_id 這隻 Gem,

詳細的實作我在之前有寫過一篇 [Gem] 使用 Friendly_id 與 Babosa 美化你的Rails 網址

在這裡面的教學還可以讓 URL 帶中文的 slug。

幾點需要注意的是,如果要提升網域的權威性,請在主網域使用
例如:

http://example.com/products/aeron-chair

會比

http://shop.example.com/products/aeron-chair

來的更好,因為他可以直接提升 http://example.com 的網域分數

慎用 HTML tag

HTML tag 如果亂用,例如在同一個頁面有一大堆 h1,是相當扣分的行為

因為 HTML tag 其實就是拿來替你的網頁劃清楚的重點,他是一個「具有意義的語言」

HTML 當初在設計時,本身就帶有「語意」

你可以這樣理解

  • h1 是大標題
  • h2, h3 是中標題
  • h4, h5, h6 是小標題
  • p 是指 paragraph (段落)
  • strong 是重點部分,他與 b 不同的是, b 只有粗體,但 strong 是加重語語氣,如果是盲人使用閱讀器在觀看你的網站時,加重語氣可以讓輔助導讀的軟體能夠正確的念出這段話
  • img 中的 alt 是指替代文字, title 是標題

開發者希望他的網站能夠正確被收錄,那麼你就應該,正確的使用 HTML 語意標籤。

by the way, <div> 是對SEO沒有特別的加分或扣分效果,因為從以前就很流行以 div + CSS 來達到網站前端畫面開發,畢竟 div 沒什麼包袱嘛,他就是區塊囉

所以 <div><span> 是沒有語意的,他只是容器

規則標準:

  • h1 一個頁面只能有 1 個
  • h2 一個頁面只能有 2~3 個
  • h3 一個頁面可以有 6~10 個

HTML 標籤權重由高至低

title > meta description > h1 > h2 > h3 > strong > p

採用 HTTPS 連線

因為近年來非常重視資安問題,尤其現在很多金流行為是可以透過網站傳輸完成的,這當中可能會有輸入信用卡等交易的機密資料,那麼用 HTTPS 可以避免被第三方監聽,因為這過程是加密傳輸的。

HTTPS 是指你的網站有沒有安裝 SSL(Secure Sockets Layer , 傳輸層安全協議),如果你有確實安裝SSL的認證,通訊協定就會從 HTTP 改變為 HTTPS(Hypertext Transfer Protocol Secure , 超文字安全傳輸協定)。

在 2014 年時, Google 官方正式宣布 HTTPS 已被列入搜尋引擎演算法之一

但如果你的網站只是「內容型網站」,沒有涉及到用戶資安問題(例如交易),就目前來說,不使用 HTTPS 並不會有「超大的影響」。

不過值得注意的是,從 2017 年 10 月起,從 Chrome 62 開始,只要是需要輸入任何資料的網頁,若未使用HTTPS,即會被標示為不安全。

參考 Google Chrome 官方文章

也因為 SSL 的憑證基本上都是要錢的,但也有很佛心的公司 Let's Encrypt 大力推廣這種加密憑證的安全,也有釋出三個月免費的版本,過期的話就要重新簽名。

申請憑證的流程大致上是:

  1. 先自己生成一個私鑰、一個申請用的憑證CSR
  2. 將 CSR 傳上去給憑證機構
  3. 憑證機構認證你真的擁有這個網域
  4. 下載 SSL 憑證
  5. 將私鑰和 SSL 憑證安裝到網站服務器上

如果主要客戶不是在中國,那麼可以更簡單的申請使用 Cloudflare 這個 CDN 服務,這包含免費的 SSL 憑證,可以免去申請安裝的麻煩。它的 Flexible SSL 模式,可以讓終端使用者到 CloudFlare 是加密連線,而你的服務器不需要安裝。使用 Cloudflare 需要將 DNS 也給它管理,在註冊的流程中會要求你去修改 Namecheap 改用 Custom DNS。

支援 RWD 響應式網頁設計

做 RWD 的好處是可以保有連結單一性,讓原本的流量不會因為行動裝置而沖散,因為這個連結的瀏覽量會讓他的權重變高,更容易出現在搜尋排名上面,但如果分別做 mobile/desktop 版,就會有兩種不同的網址連結,會讓 SEO 的效果打折。

RWD,也不是有做就好,而是會去依照載入速度有不一樣的評分。

詳細可以到 Google 提供的簡易測試工具來測試一下你的讀取秒數吧,依照 Google 說法是人的耐性只有三秒XD,那就盡可能的壓到 3 秒以下吧 XDrz。

網站開啟速度

通常一個網站會慢多半不是後端處理 query 的速度,都會是在前端資源情況吃太緊,既然要作最佳化就必須要用科學化的方式量測,這樣一來我們才知道最佳化有沒有成功。

Chrome 的除錯器本身就很詳細,可以觀察 Network 在 Load page 花了多長的時間。

對前端來說,重視的是 Page load time, 而不是單一 request 的時間,因為網頁的組成有 HTML + CSS + JavaScript

Google 提供的好用工具 PageSpeed Insights

PageSpeed Insight 評分標準

或是用 Chrome 外掛 Lighthouse

都有清楚的報表以及提示你如何改善。

知識點,在 HTTP2 以後,有 async 和 defer 屬性可以用。

以往的關鍵渲染會是把 <script> 移出 <head>, 讓 CSS 優先加載達到畫面快速渲染,在載入能夠有互動式效果的 JS file。

不過新的屬性可以讓瀏覽器知道要異步加載

例如

app/views/layout/application.html.erb
-  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', :async => true %>

或是

app/views/layout/application.html.erb
-  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', :defer => true %>

async 與 defer 差別在於

  • async, 瀏覽器不會阻擋 HTML 渲染,當 JavaScript 下載完時就會直接執行,不會等 HTML DOM加載
  • defer, 瀏覽器也不會阻擋 HTML 渲染,但是當 JavaScript 下載完成後,會等 HTML 加載完成,才會執行 JavaScript。如果你的 JavaScript 裡面有依賴 DOM 的話,適合用這個方式。

CSS 也被瀏覽器視為一種 render blocking 的資源,當瀏覽器解析 HTML 看到 <link href="style.css" rel="stylesheet" 時,就會等待完整解析這個 CSS 後才會繼續渲染頁面。

語系與國家

如果你的網站本身有支援多語系,那麼沒有設定好的情況會變成說,不論哪個國家的搜尋引擎搜到你,進來都還要自己調整語系,而且在 google 搜尋結果上面也會變得怪異,例如:美國 IP 搜出來的標題是中文之類的。

所以別忘記在你的 html tag 裡面加入

<html lang="zh">

可以參考 Apple 官方網站的作法,該網站是很標準的能夠支援多語系 SEO 的寫法,具體如下

<link rel="canonical" href="https://www.apple.com/">
<link rel="alternate" href="https://www.apple.com/" hreflang="en-US">
<link rel="alternate" href="https://www.apple.com/ae-ar/" hreflang="ar-AE">
<link rel="alternate" href="https://www.apple.com/ae/" hreflang="en-AE">
<link rel="alternate" href="https://www.apple.com/am/" hreflang="en-AM">
...

這樣就能夠讓搜尋引擎正確在每個國家直接顯示相對應語系的網站了。

這個方法不是唯一,你也可以選擇用 Sitemap 的方法來讓搜尋引擎正確收錄。

擇一即可。

Sitemap

Sitemap基本是描述一個網站的架構,它可以是任意形式的網頁頁面,通常是採用分級或分類的形式,能夠消化龐大的往架構,對於網站的訪問者在網站瀏覽上的資訊需求也能快速獲得,且能提高SEO搜尋引擎優化的效果,對網站的幫助是非常大。

參考 Apple 繁體中文官網的 Sitemap

在這部份用 Gem "sitemap_generator" 可以輕鬆幫你完成,並且有 rake task 能夠讓你每次產生新內容的時候更新上去。

爬蟲

在 Rails 的路徑 public/robots.txt 是專門拿來給搜尋引擎爬蟲讀取的,這隻檔案會告訴他什麼資源不需要被收錄。

參考 Apple 官方網站的 robots.txt

不過有時候我們除了 Production 環境以外,可能還有 Staging ,避免被收錄的話可以依照環境動態生成 robots 這隻檔案。

config/routes.rb
get '/robots.txt' => 'home#robots'
home_controller.rb
def robots                                                                                                                                      
  robots = File.read(Rails.root + "config/robots.#{Rails.env}.txt")
  render :text => robots, :layout => false, :content_type => "text/plain"
end

分別在 public/ 下生成 robots.staging.txt, robots.production.txt

就可以做到環境控制 robots.txt 生成囉

參考 Gist

瀏覽量

你的網域權重的提升也會因為瀏覽量的高低有不一樣的排名,所以適時的導流進去,讓更多用戶喜歡上這個產品能夠不斷回訪網站,會讓權重分數慢慢往上爬,這就跟養小孩一樣,需要一點時間才會成長。

Google 是會將大量的垃圾連結或不優質的內容降低權重的,所以非常重視網站經營者生成的內容,他們的演算法會一直更新,阻擋那些嘗試作弊欺騙權重的網站,最後一點就是認真經營網站囉。

參考資源

 
over 1 year ago

平常我在記筆記的時候,最常使用的是 MWeb 、 Evernote,之所以會特地分兩款的原因是因為 evernote 不支援 markdown 書寫。

對於我這種已經寫習慣的人,實在是很難轉換他的 syntax,不過好玩的是, Sublime 裝了 Plugin 就可以解決這件事情了,還可以做到雙向轉換

  • 在 sublime 寫 markdown
  • 在 evernote 是正常的 syntax

安裝

sublime-evernote

  • 打開 Sublime 用 Install Package 安裝
  • 設置關聯,在此之前要去申請一組 API,點擊 Create a developer token
  • 打開 Preferences > Package Settings > Evernote >Settings - User

填入你的 API 資訊

{
 "noteStoreUrl": "",
 "token": ""
}

通過呼叫 Command + Shift + P,輸入 Evernote,後顯示 Evernote 選單,表示安裝成功。

點擊Evernote:list recent notes,如果看到選單中出現最新的筆記,則說明授權成功!

常用選項

  • Evernote: List resent notes 最近幾筆筆記
  • Evernote: New empty note 創建筆記
  • Evernote: Search note 搜索筆記

嫌麻煩?那就用Marxi吧~

使用心得

其實我寫這篇文還是用了 MWeb,想說也許有人需要就寫了,我自己還是用不習慣,主要有兩點

  • 我希望能夠即時預覽 (MWeb can do it!)
  • Sublime 不知道要寫到哪裡才會換行,有時候螢幕太寬會忘我 XD
參考資源