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 精品国产成人三级在线观看 ,91精品视频观看,欧美高清国产在线观看

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          C++(Qt) 和 Word、Excel、PDF 交互總結(jié)

          閱讀本文大概需要 6 分鐘

          日常開發(fā)軟件可能會(huì)遇到這類小眾需求,導(dǎo)出數(shù)據(jù)到 WordExcel 以及 PDF文件,如果你使用 C++ 編程語言,那么可以選擇的方案不是很多,恰好最近剛好有這部分需求,整理下這段時(shí)間踩過的坑,方便后人

          讀寫 Word

          日常開發(fā)的軟件使用最多的應(yīng)該是導(dǎo)出數(shù)據(jù)到 Word 文檔中,目前可以用的方案有這幾種

          沒有十全十美的方案,任何方案都存在優(yōu)點(diǎn)和缺點(diǎn),下面來詳細(xì)看下這幾種方案的優(yōu)缺點(diǎn)以及適用場(chǎng)景

          XML 模板替換

          原理:事先編輯好一份 Word 模板,需要替換內(nèi)容的 地方預(yù)留好位置,然后使用特殊字段進(jìn)行標(biāo)記,后面使用代碼進(jìn)行全量替換即可完成

          優(yōu)點(diǎn)

          • 代碼量相對(duì)較少、導(dǎo)出速度快
          • 跨平臺(tái),支持多個(gè)系統(tǒng),系統(tǒng)不安裝 office 也能導(dǎo)出;
          • 支持圖片以及固定格式導(dǎo)出;

          缺點(diǎn)

          • 導(dǎo)出格式固定,可擴(kuò)展性不強(qiáng),如果需求變化導(dǎo)出格式變了,那么模板也要跟著改變;
          • 一種格式對(duì)應(yīng)一份模板,如果導(dǎo)出格式較多,需要準(zhǔn)備的模板文件較多,這樣比較繁瑣;
          • 需要 Word 2003 以上版本;

          舉個(gè)栗子

          我們先編輯一份 Word 模板文檔,內(nèi)容大概如下所示:

          • 將該文檔另存為 Word XML 文檔 XML-Template.xml
          • 讀取文檔內(nèi)容進(jìn)行變量替換
              QFile file("XML-Template.xml");
              if (!file.open(QIODevice::ReadOnly))
              {
                  qDebug() << "open xxml file fail. " << file.errorString();
                  return 0;
              }
              QByteArray baContent = file.readAll();
              file.close();
              QString strAllContent = QString::fromLocal8Bit(baContent);
          
              strAllContent.replace("$VALUE0", "1");
              strAllContent.replace("$VALUE1", QString::fromLocal8Bit("法外狂徒張三"));
              strAllContent.replace("$VALUE2", QString::fromLocal8Bit("考試不合格"));
              strAllContent.replace("$VALUE3", "2");
              strAllContent.replace("$VALUE4", QString::fromLocal8Bit("李四"));
              strAllContent.replace("$VALUE5", QString::fromLocal8Bit("合格"));
          
              QFile newFile("export.doc");
              if (!newFile.open(QIODevice::WriteOnly))
              {
                  qDebug() << "file open fail." << newFile.errorString();;
                  return 0;
              }
          
              newFile.write(strAllContent.toLocal8Bit());
              newFile.close();
          
          • 保存替換后的內(nèi)容,寫入文件

          可以看出來這種方式比較繁瑣,重點(diǎn)是編輯固定的模板格式,而且編輯好后保存成XML格式后還需要繼續(xù)調(diào)整,這種 XML 格式標(biāo)簽很多,不小心就修改錯(cuò)了,導(dǎo)致導(dǎo)出的文檔打不開

          這種方式適合模板內(nèi)容不太復(fù)雜,內(nèi)容較少的情況下使用

          COM 組件方式

          原理:采用 Micro Soft公開的接口進(jìn)行通訊,進(jìn)行讀寫時(shí)會(huì)打開一個(gè) `Word進(jìn)程來交互

          COM 技術(shù)概述

          Qt 為我們提供了專門進(jìn)行交互的類和接口,使用 Qt ActiveX框架就可以很好的完成交互工作

          優(yōu)點(diǎn)

          • 實(shí)現(xiàn)簡(jiǎn)單,快速上手;

          缺點(diǎn)

          • 導(dǎo)出寫入速度慢,因?yàn)橄喈?dāng)于打開 word 文檔操作;
          • Windows平臺(tái)可用,其它平臺(tái)失效;
          • 需要程序運(yùn)行的電腦安裝 office word,否則調(diào)用失敗

          舉個(gè)栗子

          使用時(shí)需要引入對(duì)應(yīng)的模塊,在 pro 文件引入模塊

          QT  *= axcontainer
          

          打開文檔寫入內(nèi)容

          QAxObject *pWordWidget = new(std::nothrow) QAxObject;
          
          bool bResult = pWordWidget->setControl("word.Application");
          
          if (!bResult)
          {
              return false;
          }
          
          // 設(shè)置是否顯示
          pWordWidget->setProperty("Visible", false);
          
          QAxObject *pAllDocuments = pWordWidget->querySubObject("Documents");
          
          if(nullptr == pAllDocuments)
          {
              return false;
          }
          
          // 新建一個(gè)空白文檔
          pAllDocuments->dynamicCall("Add (void)");
          
          // 獲取激活的文檔并使用
          QAxObject *pActiveDocument = pAllDocuments->querySubObject("ActiveDocument");
          if(nullptr == pActiveDocument)
          {
              return false;
          }
          
          // 插入字符串
          QAxObject *pSelectObj = pWordWidget->querySubObject("Selection");
          if (nullptr != pSelectObj)
          {
              pSelectObj->dynamicCall("TypeText(const QString&)", "公眾號(hào):devstone");
          }
          
          ……
          

          可以看出來使用起來不難,對(duì)于新手友好一點(diǎn),很多寫入操作方法比較繁瑣,需要自己重新封裝一套接口

          • 這種方案比較適合那些排版比較復(fù)雜,圖片、文字、表格混排的場(chǎng)景下,而且內(nèi)容都是動(dòng)態(tài)變化的,可以很好的實(shí)現(xiàn)定制化
          • 當(dāng)然了它的缺點(diǎn)也不少,也有一些坑,有時(shí)候莫名其妙會(huì)失敗,還有就是比如你電腦安裝的 Word 沒有激活,那么每次啟動(dòng)會(huì)彈激活窗口
          • 還有就是這種方式要求所有的路徑必須是本地化的,比如 D:\Soft\test.png
          • 使用前最好讀取注冊(cè)表判斷當(dāng)前電腦是否安裝了 Office Word,如果沒有安裝,直接讀取操作肯定會(huì)崩潰

          這種方式同樣適用于寫入 Excel 文件,后面再說

          HTML 方式

          原理:這種方式得益于 Word支持 HTML格式導(dǎo)出渲染顯示,那么反向也可以支持,需要我們拼接 HTML格式內(nèi)容,然后寫入文件保存成 .doc格式

          優(yōu)點(diǎn)

          • 跨平臺(tái),不僅限于 Windows平臺(tái),代碼可擴(kuò)展性比較好
          • 導(dǎo)出速度快、代碼可擴(kuò)展;

          缺點(diǎn)

          • 字符串拼接 HTML 容易出錯(cuò),缺失標(biāo)簽導(dǎo)出后無法顯示;
          • 插入的圖片是本地圖片文件的鏈接,導(dǎo)出的 word文檔拷貝到其它電腦圖片無法顯示

          舉個(gè)栗子

          QString HTML2Word::getHtmlContent()
          {
              QString strHtml = "";
              strHtml += "<html>";
              strHtml += "<head>";
              strHtml += "<title>測(cè)試生成word文檔</title>";
              strHtml += "<head>";
              strHtml += "<body style=\"bgcolor:yellow\">";
              strHtml += "<h1 style=\"background-color:red\">測(cè)試qt實(shí)現(xiàn)生成word文檔</h1>";
              strHtml += "<hr>";
              strHtml += "<p>這里是插入圖片<img src=\"D:\\title.jpg" alt=\"picture\" width=\"100\" height=\"100\"></p>";
              strHtml += "</hr>";
              strHtml += "</body>";
              strHtml += "</html>";
          
              return strHtml;
          }
          
          // 保存寫入文件
          QFile file("D:/htmp2Word.doc");
          if (!file.open(QIODevice::WriteOnly))
          {
              return false;
          }
          
          QTextStream out(&file);
          out << getHtmlContent();
          file.close();
          
          

          這種方式難點(diǎn)在于 HTML格式拼接,任何缺失字段都會(huì)導(dǎo)致導(dǎo)出失敗,適合小眾需求下導(dǎo)出

          圖片問題其實(shí)可以手動(dòng)進(jìn)行轉(zhuǎn)化,文檔導(dǎo)出成功后手動(dòng)拷貝內(nèi)容到新的文檔,這樣圖片就真正插入到文檔中,文檔發(fā)送給別人也不會(huì)丟失圖片了

          還有一個(gè)坑就是:如果你使用 WPS 打開導(dǎo)出的文檔,默認(rèn)顯示的是 web視圖,需要手動(dòng)進(jìn)行調(diào)整

          某些電腦分辨率變化也會(huì)導(dǎo)致生成的文檔中字體等產(chǎn)生變化

          第三方開源庫

          可以使用的第三方庫幾乎沒有,網(wǎng)絡(luò)上找到的有這么幾個(gè)

          • OpenOffice: 兼容性差,集成調(diào)用難度大
          • LibOffice: 太龐大,不容易集成
          • DuckX: 太小眾,只能簡(jiǎn)單的使用
          • docx:小眾庫

          DuckX庫 docx庫

          在讀寫 Word這部分,C++ 基本沒有可以使用的第三方庫,不像其他語言JavaC#Python有很多可以選擇,這個(gè)痛苦也只有 C++ 程序員能夠理解了吧

          所以怎么選擇還是看自己項(xiàng)目需求吧,沒有十全十美的方案


          上面說了這么多,都是導(dǎo)出生成 Wrod,那么下面來看看有那些方式可以讀取顯示 Word內(nèi)容

          這種需求應(yīng)該不會(huì)很多,而且顯示難度更大一些

          使用 COM組件方式,即采用 QAxWidget框架顯示 office 文檔內(nèi)容,本質(zhì)上就是在我們編寫的 Qt 界面上嵌入 office 的軟件,這種方式其實(shí)和直接打開 Word查看沒有啥區(qū)別,效果、性能上不如直接打開更好一些

          目前一般都會(huì)采用折中方案,把 Word 轉(zhuǎn)為 PDF 進(jìn)行預(yù)覽加載顯示,我們知道 PDF 渲染庫比較多,生態(tài)相對(duì)來說要好一些,在選擇上就更廣泛些,如何使用后面部分有專門介紹 PDF章節(jié)

          讀寫 Excel

          目前有一個(gè)支持比較好的第三方庫可以使用,整體使用基本可以滿足日常使用

          QXlsx

          這款開源庫支持跨平臺(tái),Linux、Windows、Mac、IOS、Android,使用方式支持動(dòng)態(tài)庫調(diào)用和源碼直接集成,非常方便

          編譯支持 qmakecmake,可以根據(jù)你自己的項(xiàng)目直接集成編譯,讀寫速度非常快

          QXlsx::Document xlsx;
          
          // 設(shè)置一些樣式
          QXlsx::Format titleFormat;
          titleFormat.setBorderStyle(QXlsx::Format::BorderThin);  // 邊框樣式
          titleFormat.setRowHeight(1,1,30);   // 設(shè)置行高
          titleFormat.setHorizontalAlignment(QXlsx::Format::AlignHCenter);   // 設(shè)置對(duì)齊方式
          
          // 插入文本
          xlsx.write(1,1, "微信公眾號(hào):devstone", titleFormat);
          
          // 合并單元格
          xlsx.mergeCells(QXlsx::CellRange(2,1,4,4), titleFormat);
          
          // 導(dǎo)出保存
          xlsx.saveAs("D:/xlsx_export.xlsx");
          
          // 添加工作表
          xlsx.addSheet("devstone");
          

          可以看到上手非常容易、各個(gè)函數(shù)命名也貼近 Qt Api,是一款非常良心的開源軟件

          PS:注意該軟件使用 MIT 許可協(xié)議,這樣對(duì)于很多個(gè)人或者公司來說非常良心,意味著你可以無償使用、修改該項(xiàng)目,但是必須在你項(xiàng)目中也添加同樣的 MIP許可

          上面也提到了,還可以使用 COM 組件的方式讀寫 Excel,不過有了這款開源庫基本就可以告別 COM組件方式了

          讀寫 PDF

          PDF相關(guān)開源庫挺多的,給了 C++ 程序員莫大的幫助,目前可用的主要有這些

          其中 mupdfpoppler 屬于功能強(qiáng)大但是很難編譯的那種,需要有扎實(shí)的三方庫編譯能力,否則面對(duì) n 個(gè)依賴庫會(huì)無從下手

          不過可喜的是 Github 上有兩個(gè)開源庫可以供選擇

          qpdf 庫

          這個(gè)庫其實(shí)封裝了 pdf.js庫,使用 WebEngine來執(zhí)行 JavaScript進(jìn)而加載文件

          項(xiàng)目地址

          • 直接從本地文件加載;
          • 支持從內(nèi)存數(shù)據(jù)直接加載渲染 PDF 內(nèi)容;

          這種方式對(duì)環(huán)境有特殊要求了,如果你的項(xiàng)目使用的 Qt 版本不支持 WebEngine,那么就無法使用

          qtpdf 庫

          這個(gè)庫是 Qt 官方親自操刀對(duì)第三方庫進(jìn)行了封裝,暴露的 APIQt 類似,使用起來非常舒服

          Qt 官方

          代碼結(jié)構(gòu)以及使用 Demo

          小試牛刀

          關(guān)于如何使用,官方已經(jīng)給了我們非常詳細(xì)的步驟了,直接跟著下面幾步就 OK 了

          官方教程

          git clone git://code.qt.io/qt-labs/qtpdf
          cd qtpdf
          git submodule update --init --recursive
          qmake
          make
          cd examples/pdf/pdfviewer
          qmake
          make
          
          ./pdfviewer /path/to/my/file.pdf
          

          可以看到使用了谷歌開源的 pdfium 三方庫,編譯時(shí)需要單獨(dú)更新下載這個(gè)庫,因?yàn)槟承┰蚩赡苣銦o法下載,不過好在有人在 GitHub上同步了這個(gè)倉庫的鏡像,有條件還是建議直接下載最新穩(wěn)定版的

          可正常訪問的倉庫地址:https://github.com/PDFium/PDFium

          相關(guān)類可以看這個(gè)文檔:https://developers.foxit.com/resources/pdf-sdk/c_api_reference_pdfium/modules.html

          最后還要注意項(xiàng)目開源協(xié)議:pdfium引擎開始來自于福昕,一個(gè)中國本土的軟件公司,Google與其合作最終進(jìn)行了開源,目前采用的是 BSD 3-Clause 協(xié)議,這種協(xié)議允許開發(fā)者自由使用、修改源代碼,也可以修改后重新發(fā)布,允許閉源進(jìn)行商業(yè)行為,不過需要你在發(fā)布的產(chǎn)品中包含原作者代碼中的 BSD 協(xié)議

          總結(jié)

          以上就是項(xiàng)目中常用的文檔處理方法總結(jié),當(dāng)然了肯定也還有其它方案可以實(shí)現(xiàn),畢竟條條大路通羅馬,如果你還要不錯(cuò)的方案和建議歡迎留言

          PS: 以上方案和對(duì)應(yīng)的源碼編譯、使用例子會(huì)統(tǒng)一上傳到 GitHub對(duì)應(yīng)的倉庫,方便后人使用

          取之互聯(lián)網(wǎng)、回報(bào)互聯(lián)網(wǎng)

          原創(chuàng)不易,如果覺得對(duì)你有幫助,歡迎點(diǎn)贊、在看、轉(zhuǎn)發(fā)

          推薦閱讀

          • Qt Creator 源碼學(xué)習(xí)筆記01,初識(shí)QTC
          • Qt Creator 源碼學(xué)習(xí)筆記02,認(rèn)識(shí)框架結(jié)構(gòu)結(jié)構(gòu)
          • Qt Creator 源碼學(xué)習(xí)筆記03,大型項(xiàng)目如何管理工程
          • Qt Creator 源碼學(xué)習(xí)筆記04,多插件實(shí)現(xiàn)原理分析
          • Qt Creator 源碼學(xué)習(xí)筆記 05,菜單欄是怎么實(shí)現(xiàn)插件化的?

          于有人站出來,打算跟 JavaScript 生態(tài)系統(tǒng)正面交鋒了。這家伙知道自己在干什么,而且也描繪出了干掉 JS 之后要?jiǎng)?chuàng)造的美好新世界。


          2022 年,前 Stripe 開發(fā)人員 Jared Sumner 發(fā)布了Bun,一種用 Zig 編程語言開發(fā)的運(yùn)行時(shí)。據(jù)我所知,Bun 最初只是種 JavaScript webserver,但在后續(xù)發(fā)展中逐漸醞釀出了全面顛覆 JS 生態(tài)系統(tǒng)的野心。


          按我個(gè)人的關(guān)注度排序,Bun 的優(yōu)勢(shì)主要有以下幾點(diǎn):


          • 據(jù)說能提供比 Node 或 Deno 更快的 JavaScript/TypeScript 運(yùn)行時(shí)
          • 包管理器比 NPM 或 Yarn 都快上億倍
          • Browser Bundler——全面支持 tsx、jsx、css、svg 等格式,能替代從 webpack 到 react-scripts 的所有內(nèi)容,而且速度仍然快如閃電
          • 提供速度極快的 webserver(替代 Express)
          • Sqlite 客戶端
          • Bread


          Bun 改朝換代的思路看著非常簡(jiǎn)單粗暴——JS 有的我也要有,而且我的要更簡(jiǎn)單、更高效。這里沒有小聰明、沒有曲線救國,要的就是正面對(duì)抗而且樣樣比 JS 強(qiáng)。用一種低級(jí)語言,編寫出運(yùn)行極快的代碼,這就是 Bun。


          Bun 還很年輕,也許還沒準(zhǔn)備好迎接那些令人頭大的真實(shí)生產(chǎn)用例。但它確實(shí)發(fā)展迅速,所以如果 Bun 真能在幾年后快速占據(jù)市場(chǎng)份額,我也覺得完全在情理之中。

          之前的方案到底有什么問題?

          不知道大家在實(shí)際工作中有沒有編寫過 JS 或 TS 生產(chǎn)代碼,那種體驗(yàn)挺難受的。多數(shù)情況下,開源工具和小項(xiàng)目也能良好運(yùn)轉(zhuǎn),但一到商業(yè)和企業(yè)級(jí)用例上就經(jīng)常掉鏈子。而因?yàn)閭鹘y(tǒng)、常規(guī)的路線走不通,企業(yè)只能試遍各種辦法讓項(xiàng)目能在生產(chǎn)環(huán)境中正常起效。


          例如,TypeScript 在涉及多位開發(fā)者的項(xiàng)目中解決了不少老大難問題,所以只要 JS 的路子走不通,我們就能隨時(shí)引入 TS 進(jìn)行代碼轉(zhuǎn)換。這里要真心感謝微軟。NPM 對(duì)大型項(xiàng)目和單體 repo 來說速度太慢,所以公司可能需要轉(zhuǎn)向 Yarn。這里又要謝謝 Facebook。總之,我們就是在拼了命地東拼西湊,最終搞出性能勉強(qiáng)說得過去的成果。


          作者提到自己所在企業(yè)的整個(gè)單體 repo 執(zhí)行 eslint 需要耗費(fèi) 79 秒,所以只能單獨(dú)配置,保證只對(duì)發(fā)生變更的文件執(zhí)行 lint。雖然會(huì)引入更多復(fù)雜元素,但也沒有辦法。


          總的來說,無數(shù)開發(fā)者都在用自己的辦法加速 JS 工具鏈中的某些特定部分。比如用 Yarn 3 那瘋狂的“即插即用”節(jié)點(diǎn)模塊虛擬化速度來替代 NPM,或者用基于 JSON Schema 的請(qǐng)求解析器解決 Express 的低速問題。其實(shí)大多數(shù)原有工具都有類似的問題,而且它們是由 JS 開發(fā)者編寫、專為 JS 開發(fā)者服務(wù)的。用 JS 編寫,就等同于速度很慢……


          于是,一些用更快語言編寫的高速工具開始流行起來。每家擁有大型 React 應(yīng)用程序的企業(yè),肯定都經(jīng)歷過 WebPack 構(gòu)建要花掉整整一分鐘的折磨。為此,他們必須轉(zhuǎn)向用 Go 語言編寫 esbuild。同樣的,其他語言版本的 eslint 替代方案也開始出現(xiàn),比如用 Rust 重寫 Rome。


          Bun 是這種趨勢(shì)的自然延續(xù),但采取的卻是自下而上的推進(jìn)路徑。這個(gè)項(xiàng)目的核心思路就是從零起步、以內(nèi)置“batteries”的方式,用低級(jí)語言重寫整個(gè) JavaScript 生態(tài)系統(tǒng)。而且到目前為止,效果還真心不錯(cuò)。


          Bun 現(xiàn)在可以做些什么?

          讓解釋器快起來

          如果 Bun 只是對(duì)所有 JS 輔助工具進(jìn)行重寫,我當(dāng)然也很歡迎,但那樣的它只能算是 Node.js 的又一個(gè)替代品。Bun 并沒有這樣偷懶,它努力讓解釋器本身也快起來。


          Bun 是用 Zig 編寫的,而且配合蘋果開發(fā)的 JavaScriptCore,類似于 Node 使用 v8。Zig 是一種新興的低級(jí)語言,主要活躍在 C++占主導(dǎo)地位的場(chǎng)景。我不是低級(jí)開發(fā)者,所以沒親自用過,更多細(xì)節(jié)就留給其他技術(shù)更強(qiáng)的博主吧。在本文中,大家只要知道 Zig 寫的代碼很快就行了。至于 JavaScriptCore,它的作用跟 v8 一樣,只是 v8 來自谷歌、而它來自蘋果。Safari 和蘋果的很多其他項(xiàng)目都有用到 JavaScriptCore。


          Bun 比 Node 到底快多少還沒有定論,但據(jù)稱在某些特定場(chǎng)景下要快得多。很多朋友可能沒經(jīng)歷過 io.js 剛誕生的時(shí)代,總結(jié)來說,那時(shí)候一個(gè)單純能提高解釋器速度的分叉就足以撼動(dòng)整個(gè) JS 生態(tài)系統(tǒng)。而 Bun 的啟動(dòng)速度又比 Node 快得多。我自己的親身實(shí)驗(yàn)是 7 毫秒左右,大概比 Node.js 快了 10 倍,所以特別適合無服務(wù)器環(huán)境和邊緣計(jì)算場(chǎng)景。


          這一波顛覆依靠的不只是速度優(yōu)勢(shì),Bun 還添加了不少優(yōu)秀的標(biāo)準(zhǔn)庫函數(shù)。例如,Bun.write()就是用于編寫文件的新函數(shù),它會(huì)返回一個(gè)承諾,而且號(hào)稱可以通過更適合的系統(tǒng)調(diào)用進(jìn)一步加快速度。


          說起 Node API,Bun 目前已經(jīng)能支持約 90%的現(xiàn)有 Node API。Node 規(guī)模很大,其中總有一些別說沒用過、可能大家聽都沒聽過的東西(比如 new AsyncLocalStorage() ),所以能支持 90%已經(jīng)很好了。誰會(huì)運(yùn)行 NPM 上的所有包呢?根本不需要,而且基本不影響我們的日常開發(fā)。


          順便說一句,TypeScript 在 Bun 這邊可是相當(dāng)有排面,直接調(diào)用 bun my-ts-file.ts 就行。Deno 對(duì) TS 的支持也就這個(gè)水平了。使用 Bun 對(duì)新項(xiàng)目進(jìn)行模板化,或者把 bun-types 添加到 tsconfig 當(dāng)中,IDE 中的自動(dòng)補(bǔ)全功能就將適用于這些新函數(shù)!


          Bun 項(xiàng)目最初目標(biāo)之一就是創(chuàng)建一種更快、更強(qiáng)大的 TypeScript 編譯器。這個(gè)目標(biāo)現(xiàn)在已經(jīng)實(shí)現(xiàn),同時(shí)被淹沒在其他眾多功能中。但目前,它仍然無法支持某些比較高級(jí)的 TypeScript 配置和功能,例如裝飾器、tsconfig 中將多個(gè)配置合并起來的擴(kuò)展功能等。

          替代 NPM

          下面來聊 Bun 最振奮人心的能力之一——替代 NPM。它真的很快,能讓人人都滿意那種快。


          在 Linux 上,bun install 的包安裝速度可以達(dá)到 npm install 的 20 倍到 100 倍。在 macOS 上,也能達(dá)到 4 倍到 80 倍。


          我敢肯定,沒 cache 快,有 cache 更快,總之就是快。


          之前就已經(jīng)有很多方案在努力幫 NPM 提速了。比如大家熟悉的 Yarn Plug-n-Play,它的思路就是徹底放棄 node_modules 文件夾來加快包安裝速度。雖然有一定效果,但在實(shí)際使用中,提速并沒有那么顯著,而且還需要處理大量 polyfill 和 escape-hatches 操作。能用是能用,但我個(gè)人實(shí)在是不想再用、也不打算向大家推薦。


          Pnpm 是另一種新興的 NPM 替代方案,在繼續(xù)使用 TypeScript 編寫的同時(shí)實(shí)現(xiàn)了一部分智能優(yōu)化。在 pnpm 中,node_modules 是通過符號(hào)鏈接從全局緩存中訪問的,每個(gè)包都能在自己的獨(dú)立時(shí)間內(nèi)完成安裝,無需等待其他包完成當(dāng)前操作。


          Bun 的基本思路跟 NPM 一樣,但速度卻更快。它有自己的 lockfile 格式,而且其中的 node_modules 和 package.json 看起來沒什么變化。如果大家對(duì)文件系統(tǒng)調(diào)用比較熟悉,可以結(jié)合低級(jí)訪問和快速語言實(shí)現(xiàn)極快的安裝效果,而且無需任何花哨的技巧。


          現(xiàn)在,Bun 還不提供工作空間支持,所以暫時(shí)沒法對(duì)接那些期待它來拯救的大型單體 repo(我們的項(xiàng)目也屬于這類)。但好在 Bun 正保持著迅猛的發(fā)展速度,幾周前剛公布的路線圖也提到了工作空間支持。


          請(qǐng)注意,大家不用全面轉(zhuǎn)向 Bun 也能把它當(dāng)成包管理器、轉(zhuǎn)譯器或者解釋器。只需要選擇我們需要的部分,丟棄其余的部分就行。我猜 Bun 的初步普及可能也會(huì)走這條道路,就是先當(dāng)個(gè)好用的包管理器,其他的以后再說。這樣接受門檻會(huì)變得更低一些。


          內(nèi)含轉(zhuǎn)譯器,矛頭指向 webpack、esbuild

          Bun 當(dāng)中包含一個(gè)用于網(wǎng)絡(luò)瀏覽器的轉(zhuǎn)譯器,這明顯是把矛頭指向了 webpack 和 esbuild。順帶一提,Bun 中的解析器就是 esbuild 解析器的一個(gè) Zig 端口,輕松愉快。

          Bun 已經(jīng)支持多種文件類型,css、svg、tsx、jsx、ts 之類的都行。JS 中的 CSS 等高級(jí)選項(xiàng)似乎也能在 Bun 上正常工作。


          由于 Bun 包含一個(gè)帶有幾套內(nèi)置模板的項(xiàng)目腳手架,所以這里我們可以直接調(diào)用:

          bun create react my-app


          之后,我運(yùn)行 bun dev 并在瀏覽器里運(yùn)行了一個(gè) react 應(yīng)用程序。我猜可以把 react-scripts 直接添加到 Bun 替換過的工具列表當(dāng)中。


          把文件擴(kuò)展名從 jsx 改成 tsx,程序就立刻生效了。導(dǎo)入 svg,沒有問題。開發(fā)模式似乎還支持 HMR,也就是前端開發(fā)者在使用 webpack 時(shí)的一大必備工具。


          那么,轉(zhuǎn)譯器方面還缺什么嗎?缺的還多,畢竟生產(chǎn)環(huán)境的要求可不簡(jiǎn)單。首先就是最小化了,這是實(shí)際用戶最希望在后續(xù)發(fā)展路線圖上看到的功能。對(duì)于大型插件生態(tài)系統(tǒng)來說,還必須要有能夠支持不同文件格式的打包工具。例如,目前.vue 文件和.scss 還沒有實(shí)際落地,特別是.scss,這東西幾代開發(fā)者都在用,必須趕緊實(shí)現(xiàn)。目前我還不確定 Bun 捆綁器的可插拔性怎么樣,而且最重點(diǎn)的是要直接在框架之內(nèi)解決問題,不要依賴大量外部開源包。


          其他功能——Web server 與 sqlite 客戶端

          Bun 還把不少傳統(tǒng)意義上的框架元素添加到了標(biāo)準(zhǔn)庫當(dāng)中。就個(gè)人而言,我對(duì)那些庫類型功能不太感興趣,畢竟 Node 中已經(jīng)有很多適用于 http server 的功能長(zhǎng)城了。


          Bun 的 webserver 看起來非常簡(jiǎn)單。Express 雖然有點(diǎn)落后于時(shí)代,但對(duì)大多數(shù)開發(fā)者來說仍然夠用(開發(fā)團(tuán)隊(duì)今年還剛剛提供了對(duì)承諾的支持)。Bun server 好像跟 Cloudflare Worker 頗為相信。只要 JavaScript 生態(tài)中的其他問題逐一得到解決,也許 Bun 的開發(fā)團(tuán)隊(duì)會(huì)轉(zhuǎn)回頭好好打磨一下 webserver 吧。需要注意的是,在某些情況下,巧用系統(tǒng)調(diào)用可以讓 Bun webserver 的速度提高一倍,特別是在文件處理過程中。


          至于新的 SQLite 適配器,我覺得之前 Node 中的 sqlite 實(shí)現(xiàn)思路有點(diǎn)脫離正常人的腦洞。現(xiàn)在大多數(shù)開發(fā)者會(huì)把舊有 sqlite 3 包跟 sqlite 打包器結(jié)合使用,借此實(shí)現(xiàn)對(duì)承諾的支持。Bun 的解決方案看起來更簡(jiǎn)潔,所以就算速度上沒啥大優(yōu)勢(shì),我也愿意用。

          酒香也怕巷子深

          我最擔(dān)心的是,Bun 的這么多優(yōu)點(diǎn)難以轉(zhuǎn)化成對(duì)社區(qū)成員的實(shí)際吸引力。Bun 本身就是 JS 生態(tài)系統(tǒng)的完整替代品,這么巨大的轉(zhuǎn)變一般人恐怕很難快速接受。


          Bun 還很年輕,目前沒有完整的說明文檔。對(duì)于大多數(shù)問題,我們只能查閱長(zhǎng)長(zhǎng)的自述文件。但創(chuàng)建一個(gè) docusaurus 站點(diǎn),再配合具備完整內(nèi)聯(lián)注釋的 TypeScript 類型生成相應(yīng)的 typedoc 并不困難,所以我猜這一點(diǎn)應(yīng)該很快就能解決。

          其他產(chǎn)品對(duì)比


          服務(wù)端渲染 React 每秒 HTTP 請(qǐng)求數(shù) (Linux AMD64) 對(duì)比,來自 Bun 官網(wǎng)

          Deno

          如果你從來沒聽說過 Deno、也不打算了解,直接跳過這章也行。而且就個(gè)人而言,我覺得 Bun 比 Deno 更有搞頭、更有前途。


          來自 Node 締造者的 Deno 宣稱解決了一些長(zhǎng)期困擾開發(fā)者的老大難問題。它把 es-modules 設(shè)定成默認(rèn)值,引入了第一方 TypeScript 支持(無需在發(fā)布前轉(zhuǎn)譯 NPM 模塊)等等。但在我看來,Deno 在解決老問題的同時(shí),也引入了不少新問題。


          首先,Deno 對(duì)包解析和語法做的變更過于大刀闊斧,導(dǎo)致沒法跟原有 NPM 生態(tài)系統(tǒng)兼容。換言之,Deno 需要培養(yǎng)起自己的全新庫生態(tài)。雖然 Deno 慢慢開始支持一些早期庫,但我覺得一個(gè)項(xiàng)目的影響力會(huì)直接決定它的發(fā)展上限,所以 Deno 的邊界估計(jì)也就到這了。當(dāng)然也有一些變通方法,比如把 NPM 包轉(zhuǎn)換成 Deno 包的 CDN,但我覺得這不是什么好招。


          Deno 還有不少在我看來暴露其半成品身份的問題,比如缺少 package.json。無論是從模塊解析的角度來看,還是從缺少 manifest 文件出發(fā),Deno 都不允許開發(fā)者為自己的包編寫可擴(kuò)展元數(shù)據(jù)。GoLang 甚至專門為此引入了 go.mod。


          另外,我覺得 Deno 設(shè)計(jì)中的沙箱/權(quán)限系統(tǒng)應(yīng)該是正確的思路,只是粒度不夠細(xì)。它位于整個(gè)項(xiàng)目的頂層、脫離了包層次,這意味著大型應(yīng)用程序最終還是需要所有權(quán)限,于是問題又回到了原點(diǎn)。而且作為一家安全公司,我們對(duì) Deno 無法保護(hù)大型應(yīng)用免受供應(yīng)鏈攻擊而頗感失望。當(dāng)然,Bun 也沒說打算如何解決這個(gè)問題,我這里只是發(fā)泄一下自己的不滿。


          所以總結(jié)起來:Bun 擁有遠(yuǎn)超 Deno 的發(fā)展?jié)摿Α?span style="color: #1C1E21; --tt-darkmode-color: #A0A3A8;">具體原因如下:


          • 它支持現(xiàn)有 NPM 生態(tài)系統(tǒng)中的所有庫,也支持大家已經(jīng)編寫的一切代碼,甚至連 package.json 都不用改。
          • 它解決了生態(tài)系統(tǒng)中的幾個(gè)突出問題(特別是大企業(yè)的訴求問題),而且把解決方案整合到了單一框架當(dāng)中。
          • 它以人們已經(jīng)熟悉的方式運(yùn)行,只是速度更快。不需要改變范式,也不強(qiáng)求轉(zhuǎn)變思路,用就是了。
          • 可以放心使用,哪怕感覺 Bun 拖慢了開發(fā)速度,我們也可以只用它的包管理器;或者說覺得 webpack 太慢,那就只用它的打包程序。
          • 它在幾乎各個(gè)維度上都更快,這是種巨大的優(yōu)勢(shì)。從 io.js 就能看到,人們是愿意為了性能而轉(zhuǎn)投陣營(yíng)的。

          Rome?

          如上所述,Rome 就是個(gè)驗(yàn)證器。Rome 的維護(hù)者們已經(jīng)開始用 Rust 代替 JS 進(jìn)行重寫了,而且 79 秒的驗(yàn)證時(shí)長(zhǎng)也有點(diǎn)夸張。(不騙人,我們的 eslint 就是用了 79 秒。)


          從路線圖來看,Rome 還打算引入捆綁器、文檔生成器、壓縮器、類型檢查器、測(cè)試框架等等。但這一切尚未完成,而 Bun 明顯已經(jīng)走得更遠(yuǎn)。至少 Rome 還沒開始重寫 Node 核心本身,所以我覺得它的影響力也就差不多這樣了。


          總之,很多項(xiàng)目都發(fā)現(xiàn)了 Node 生態(tài)系統(tǒng)中的現(xiàn)有問題,而且各自嘗試在統(tǒng)一的高性能框架中將其一舉解決。接下來,就看誰發(fā)展得更快了。


          開源世界中的生態(tài)陣營(yíng)

          這里我想把視野縮小一點(diǎn),通過具體案例聊聊開源世界中的生態(tài)陣營(yíng)是怎么產(chǎn)生的。


          相信很多 Node 開發(fā)者都知道 Jest 是怎樣力壓 Mocha 測(cè)試框架,一路迅猛崛起的。Mocha 想當(dāng)年也是人們首選的測(cè)試運(yùn)行程序,效果不錯(cuò)而且語法優(yōu)秀,但只要涉及更復(fù)雜的需求或者斷言,就得引入其他模塊和插件。好在有了社區(qū)協(xié)作,插件也不算太難找。總之,開發(fā)者需要具備更廣泛的知識(shí)才能引入相應(yīng)的庫。


          后來 Facebook 搞出了 Jest,一套內(nèi)含“batteries”的測(cè)試框架。它借鑒了 Mocha 語法和庫,并把一切整合到了單一框架中。Jest 什么都能解決,從偽造時(shí)間到需求的檢測(cè)和模擬。Jest 也有擴(kuò)展空間,但我在實(shí)際工作中就用過一次。大部分概念驗(yàn)證和設(shè)計(jì)都是由 Mocha 承擔(dān)的,作為后來者的 Jest 只是把成果統(tǒng)一了起來并使其變得更易于訪問。雖然 Mocha 也不乏鐵桿粉絲,但 Jest 確實(shí)更受歡迎。


          開源世界中有很多這樣的案例。首創(chuàng)解決方案拿下先發(fā)優(yōu)勢(shì),而后續(xù)一旦增長(zhǎng)乏力,就會(huì)有熱心的開發(fā)商把功能整合起來。這也讓我想到了 Linux 大家族還未統(tǒng)一時(shí)的 systemd。如今,systemd 幾乎可以管理大多數(shù) Linux 發(fā)行版上的所有內(nèi)容,而 Bun 也許會(huì)以同樣的方式席卷整個(gè) JavaScript 世界。


          我意識(shí)到從開源的角度來看,這種合并和統(tǒng)一似乎與開源精神相悖,但用大量庫實(shí)現(xiàn)簡(jiǎn)單需求確實(shí)已經(jīng)成為折磨開發(fā)者們的痛點(diǎn)。而且如果每個(gè)庫都有相應(yīng)的維護(hù)團(tuán)隊(duì),那惡意黑客通過簡(jiǎn)單的偽造郵件域就能實(shí)施供應(yīng)鏈攻擊。我們不想這樣,但現(xiàn)實(shí)就是如此殘酷。老手尚且容易中招,更遑論剛接觸大量名稱、還不熟悉種種語言的新人了。所以從務(wù)實(shí)的角度出發(fā),我覺得很多朋友應(yīng)該跟我一樣,并不覺得把更多常用功能引入標(biāo)準(zhǔn)庫、將多種開發(fā)工具整合進(jìn)統(tǒng)一框架屬于歷史的倒退。

          ?結(jié)束語


          截至 2022 年 7 月,Bun 還是沒有做好進(jìn)軍生產(chǎn)環(huán)境的準(zhǔn)備,但我強(qiáng)烈建議大家自己裝上試一試。整個(gè)流程非常便捷,而且我覺得現(xiàn)在的 Bun 已經(jīng)足夠應(yīng)付小型子項(xiàng)目或者公司里的簡(jiǎn)單內(nèi)部?jī)x表板了。


          我不敢說 Bun 在未來幾年能否甚至如何重塑 JavaScript 的面貌,但我真心對(duì)它的發(fā)展充滿期待。


          原文鏈接:


          https://www.lunasec.io/docs/blog/bun-first-look/

          者:陳吉

          轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/HweEFh78WXLawyQr_Vsl5g


          主站蜘蛛池模板: 色婷婷av一区二区三区仙踪林| 国产品无码一区二区三区在线蜜桃| 欧美av色香蕉一区二区蜜桃小说| 天堂一区二区三区精品| 99精品久久精品一区二区| 另类ts人妖一区二区三区| 无码毛片视频一区二区本码 | 亚洲熟妇av一区二区三区| 精品国产精品久久一区免费式| 亚洲国产一区二区a毛片| 91麻豆精品国产自产在线观看一区| 国产suv精品一区二区6| 亚洲日韩中文字幕无码一区| 亚洲第一区香蕉_国产a| 亚洲av鲁丝一区二区三区| 亚洲日韩国产精品第一页一区| 国产免费伦精品一区二区三区| 成人精品一区二区三区电影| 国产乱码精品一区二区三区| 亚洲av永久无码一区二区三区| 精品国产一区二区三区色欲| 一区二区不卡在线| 亚洲爆乳精品无码一区二区| 亚洲AV无码一区二区三区性色| 国产日韩精品视频一区二区三区 | 日韩一区二区三区射精| 午夜AV内射一区二区三区红桃视| 伊人色综合网一区二区三区| 自拍日韩亚洲一区在线| 人妻av综合天堂一区| 国产在线观看精品一区二区三区91| 精品久久综合一区二区| 精彩视频一区二区| 国产成人精品a视频一区| 国产一区二区三区免费观看在线| 久久综合精品不卡一区二区| 日韩一区二区超清视频| 日本一区二区三区精品视频| 一区二区三区视频观看| 久久久久无码国产精品一区| 中文激情在线一区二区|