Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
otted 是一個 HTML、CSS、JavaScript 演示環境,可編輯源代碼。
安裝:
npm: npm install --save jotted
Bower: bower install --save jotted
jsDelivr:
<link rel="stylesheet" type="text/css" >
<script src="https://cdn.jsdelivr.net/jotted/latest/jotted.min.js"></script>
主要特性:
輕量級:無依賴,默認使用 textarea
s 編輯
插件:靈活插件架構,可定制編輯器,預處理器等
代碼編輯器:包括類似 Ace 和 CodeMirror 的代碼編輯器插件
預處理器:包括預處理器插件 (ES6, CoffeeScript, Less, Stylus, Markdown)
快速入門:
<link rel="stylesheet" href="jotted.css">
<script src="jotted.js"></script>
<div id="editor"></div><script> new Jotted(document.querySelector('#editor'), { files: [{ type: 'html', url: 'index.html' }] })</script>
示例:
new Jotted(document.querySelector('#demo'), {
files: [{
type: 'css',
url: 'index.styl'
}, {
type: 'html',
content: '<h1>Demo</h1>'
}],
showBlank: true,
plugins: [ 'stylus',
{
name: 'codemirror',
options: {
lineNumbers: false
}
}
]
Jotted 遵循 MIT 開源授權協議
微信訂閱號:開源派 (opensourcepie)
開源派官網:osp.io 作者:葉秀蘭
如今,Javascript 模塊化規范非常方便、自然,但這個新規范僅執行了2年,就在 4 年前,js 的模塊化還停留在運行時支持,10 年前,通過后端模版定義、注釋定義模塊依賴。對經歷過來的人來說,歷史的模塊化方式還停留在腦海中,反而新上手的同學會更快接受現代的模塊化規范。
但為什么要了解 Javascript 模塊化發展的歷史呢?因為凡事都有兩面性,了解 Javascript 模塊化規范,有利于我們思考出更好的模塊化方案,縱觀歷史,從 1999 年開始,模塊化方案最多維持兩年,就出現了新的替代方案,比原有的模塊化更清晰、強壯,我們不能被現代模塊化方式限制住思維,因為現在的 ES2015 模塊化方案距離發布也僅僅過了兩年。
直接定義依賴 (1999): 由于當時 js 文件非常簡單,模塊化方式非常簡單粗暴 —— 通過全局方法定義、引用模塊。這種定義方式與現在的 commonjs 非常神似,區別是 commonjs 以文件作為模塊,而這種方法可以在任何文件中定義模塊,模塊不與文件關聯。
閉包模塊化模式 (2003): 用閉包方式解決了變量污染問題,閉包內返回模塊對象,只需對外暴露一個全局變量。
模版依賴定義 (2006): 這時候開始流行后端模版語法,通過后端語法聚合 js 文件,從而實現依賴加載,說實話,現在 go 語言等模版語法也很流行這種方式,寫后端代碼的時候不覺得,回頭看看,還是掛在可維護性上。
注釋依賴定義 (2006): 幾乎和模版依賴定義同時出現,與 1999 年方案不同的,不僅僅是模塊定義方式,而是終于以文件為單位定義模塊了,通過 lazyjs 加載文件,同時讀取文件注釋,繼續遞歸加載剩下的文件。
外部依賴定義 (2007): 這種定義方式在 cocos2d-js 開發中普遍使用,其核心思想是將依賴抽出單獨文件定義,這種方式不利于項目管理,畢竟依賴抽到代碼之外,我是不是得兩頭找呢?所以才有通過 webpack 打包為一個文件的方式暴力替換為 commonjs 的方式出現。
Sandbox模式 (2009): 這種模塊化方式很簡單,暴力,將所有模塊塞到一個 sanbox 變量中,硬傷是無法解決明明沖突問題,畢竟都塞到一個 sandbox 對象里,而 Sandbox 對象也需要定義在全局,存在被覆蓋的風險。模塊化需要保證全局變量盡量干凈,目前為止的模塊化方案都沒有很好的做到這一點。
依賴注入 (2009): 就是大家熟知的 angular1.0,依賴注入的思想現在已廣泛運用在 react、vue 等流行框架中。但依賴注入和解決模塊化問題還差得遠。
CommonJS (2009): 真正解決模塊化問題,從 node 端逐漸發力到前端,前端需要使用構建工具模擬。
Amd (2009): 都是同一時期的產物,這個方案主要解決前端動態加載依賴,相比 commonJs,體積更小,按需加載。
Umd (2011): 兼容了 CommonJS 與 Amd,其核心思想是,如果在 commonjs 環境(存在 module.exports,不存在 define),將函數執行結果交給 module.exports 實現 Commonjs,否則用 Amd 環境的 define,實現 Amd。
Labeled Modules (2012): 和 Commonjs 很像了,沒什么硬傷,但生不逢時,碰上 Commonjs 與 Amd,那只有被人遺忘的份了。
YModules (2013): 既然都出了 Commonjs Amd,文章還列出了此方案,一定有其獨到之處。其核心思想在于使用 provide 取代 return,可以控制模塊結束時機,處理異步結果;拿到第二個參數 module,修改其他模塊的定義(雖然很有拓展性,但用在項目里是個攪屎棍)。
ES2015 Modules (2015): 就是我們現在的模塊化方案,還沒有被瀏覽器實現,大部分項目已通過 babel 或 typescript 提前體驗。
從語言層面到文件層面的模塊化
從 1999 年開始,模塊化探索都是基于語言層面的優化,真正的革命從 2009 年 CommonJS 的引入開始,前端開始大量使用預編譯。
這篇文章所提供的模塊化歷史的方案都是邏輯模塊化,從 CommonJS 方案開始前端把服務端的解決方案搬過來之后,算是看到標準物理與邏輯統一的模塊化。但之后前端工程不得不引入模塊化構建這一步。正是這一步給前端開發無疑帶來了諸多的不便,尤其是現在我們開發過程中經常為了優化這個工具帶了很多額外的成本。
從 CommonJS 之前其實都只是封裝,并沒有一套模塊化規范,這個就有些像類與包的概念。我在10年左右用的最多的還是 YUI2,YUI2 是用 namespace 來做模塊化的,但有很多問題沒有解決,比如多版本共存,因此后來 YUI3 出來了。
YUI().use('node', 'event', function (Y) { // The Node and Event modules are loaded and ready to use. // Your code goes here! });
YUI3 的 sandbox 像極了差不多同時出現的 AMD 規范,但早期 yahoo 在前端圈的影響力還是很大的,而 requirejs 到 2011 年才誕生,因此圈子不是用著 YUI 要不就自己封裝一套 sandbox,內部使用 jQuery。
為什么模塊化方案這么晚才成型,可能早期應用的復雜度都在后端,前端都是非常簡單邏輯。后來 Ajax 火了之后,web app 概念的開始流行,前端的復雜度也呈指數級上漲,到今天幾乎和后端接近一個量級。工程發展到一定階段,要出現的必然會出現。
前端三劍客的模塊化展望
從 js 模塊化發展史,我們還看到了 css html 模塊化方面的嚴重落后,如今依賴編譯工具的模塊化增強在未來會被標準所替代。
原生支持的模塊化,解決 html 與 css 模塊化問題正是以后的方向。
再回到 JS 模塊化這個主題,開頭也說到是為了構建 scope,實則提供了業務規范標準的輸入輸出的方式。但文章中的 JS 的模塊化還不等于前端工程的模塊化,Web 界面是由 HTML、CSS 和 JS 三種語言實現,不論是 CommonJS 還是 AMD 包括之后的方案都無法解決 CSS 與 HTML 模塊化的問題。
對于 CSS 本身它就是 global scope,因此開發樣式可以說是喜憂參半。近幾年也涌現把 HTML、CSS 和 JS 合并作模塊化的方案,其中 react/css-modules 和 vue 都為人熟知。當然,這一點還是非常依賴于 webpack/rollup 等構建工具,讓我們意識到在 browser 端還有很多本質的問題需要推進。
對于 css 模塊化,目前不依賴預編譯的方式是 styled-component,通過 js 動態創建 class。而目前 css 也引入了與 js 通信的機制 與 原生變量支持。未來 css 模塊化也很可能是運行時的,所以目前比較看好 styled-component 的方向。
對于 html 模塊化,小尤最近爆出與 chrome 小組調研 html Modules,如果 html 得到了瀏覽器,編輯器的模塊化支持,未來可能會取代 jsx 成為最強大的模塊化、模板語言。
對于 js 模塊化,最近出現的 <script type="module"> 方式,雖然還沒有得到瀏覽器原生支持,但也是我比較看好的未來趨勢,這樣就連 webpack 的拆包都不需要了,直接把源代碼傳到服務器,配合 http2.0 完美拋開預編譯的枷鎖。
上述三中方案都不依賴預編譯,分別實現了 html、css、js 模塊化,相信這就是未來。
模塊化標準推進速度仍然緩慢
2015 年提出的標準,在 17 年依然沒有得到實現,即便在 nodejs 端。
這幾年 TC39 對語言終于重視起來了,慢慢有動作了,但針對模塊標準制定的速度,與落實都非常緩慢,與 javascript 越來越流行的趨勢逐漸脫節。nodejs 至今也沒有實現 ES2015 模塊化規范,所有 jser 都處在構建工具的陰影下。
Http 2.0 對 js 模塊化的推動
js 模塊化定義的再美好,瀏覽器端的支持粒度永遠是瓶頸,http 2.0 正是考慮到了這個因素,大力支持了 ES 2015 模塊化規范。
幸運的是,模塊化構建將來可能不再需要。隨著 HTTP/2 流行起來,請求和響應可以并行,一次連接允許多個請求,對于前端來說宣告不再需要在開發和上線時再做編譯這個動作。
幾年前,模塊化幾乎是每個流行庫必造的輪子(YUI、Dojo、Angular),大牛們自己爽的同時其實造成了社區的分裂,很難積累。有了 ES2015 Modules 之后,JS 開發者終于可以像 Java 開始者十年前一樣使用一致的方式愉快的互相引用模塊。
不過 ES2015 Modules 也只是解決了開發的問題,由于瀏覽器的特殊性,還是要經過繁瑣打包的過程,等 Import,Export 和 HTTP 2.0 被主流瀏覽器支持,那時候才是徹底的模塊化。
Http 2.0 后就不需要構建工具了嗎?
看到大家基本都提到了 HTTP/2,對這項技術解決前端模塊化及資源打包等工程問題抱有非常大的期待。很多人也認為 HTTP/2 普及后,基本就沒有 Webpack 什么事情了。
不過 Webpack 作者 @sokra 在他的文章 webpack & HTTP/2 里提到了一個新的 Webpack 插件 AggressiveSplittingPlugin。簡單的說,這款插件就是為了充分利用 HTTP/2 的文件緩存能力,將你的業務代碼自動拆分成若干個數十 KB 的小文件。后續若其中任意一個文件發生變化,可以保證其他的小 chunck 不需要重新下載。
可見,即使不斷的有新技術出現,也依然需要配套的工具來將前端工程問題解決方案推向極致。
模塊化是大型項目的銀彈嗎?
只要遵循了最新模塊化規范,就可以使項目具有最好的可維護性嗎? Js 模塊化的目的是支持前端日益上升的復雜度,但絕不是唯一的解決方案。
分析下 JavaScript 為什么沒有模塊化,為什么又需要模塊化:這個 95 年被設計出來的時候,語言的開發者根本沒有想到它會如此的大放異彩,也沒有將它設計成一種模塊化語言。按照文中的說法,99 年也就是 4 年后開始出現了模塊化的需求。如果只有幾行代碼用模塊化是扯,初始的 web 開發業務邏輯都寫在 server 端,js 的作用小之又小。而現在 spa 都出現了,幾乎所有的渲染邏輯都在前端,如果還是沒有模塊化的組織,開發過程會越來越難,維護也是更痛苦。
本文中已經詳細說明了模塊化的發展和優劣,這里不準備做過多的贅述。但還有一個問題需要我們去關注,那就是在模塊化之后還有一個模塊間耦合的問題,如果模塊間耦合度大也會降低代碼的可重用性或者說復用性。所以也出現了降低耦合的觀察者模式或者發布/訂閱模式。這對于提升代碼重用,復用性和避免單點故障等都很重要。說到這里,還想順便提一下最近流行起來的響應式編程(RxJS),響應式編程中有一個很核心的概念就是 observable,也就是 Rx 中的流(stream)。它可以被 subscribe,其實也就是觀察者設計模式。
未來前端復雜度不斷增加已成定論,隨著后端成熟,自然會將焦點轉移到前端領域,而且服務化、用戶體驗越來越重要,前端體驗早不是當初能看就行,任何網頁的異常、視覺的差異,或文案的模糊,都會導致用戶流失,支付中斷。前端對公司營收的影響,漸漸與后端服務宕機同等嚴重,所以前端會越來越重,異常監控,性能檢測,工具鏈,可視化等等都是這幾年大家逐漸重視起來的。
我們早已不能將 javascript 早期玩具性質的模塊化方案用于現代越來越重要的系統中,前端界必然出現同等重量級的模塊化管理方案,感謝 TC39 制定的 ES2015 模塊化規范,我們已經離不開它,哪怕所有人必須使用 babel。
話說回來,標準推進的太慢,我們還是把編譯工具當作常態,抱著哪怕支持了 ES2015 所有特性,babel 依然還有用的心態,將預編譯進行到底。一句話,模塊化仍在路上。js 模塊化的矛頭已經對準了 css 與 html,這兩位元老也該向前衛的 js 學習學習了。
未來 css、html 的模塊化會自立門戶,還是賦予 js 更強的能力,讓兩者的模塊化依附于 js 的能力呢?目前 html 有自立門戶的苗頭(htmlModules),而 css 遲遲沒有改變,社區出現的 styled-component 已經用 js 將 css 模塊化得很好了,最新 css 規范也支持了與 js 的變量通信,難道希望依附于 js 嗎?這里希望得到大家更廣泛的討論。
我也認同,畢竟壓縮、混淆、md5、或者利用 nonce 屬性對 script 標簽加密,都離不開本地構建工具。
據說 http2 的優化中,有個最佳文件大小與數量的比例,那么還是脫離不了構建工具,前端未來會越來越復雜,同時也越來越美好。
至此,對于 javascript 模塊化討論已接近尾聲,對其優缺點也基本達成了一致。前端復雜度不斷提高,促使著模塊化的改進,代理(瀏覽器、node) 的支持程度,與前端特殊性(流量、緩存)可能前端永遠也離不開構建工具,新的標準會讓這些工作做的更好,同時取代、增強部分特征,前端的未來是更加美好的,復雜度也更高。
讀文本大概需要 5 分鐘。
JS 都是大豬蹄子
昨天讀者群有位水友發了這么一條消息,說這樣的網站頁面信息要如何提取 td 的內容,聊天截圖顯現的頁面是在瀏覽器上看到的代碼。
那時候我剛下班,日常水下群。然后看到這條消息,心里就想這個簡單啊,寫個 xpath、寫個 bs4、寫個正則匹配下,輕輕松松就可以獲取到,然而事情并沒有想象中的那么簡單。
隨后水友就提到了關鍵信息:當水友實際用 Python 請求時,返回的內容卻是 JS 代碼。
我明明在瀏覽器上看到的是一個個很有層次的貌美如花的小姐姐 HTML 代碼,怎么用代碼請求就成了晦澀難懂的大豬蹄子 JS 代碼啊?我要小姐姐!
一時間水友不知所措,怎么提取也提取不到自己想要的內容。隨后群里有些水友提出要不用 bs4 試試,或者用正則匹配,各有說辭,聊的不亦悅乎。
身為爬蟲老司機的我,爬過的網站雖然沒有成千,但至少也快上百了,大大小小的坑基本都遇到過。當我接到一個新的爬蟲任務時,首選第一步就是分析下網頁數據請求的流程。很多時候會有很簡單的辦法就可以獲取到網頁的數據。
所以在水友找到我的時候,我首先看下網站長的什么樣子,水友需要的信息是各大區的名稱。
網站地址:
https://xyq.cbg.163.com/
第一眼看到這個網站,心里的印象是這個網站結構不復雜,信息不難提取。但因為有了之前群里消息的鋪墊,我就懂了這個網頁是 JS 代碼渲染出來的。
JS 渲染網頁
JS 渲染網頁是爬蟲里很常見的一種網頁類型,這類的網站有個特點,即如果你不是帶有瀏覽器環境信息進行請求,服務器是不會把正確的數據返回給你。普通的請求只能獲取到大豬蹄子 JS 代碼,晦澀又難懂。
針對這種情況,你想要看到小姐姐真正的盛世美顏,有兩種辦法,1 利用 selenium 自動化框架,2 解析具體的 JS 代碼。
selenium 就像一個彪形大漢,直接模擬一個真實的瀏覽器環境,簡單粗暴的就可以獲取到真實的數據,跟真正的瀏覽器發生請求是一樣的。但這樣的粗暴方式帶來的后果就是效率非常低下。
所以我們可以嘗試第二種方法:通過解析具體的 JS 代碼,出淤泥而不染的輕輕的看到小姐姐的容顏。
隨后我熟練的打開瀏覽器控制臺,查看了下網頁請求的過程,把具體的 JS 請求部分找出來。大致看了下所有的 JS 文件,找到了一個名為 server_list_data.js 文件,這個文件中有個 list_data 字段,非常有可能是存儲了一些數據。所以我點開這個文件進行具體的查看。
果不其然在這個文件中看到了很多 unicode 編碼的內容,隨后我再找了一個編碼轉換網站進行驗證。
這些 unicode 編碼正是網頁上顯示的內容,接下來我們要做的就是用程序請求下這個 JS 鏈接,解析下返回的內容,把 unicode 碼轉換成中文即可。
程序代碼
import requests import re def parse_js(): url = "https://cbg-xyq.res.netease.com/js/server_list_data.js" headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"} html = requests.get(url, headers=headers) patten = re.compile(r"(.*)var server_data =(.*)", re.S) data = re.findall(patten, html.text) server_data = eval(data[0][1][:-1]) for i in server_data: for j in server_data[i]: print(j) if __name__ == '__main__': parse_js()
輸出結果:
多么美妙的小姐姐啊,呸,多么工整的數據啊。
本文首發于頭條號「小白極客」,公眾號后臺回復「1024」即可獲取最新編程資源。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。