MathJax 瘦身記

說來話長

對於理工科背景的人而言,不管是 Web x.0 的時代,對應的網站都應該支持數學公式。因此,QQ 不支持數學公式,就不必用 QQ;微信不支持數學公式,就不必用微信;微博不支持數學公式,就不必用微博……然而這一切都要歸罪於 HTML 的發明者,理工科的專家發明的東西竟然不支持數學公式……雖然有個 MATHML,但基本上形同虛設(關於 MATHML 的知識,可參考:http://www.ibm.com/developerworks/cn/xml/x-mathml/)。javascript

事實上,HTML 並不是對數學公式徹底的不支持,利用 Javascript + CSS + 一組完備的數學字體,是徹底能夠直接以 HTML 標記的形式產生數學公式圖形的。MS Word 與 TeX 之因此可以排版數學公式,也是由於它們有本身的『CSS』與數學字體。這個方案也許是 HTML 對數學公式提供支持的終極方案,也是最爲複雜的方案,可是 MathJax 的開發者們成功的實現了這個方案。css

之因此說基於『Javascript + CSS + 一組完備的數學字體』的 HTML 數學公式支持方案是最複雜的方案,這個問題,常常折騰 CSS 的人必定會明白的,那就是 CSS 面向各類瀏覽器的兼容性問題。因此 MathJax 很是複雜,所以它也很是膨脹。html

能夠下載最新的 MathJax 包看一下,java

$ wget https://github.com/mathjax/MathJax/archive/master.zip

$ du -h ./master.zip
33M     master.zip

$ unzip master.zip  # 解包後獲得 MathJax-master 目錄

$ du -h -s MathJax-master
176M    MathJax-master

對於網站而言,176 MB 的大小不算什麼,原本 MathJax 就是爲網站上部署網頁數學公式支持而開發的,適配各類網頁瀏覽器。但總有些人沒法接受這麼大的軟件包,好比我。node

Nikola 與 MathJax

自從實驗室服務器壞掉以後,咱們的公共 wiki 就無法用了。雖然一部分數據是有備份的,可是再從新搭建一個服務器環境實在是太麻煩了,並且也一直缺少專人維護。python

爲了解決這個小團體內部信息的分享問題,我想了個辦法,讓你們在各自的機器上部署 Nikola 。所謂 Nikola,就是一款靜態網站生成器,這意味着實驗室每一個人都創建了本身的我的靜態站點。平時要分享一些內容,只需用 markdown 或 reStructuredText 寫出文檔,而後用 nikola build 命令產生 HTML 文件。在 nginx 的幫助下,咱們能夠互相訪問彼此的站點,而且也能夠利用 rsync 將其餘人的站點的內容同步到本地目錄,這有點像 git 的工做方式。nginx

爲了讓 Nikola 可以支持數學公式,我給它配置了 MathJax,即在 Nikola 的配置文件 conf.py 中寫入如下內容:git

MATHJAX_CONFIG = """
<script type="text/javascript" src="../MathJax/MathJax.js?config=TeX-AMS_HTML-full">
</script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        tex2jax: {
            inlineMath: [ ['$','$'], ["\\\(","\\\)"] ],
            displayMath: [ ['$$','$$'], ["\\\[","\\\]"] ],
            processEscapes: true
        },
        TeX: {
             Macros: {
                    RR: '{\\bf R}',
                    bold: ['{\\bf #1}', 1]
             }
        },
        "HTML-CSS": { imageFont: null }
    });
</script>
"""

MathJax 目錄是放在個人 Nikola 根目錄下的,個人 Nikola 根目錄構成以下:github

$ tree -L 1 rca
rca
├── cache
├── conf.py
├── conf.pyc
├── files
├── galleries
├── images
├── listings
├── MathJax
├── mycss
├── output
├── posts
├── stories
└── templates

其中,rca 就是個人 Nikola 根目錄;posts 是放置 markdown 或 reStructuredText 源文件的目錄。npm

在 rca 目錄下,若是執行:

$ nikola build

那麼,posts 目錄中的 markdown 或 reStructuredText 源文件就會被轉換爲 HTML 文件。output 目錄用於存放所生成的 HTML 文件。

我爲 rca 這個站點配置了局域網內的 nginx 服務器,即在 /etc/nginx/nginx.conf 文件中增長如下內容:

server {
        listen 192.168.0.7;
        server_name localhost;

        access_log /var/log/nginx/localhost.access_log main;
        error_log /var/log/nginx/localhost.error_log info;

        root /home/garfileo/var/rca/output;
    }

也就是說,output 是個人站點的根目錄,而 MathJax 目錄則在站點根目錄以外。這時,output 目錄中的 HTML 文件就沒法加載 MathJax.js 文件了。

若是將 MathJax 目錄至於 output 目錄中,能夠解決上述問題,可是 Nikola 的官方文檔不建議用戶在 output 目錄中放文件,由於 Nikola 的某些操做會將 output 目錄中的全部內容清除。若是須要將一些文件放到 output 目錄,那麼 Nikola 支持文件的複製,亦即在 conf.py 文件中增長:

FILES_FOLDERS = {'MathJax': 'MathJax'}

這樣,每次執行 nikola build 命令時,nikola 便會掃描 FILES_FOLDERS 目錄中的文件有沒有變化,若是有變化就會發生變化的文件複製到 output 目錄中。

如今,問題終於出現了。由於 MathJax 解包後的大小是 176 MB,在個人機器上,它被 nikola 掃描一次就須要用 25 秒,而未部署 MathJax 時 nikola 掃描文件只需 3 秒。因此,想隨時查看文檔的輸出結果就變得不現實了。不知道其餘靜態站點生成工具部署 MathJax 是否是也存在這個問題。

我的只須要小而精的東西

後來,我試着在 nginx.conf 中爲 MathJax 目錄單獨配置一個服務器,而後在 Nikola 的配置文件中使用 MathJax 的 URL 來尋找 MathJax.js 文件,這樣作是能夠的,可是 MathJax.js 中所使用的字體路徑是相對路徑而非絕對路徑,而這個相對路徑是 Nikola 的。結果就是,MathJax.js 找不到字體,因而它只能用瀏覽器默認字體,雖然能顯示數學公式,可是隻是醜陋不堪的顯示。

hack 一下 MathJax.js,讓它能根據 MathJax 的 URL 找到字體目錄,這樣興許能解決問題。然而,雖然 JavaScript 是無處不在的,可是我實在不肯意 hack 它。之因此不肯意,是由於我不會,並且還不肯意學。

還有一條路,就是對 MathJax 進行精簡。由於它支持的瀏覽器那麼多,而我卻只是 firefox 的死忠,因此確定能夠去掉不少文件。分析了一下 MathJax 的目錄,發現僅僅位圖字體就佔用了 116 MB,觸目驚心啊!

對我來講,瘦身應該是最簡單的方法。至於跨服務器調用 MathJax 的事,應該交給願意作並且願意分享的人來作。

MathJax-grunt-cleaner

在 google 上面用了 MathJax trim, MathJax slim 之類的關鍵詞,很快就發現了這個:https://github.com/mathjax/MathJax-grunt-cleaner

MathJax-grunt-cleaner 的 README 看上去挺簡單的,也許它的開發者認爲凡是使用這個東西的人必然是瞭解 node.js 與 grunt 的。惋惜,如今他恰恰碰到了我這種在他眼裏可能什麼都不會可是依然堅持要用他的東西的人,因此下面的 MathJax-grunt-cleaner 的用法可能很是笨拙且不對路。

個人作法是先下載 MathJax-grunt-cleaner:

$ git clone https://github.com/mathjax/MathJax-grunt-cleaner.git

而後將其中的 package.json 與 Gruntfile.js 文件複製到 MathJax-master 目錄(若是不知道這個是什麼目錄的話,抓緊看本文的起始部分)。在 MathJax-master 目錄中使用 npm 命令安裝 package.json 中所記錄的依賴包:

$ npm install

npm 是 node.js 的包管理命令。這也意味着,要使用 MathJax-grunt-cleaner,你須要 node.js……這對於 JS 程序猿而言,不是什麼問題吧?

而後就開始修改 Gruntfile.js 文件中的 template 部分,即:

grunt.registerTask("template", [
    ...
    ...
  ]};

template 默認是幹掉 MathJax 的一切,因此你想留下哪些內容,就註釋掉相應的 clean 語句,而後執行 grunt 命令對 MathJax 進行殘酷的閹割:

$ grunt template

若是將:

grunt.registerTask("template"

換爲:

grunt.registerTask("default"

那麼只需執行:

$ grunt

便可完成清理過程。

下面是我定製的 default 部分,僅供參考:

grunt.registerTask("default", [
    // **Notes** on the template. When instructions say "Pick one", this means commenting out one item (so that it"s not cleaned).
    //
    //      Early choices.
    "clean:unpacked",
    //"clean:packed", // pick one -- packed for production, unpacked for development.
    //"clean:allConfigs", // if you do not need any combined configuration files.
    //      Fonts. Pick at least one! Check notes above on configurations.
    "clean:fontAsana",
    "clean:fontGyrePagella",
    "clean:fontGyreTermes",
    "clean:fontLatinModern",
    "clean:fontNeoEuler",
    "clean:fontStix",
    "clean:fontStixWeb",
    //"clean:fontTeX",
    //      Font formats. Pick at least one (unless you use SVG output; then clean all).
    //"clean:dropFonts", // when using SVG output
    "clean:eot",
    //"clean:otf",
    "clean:png",
    "clean:svg",
    "clean:woff",
    //      Input. Pick at least one.
    "clean:asciimathInput",
    "clean:mathmlInput",
    //"clean:texInput",
    //       Output
    //"clean:htmlCssOutput",
    "clean:mathmlOutput",
    "clean:svgOutput",
    // Extensions. You probably want to leave the set matching your choices.
    "clean:extensionsAsciimath",
    "clean:extensionsMathml",
    //"clean:extensionsTeX",
    "clean:extensionHtmlCss",
    // Other items
    "clean:locales",
    "clean:miscConfig",
    //        "clean:miscExtensions", // you probably want that
    "clean:images",
    "clean:notcode"
  ]);

清理過程結束後,從 MathJax-master 目錄中移走 Gruntfile.js, package.json, 以及 npm 安裝的 js 包目錄 node_modules,能夠找個地方把它們保存起來,以備往後使用。

精簡後的 MathJax 大小爲:

$ du -h -s MathJax-master
2.3M    MathJax-master

從 176 MB 到 2.3 MB,我閹割的也許是一部波瀾壯闊的瀏覽器發展歷史。

相關文章
相關標籤/搜索