pulipulichen / Blogger-Editor

An editor for Blogger writer
MIT License
0 stars 2 forks source link

會出現莫名其妙的span #116

Closed pulipulichen closed 5 years ago

pulipulichen commented 5 years ago

image

<p><a href="//3.bp.blogspot.com/-GLqCKzmZlRk/XNw_3HbwlDI/AAAAAAAEPsA/PXlRPS2OiFs1-uCGo2xp4Y18_zPIYHYdQCK4BGAYYCw/s1600/1-Webpack_2.png">      <img src="//3.bp.blogspot.com/-GLqCKzmZlRk/XNw_3HbwlDI/AAAAAAAEPsA/PXlRPS2OiFs1-uCGo2xp4Y18_zPIYHYdQCK4BGAYYCw/s668/1-Webpack_2.png" title="1-Webpack_2.png" alt="1-Webpack_2.png">    </a></p><p><span>在Webpack中引用其他程式碼的模組解析,可以是來自於獨立的JavaScript檔案,也可以是來自於Node.js中已安裝的模組,可以使用require,也可以使用import。我很好奇到底這兩種引用方式對於最後產生的檔案大小有何影響,在這篇中我以引用獨立檔案或是已安裝的模組、require或是import這四種組合來引用</span><a href="https://www.npmjs.com/package/jquery" target="_blank">jQuery</a><span>跟</span><a href="https://stuk.github.io/jszip/" target="_blank">JSZip</a><span>、</span><a href="https://www.npmjs.com/package/file-saver" target="_blank">FileSaver</a><span>這三個模組,發現引用Node.js已安裝模組的方式產生的檔案較大,引用</span><span>獨立檔案所產生的檔案較小。而import產生的檔案比較大,require比較小。所以專案要選擇用require來引用獨立檔案會比較好嗎?我也不這樣認為。</span></p><p><a name="more"><br></a></p><h2>對於Webpack打包的疑惑 /&nbsp;Question about module import in Webpack&nbsp;</h2><p><a href="//2.bp.blogspot.com/-o-vyXtiZUmI/XNw-U-ugiYI/AAAAAAAEPq0/SvLN_ghQzO8cxvdaLYryjjjJifmAnX8qACK4BGAYYCw/s1600/2019-0514-104954.png">      <img src="//2.bp.blogspot.com/-o-vyXtiZUmI/XNw-U-ugiYI/AAAAAAAEPq0/SvLN_ghQzO8cxvdaLYryjjjJifmAnX8qACK4BGAYYCw/s450/2019-0514-104954.png" title="2019-0514-104954.png" alt="2019-0514-104954.png" width="450" height="249">    </a><span><br></span></p><p><span>我在「</span><a href="http://blog.pulipuli.info/2019/04/blogger-how-do-i-maintain-bloggers.html#postcatablogger-how-do-i-maintain-bloggers.html0_anchor17" target="_blank">閒聊Blogger範本程式碼的管理</a><span>」這篇講述到可以用Webpack將多個檔案打包成一個檔案,已達到節省HTTP請求所額外消耗的頻寬和時間。Wepback引用其他檔案的方式稱之為</span><a href="https://webpack.docschina.org/concepts/module-resolution/" target="_blank">模組解析(module resolution)</a><span>,可以透過import或require兩種方式來引用其他檔案。除了像傳統網頁一樣地引用個別的檔案之外,例如「import './some-module.js'」,在Webpack中也可以引用Node.js的模組,例如「import 'some-module'」,而後者是許多模組說明中推薦的作法。</span></p><h3>引用<span>獨立檔案 / Import from files</span></h3><p><a href="//3.bp.blogspot.com/-OxECpUWdxH0/XNw-U4cRYZI/AAAAAAAEPqk/VBZMF5tJaccR9BbpmGYS-MNKVnwzWy5AACK4BGAYYCw/s1600/2019-0514-105232.png">      <img src="//3.bp.blogspot.com/-OxECpUWdxH0/XNw-U4cRYZI/AAAAAAAEPqk/VBZMF5tJaccR9BbpmGYS-MNKVnwzWy5AACK4BGAYYCw/s450/2019-0514-105232.png" title="2019-0514-105232.png" alt="2019-0514-105232.png" width="450" height="257">    </a></p><p>以「<a href="https://jquery.com/" target="_blank">jQuery</a>」這個前端開發時常用到的模組為例。它提供了已經打包好的單獨檔案,下載位置如下:</p><ul><li><a href="https://code.jquery.com/jquery-3.4.1.min.js" target="_blank">jquery-3.4.1.min.js</a></li></ul><p><span>如果要引用這個檔案,在Webpack中的寫法是:</span></p><pre><code class="javascript">import&nbsp;$&nbsp;from&nbsp;'./jquery-3.4.1.min.js'<br>window.$ = $</code></pre><p><span>第二行加上「window.$ = $」之後,在網頁的其他腳本中才能使用$。</span></p><h3><span>引用模組 / Import from module</span></h3><p><a href="//1.bp.blogspot.com/-dINKkPC_alo/XNw-UgqAq2I/AAAAAAAEPqc/e5LWelRTOEwcz7XijDan3eogbTxL2WBsQCK4BGAYYCw/s1600/2019-0514-105310.png">      <img src="//1.bp.blogspot.com/-dINKkPC_alo/XNw-UgqAq2I/AAAAAAAEPqc/e5LWelRTOEwcz7XijDan3eogbTxL2WBsQCK4BGAYYCw/s450/2019-0514-105310.png" title="2019-0514-105310.png" alt="2019-0514-105310.png" width="450" height="252">    </a></p><p>此外,jQuery也有<a href="https://www.npmjs.com/package/jquery" target="_blank">Node.js的模組</a>。我們可以用npm來下載與安裝這個模組:</p><pre><code class="bash">npm&nbsp;install&nbsp;jquery</code></pre><p>安裝之後,在Webpack裡面要引用jQuery模組的寫法如下:</p><pre><code class="javascript">import&nbsp;$&nbsp;from&nbsp;'jquery'<br>window.$ = $</code></pre><p>兩種引用模組的方式都很簡單,不過這對最後打包的檔案有什麼影響呢?讓我們來做個實驗吧。</p><h2>測試打包檔案大小 / Test the size of bundle files from different import methods</h2><p><a href="//4.bp.blogspot.com/-YOKDUhNkoFI/XNw-U1uu4CI/AAAAAAAEPq4/Ca0i7yU80Q8G_77oOmK-sqYpBLkB8Q3ZgCK4BGAYYCw/s1600/2019-0514-110422.png">      <img src="//4.bp.blogspot.com/-YOKDUhNkoFI/XNw-U1uu4CI/AAAAAAAEPq4/Ca0i7yU80Q8G_77oOmK-sqYpBLkB8Q3ZgCK4BGAYYCw/s450/2019-0514-110422.png" title="2019-0514-110422.png" alt="2019-0514-110422.png" width="450" height="271">    </a></p><p>我開了一個GitHub儲存庫來執行Webpack的測試:</p><ul><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size">https://github.com/pulipulichen/Test-Webpack-package-file-size</a><br></li></ul><h3>Webpack設定檔 / Webpack configuration</h3><p>Webpack打包檔案的設定檔為<a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/webpack.config.js" target="_blank" style="color: rgb(35, 82, 124); outline: 0px; font-weight: 400; background-color: rgb(255, 255, 255);">webpack.config.js</a>。</p><p><span>我在設定檔中加入了</span><a href="https://github.com/babel/babel-loader" target="_blank">babel-loader</a><span>,讓ECMAScript 6的程式碼降級為ECMAScript 5,好讓瀏覽器能夠讀取。又使用</span><a href="https://github.com/webpack-contrib/uglifyjs-webpack-plugin" target="_blank">uglifyjs-webpack-plugin</a><span>來壓縮JavaScript程式碼。</span></p><p><span>最後以生產模式來執行Webpack,指令如下:</span></p><pre><code class="bash">webpack&nbsp;--mode&nbsp;production</code></pre><h3>打包檔案 / Bundle files</h3><p>在設定檔中,我總共會打包4個檔案:</p><ul><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/import-from-file.js" target="_blank">import-from-file.js</a>:以import方法,從獨立檔案引用模組。</li><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/import-from-module.js" target="_blank">import-from-module.js</a>:以import方法,從Node.js安裝模組來引用模組。</li><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/require-from-file.js" target="_blank">require-from-file.js</a>:以require方法,從獨立檔案引用模組。</li><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/require-from-module.js" target="_blank">require-from-module.js</a>:以require方法,從Node.js安裝模組來引用模組。</li></ul><p>這四個檔案都引用三種模組:</p><ul><li><a href="https://jquery.com/" target="_blank">jQuery</a>:<a href="https://code.jquery.com/jquery-3.4.1.min.js" target="_blank">獨立檔案版本</a>、<a href="https://www.npmjs.com/package/jquery" target="_blank">npm版本</a></li><li><a href="https://stuk.github.io/jszip/" target="_blank">JSZip</a>:<a href="https://github.com/Stuk/jszip/blob/master/dist/jszip.min.js" target="_blank">獨立檔案版本</a>、<a href="https://www.npmjs.com/package/jszip" target="_blank">npm版本</a></li><li><a href="https://github.com/eligrey/FileSaver.js#readme" target="_blank">FileSaver</a>:<a href="https://github.com/eligrey/FileSaver.js/blob/master/dist/FileSaver.min.js" target="_blank">獨立檔案版本</a>、<a href="https://www.npmjs.com/package/file-saver" target="_blank">npm版本</a></li></ul><p><a href="//2.bp.blogspot.com/-OTvTxrfJ4O0/XNw-VJTfDGI/AAAAAAAEPrE/zxhWe44g6zkxudT9qUbp5OzzjQqOxk7wgCK4BGAYYCw/s1600/2019-0514-112629.png">      <img src="//2.bp.blogspot.com/-OTvTxrfJ4O0/XNw-VJTfDGI/AAAAAAAEPrE/zxhWe44g6zkxudT9qUbp5OzzjQqOxk7wgCK4BGAYYCw/s450/2019-0514-112629.png" title="2019-0514-112629.png" alt="2019-0514-112629.png" width="450" height="294">    </a></p><p>打包後的檔案經過測試皆能順利使用這三種模組的功能,<a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/tree/master/dist/html" target="_blank">測試網頁的檔案位置也放在GitHub中了</a>。</p><h3>檔案大小 / The size of bundle files</h3><p><a href="//1.bp.blogspot.com/-mHpWcVz9DvY/XNw-UwWDH6I/AAAAAAAEPq8/4y-sKFKFXFUZKDJr4IZYDBwHHwAIRsYoQCK4BGAYYCw/s1600/2019-0514-112949.png">      <img src="//1.bp.blogspot.com/-mHpWcVz9DvY/XNw-UwWDH6I/AAAAAAAEPq8/4y-sKFKFXFUZKDJr4IZYDBwHHwAIRsYoQCK4BGAYYCw/s450/2019-0514-112949.png" title="2019-0514-112949.png" alt="2019-0514-112949.png" width="450" height="174"></a></p><p>最後打包檔案的檔案大小,由多至少排列如下:</p><ul><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/require-from-file.js" target="_blank">require-from-file.js</a>:209KB</li><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/import-from-file.js" target="_blank">import-from-file.js</a>:210KB</li><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/require-from-module.js" target="_blank">require-from-module.js</a>:241KB</li><li><a href="https://github.com/pulipulichen/Test-Webpack-package-file-size/blob/master/src/import-from-module.js" target="_blank">import-from-module.js</a>:241KB</li></ul><p>在這種情況下,可以看到使用require比import所產生的檔案要小一點。而從獨立檔案引用所打包的檔案大小,又比從Node.js已安裝模組還要小得多。這似乎是表示我們應該準備獨立檔案來打包,而不要使用已安裝模組來打包,並且更應該使用require。</p><p>不過真的是這樣嗎?</p><h2>討論 / Discussion</h2><p><span>我個人覺得,這個簡單的測試所得到的答案,很難說是最終解答。以下我們從要不要從Node.js已安裝的模組引用,以及對於require和import的選擇來做個簡單的討論。</span></p><h3>引用來源的選擇 / Difference of import source</h3><p>要引用Node.js已安裝的模組呢?還是下載獨立檔案,然後引用獨立檔案呢?</p><p>從上面的實驗看下來,似乎是引用獨立檔案較能降低最後打包檔案的檔案大小。不過,因為這個實驗只是用簡單的單一檔案來做測試。在會引用大量模組的複雜專案中,又是另外一回事了。</p><p><span>實務上,</span><span>我認為引用獨立檔案的主要缺點在於</span><span>引用路徑的設定。要引用獨立檔案時,我們必須</span><span>指定絕對或相對路徑。大型專案中我們常常可能會在不同程式碼引用相同的模組。但是因為程式碼所在位置不同,如果要引用相同的獨立檔案,那就要特別注意程式碼與獨立檔案之間的相對位置。</span></p><p><span>舉例來說,如果程式碼跟要引用的獨立檔案在相同位置,則引用的寫法如下:</span></p><pre><code class="javascript">import&nbsp;'./some-module.js'</code></pre><p><span>但如果引用的獨立檔案是在其他資料夾中,那引用的寫法就會變得複雜許多,像是:</span></p><pre><code class="javascript">import&nbsp;'../libs/some-module.js'</code></pre><p>相較之下,<span>引用已安裝模組的寫法皆相同,不需要考慮路徑位置:</span></p><pre><code class="javascript">import&nbsp;'some-module'</code></pre><p>從這個角度來看,似乎還是<span style="font-weight: bold; color: rgb(255, 0, 0);">引用Node.js已安裝模組的話,會比較省工一些。</span></p><p>另一點是,有些模組仍然比較適合使用各別檔案來引用。例如<a href="https://www.npmjs.com/package/semantic-ui" target="_blank">semantic-ui有npm</a>的安裝方式,不過實際上使用的時候似乎還是以<a href="https://semantic-ui.com/introduction/getting-started.html#include-in-your-html" target="_blank">個別獨立檔案</a>來引用。另一方面<a href="https://www.npmjs.com/package/summernote" target="_blank">summernote也一樣有npm</a>,但使用的時候仍然是以獨立檔案個別引用。我們可以在HTML裡面用&lt;link&gt;跟&lt;script&gt;來引用,或是在Webpack裡面用import或require來引用,不過這就似乎不能用引用Node.js已安裝模組的寫法來引用,也就是「import 'summernote'」是沒有效果的。</p><p>似乎除此之外,兩者之間就沒有太多決定性的差異。我本來以為<span>Webpack的分塊功能splitChunks只能用在引用模組的時候,不過實際測試結果,對於獨立檔案也能夠順利分塊。關於Webpack分塊的設定與好處,請看</span><span>「</span><a href="https://segmentfault.com/a/1190000016623314" target="_blank" style="font-weight: 400; background-color: rgb(255, 255, 255);">Webpack 4 教程 - 4. 使用SplitChunksPlugin插件进行代码分割</a><span>」</span><span>這篇。</span></p><h3>require還是import / require or import</h3><p>這個實驗中發現了require所打包的檔案大小會比import少,這是可以預期的事情。<span>我在Webpack的設定中使用了babel,它會將import語法轉換為require,又多了一層包裝,這可能是讓程式碼稍微變大的原因之一。</span></p><p>我對Node.js與Webpack的認識還不夠深,常常苦於require跟import之間的差異。實務上,使用require比較靈活,可以用傳統寫網頁的方式來撰寫,而且Webpack打包之後也比較小。import有許多限制,像是只能放在程式碼的最開頭,而且不能搭配邏輯來引用。require跟import在程式的運作上也有些微差異,簡單來說,import是更符合模組化、讓程式與程式之間更能完整隔離的作法。<span>許多模組對於如何引用它們有不同的見解。有些模組在範例上使用require,有些使用import。這可能跟模組開發的早晚時間有關係。</span></p><p><span>而且有時候要引用獨立檔案,特別是會用到jQuery的套件時,不論是使用require還是要用import,都得要稍微調整一下寫法才行。這部分我想另外寫一篇討論吧。</span></p><p>就目前為止,<span><b style="color: rgb(255, 0, 0);">似乎是遵循EMCAScript 6的import較受開發者青睞</b>。雖然require出現得較早,許多早期教學也都以require作為範例,但開發者還是認為未來應該要迎合標準的import,早日捨棄CommonJS中的require。附帶一提,現在最新的版本是2018年6月提出的<a href="https://www.ecma-international.org/ecma-262/9.0/index.html" target="_blank">ECMAScript 2018 (ES2018)</a>,第9版。</span></p><p>關於這些不同的模組引用方式及其原理,可以參考「<a href="https://www.cnblogs.com/libin-1/p/7127481.html" target="_blank">彻底搞清楚javascript中的require、import和export</a>」這篇。</p><h2>結語 / In closing</h2><p>寫到這邊,總覺得我好像做了一次白工的感覺。</p><p>本來以為使用import跟引用Node.js模組會讓最後產生的檔案比較小,結果實際上是require跟引用獨立檔案比較小。不過幾經考量之後,又覺得還是繼續使用import來引用Node.js的已安裝模組比較方便。真是自打嘴巴。</p><p>不過,還有一件更殘酷的事實,請看下圖:</p><p><a href="//3.bp.blogspot.com/-KOFe8dq92H8/XNw_XFfgdGI/AAAAAAAEPro/jZXDfMtM0t89rueZ4y8semJkWw3dsPc7wCK4BGAYYCw/s1600/lib..Properties.png">      <img src="//3.bp.blogspot.com/-KOFe8dq92H8/XNw_XFfgdGI/AAAAAAAEPro/jZXDfMtM0t89rueZ4y8semJkWw3dsPc7wCK4BGAYYCw/s449/lib..Properties.png" title="lib..Properties.png" alt="lib..Properties.png" width="328" height="450">    </a></p><p>如果只看import-from-file.js跟引用的三個獨立檔案,把這四個檔案的檔案大小相加,最後得到的檔案大小為183KB。顯然地又比前面打包的結果還要小。呃,若以最後打包大小來看的話,搞不好直接引用各別的檔案是最好的作法。</p><p>不過在經過上述討論,以及實際體驗過使用Webpack打包之後,就已經不太想回到拆開獨立檔案個別引用的開發方式了。</p><p>那麼這次對於Webpack引用方式如何影響最後打包檔案的大小的討論就到這邊了。你也是Webpack的使用者嗎?你是如何引用模組呢?有什麼特別值得注意的地方,可以跟大家分享嗎?歡迎在下面的留言處跟我們分享你的想法。如果你覺得我這篇寫的不錯的話,請幫我在AddThis分享工具按讚、將這篇分享到Facebook等社群媒體吧!感謝你的耐心閱讀,讓我們下一篇見。</p>
pulipulichen commented 5 years ago

需要在cleancode的時候清理掉

pulipulichen commented 5 years ago

算是已經解決了