node_modules 資料夾大小不是問題,反而是一個特權

關於 node_modules 資料夾大小辯論的我的想法 我曾對於 node_modules 資料夾的大小感到懊惱。一個 JavaScript 應用程式怎麼可能在沒有我加入任何一行程式碼的情況下就有100、200MB的大小呢?我只是執行 npx create-react-app todolist,然後下載了218.7MB的東西!(我現在剛剛檢查了一下,這是真的數字)。 每當你思考 node_modules 的大小時,請想想我們程式開發人員投入的無數工時。 這是完全開源的軟體,是你可以檢視和學習的軟體。它是由世界各地的程式開發人員和公司慷慨捐贈的。它是一個全球性的努力,某人將它變得非常簡單好用。首先是 npm 這個工具,接著才是 npm 公司。 我們都同意將自己的程式碼發布到他們的伺服器上,人們在上面進一步建立了其他東西,直到我們得到了快速入門工具(如 create-react-app 或 Vue CLI 等),可以免費獲得大量功能。 在 TB 級快速儲存的時代,200MB 的大小算太大嗎? 請記住,在這個大小中,絕大多數是測試、文件等等。而且剩下的程式碼絕大多數只會在開發環境中使用。這並不意味著你會將一個200MB的應用程式提供給用戶,我認為這一點是深入人心的。 我以 create-react-app 為例,那 200MB 中有些什麼? 首先,create-react-app 包含了: 編譯器 (Babel) 打包工具 (Webpack) 程式碼壓縮工具 程式碼檢查工具 (ESLint) 樣式流程工具 (SCSS) 具有熱重載功能的開發伺服器 測試執行工具 (Jest) 如果你想要開發 Mac 或 iPhone 應用程式,你必須安裝蘋果提供的 IDE,即 Xcode。Xcode 的大小(等一下……)幾乎是 14GB。那是 node_modules 的 70 倍大小。確實,我們在比較兩件不同的事物,但 node_modules 包含了你開始編寫程式碼所需的一切。你可以搭配大小為 200MB 的 VS Code 或大小為 30MB 的 Sublime Text 使用,都沒關係,並不是必須的(而你卻無法在沒有 Xcode 的情況下創建 iOS/macOS 應用程式)。...

node-mass-rename-files

#如何在Node.js中批量更名文件 了解如何使用Node.js更改一组文件名 在本篇博客文章中,我将解释如何更改一组文件的名称。 相同的过程也适用于将文件移动到另一个文件夹,因为在更改名称时,实际上是更改文件的路径。 进行此任务的动机是:在Hugo中,我们可以将博客文章编写为文件,如下所示: first-post.md second-post.md third-post.md 我们还可以将它们添加到包含 index.md 文件的文件夹中: first-post/ > index.md second-post/ > index.md third-post/ > index.md 不同之处在于,使用文件夹可以更轻松地添加图片并将其与博客文章关联起来。 我本可以手动进行更改,但这个文件夹中有大约50个文件,我真的不想自己动手。 我希望能够自动进行更改。 让我们首先引入我们将使用的一个核心模块:fs。由于它是一个核心模块,所以无需进行 npm install。 const fs = require('fs') 然后,获取对当前文件夹的引用。假设我们要在想要执行此更改的同一文件夹中运行脚本。 __dirname 是指向当前工作文件夹的变量。 我获取了所有文件和文件夹的列表: const files = fs.readdirSync(__dirname) 然后,我仅筛选出以 .md 结束的项: for (const file of files) { if (file.endsWith('.md')) { console.log(file) } } 一旦我们有了代表文件名的 file 引用,我们就可以调用 fs.mkdirSync() 来创建文件夹: fs.mkdirSync( __dirname + '/' + file.replace('.md', ''), { recursive: true }, (err) => { console....

Node:接收命令行参数

如何在Node.js程序中从命令行接收参数 在调用Node.js应用程序时,您可以传递任意数量的参数 node app.js 参数可以是独立的,也可以由键和值组成。 例如: node app.js flavio 或者 node app.js name=flavio 这会影响您在Node代码中如何检索这个值。 要检索它,可以使用Node内置的process对象。 它暴露了一个argv属性,它是一个包含所有命令行参数的数组。 第一个参数是node命令的完整路径。 第二个元素是正在执行的文件的完整路径。 所有其他参数从第三个位置开始存在。 您可以使用循环遍历所有参数(包括节点路径和文件路径): process.argv.forEach((val, index) => { console.log(`${index}: ${val}`) }) 通过创建一个新数组来排除前两个参数,您可以仅获取其他参数: const args = process.argv.slice(2) 如果有一个没有索引名称的参数,像这样: node app.js flavio 您可以使用以下方式访问它: const args = process.argv.slice(2) args[0] 在这种情况下: node app.js name=flavio args[0]是name=flavio,您需要解析它。 最好的方法是使用minimist库,它有助于处理参数: const args = require('minimist')(process.argv.slice(2)) args['name'] // flavio

Node.js Runtime v8 選項列表

您在啟動 Node.js 程式時可以使用的所有選項 Node.js 可以以各種方式啟動,您可以使用許多選項來配置 Node.js 的行為。 這些選項中的大部分都用於配置 v8 引擎的行為。 這裡列出的某些選項默認情況下是禁用的,就像您在 Default 列中看到的那樣。您可以通過運行 node 並傳遞標誌來啟用它們,例如 node --experimental-extras。 如果一個選項默認是啟用的,您可以通過在標誌名稱前加上 --no- 來禁用它,例如 node --no-harmony-shipping。 一些選項可用於優化性能,例如 --optimize-for-size、--max_old_space_size 和 --gc_interval,就像 Heroku 建議的那樣。 其他一些選項用於啟用或禁用特定功能。我經常使用它們來嘗試在 beta 中實現的新提議的 JavaScript 功能,比如 --harmony-public-fields。 註: 選項名稱允許使用連字符(-)或下劃線(_)分隔單詞,或者兩者混合使用。在教程中您會發現兩者混合使用,可能會有點混淆。它們沒有區別。 我通過運行命令 node --v8-options 得到了以下列表,它是相對於 Node.js 11.9.0 進行的,這是我撰寫本文時的最新 Node.js 版本。 選項 描述 類型 默認值 --experimental-extras 启用通过 v8_experimental_extra_library_files 編譯的代碼 bool false --use-strict 強制使用嚴格模式 bool false --es-staging 启用值得測試的和內部使用的 Harmony 功能 bool - --harmony 啟用所有已完成的 Harmony 功能 bool false --harmony-shipping 啟用所有已發佈的 Harmony 功能 bool true --harmony-do-expressions 啟用“harmony do-expressions” 進展中 bool --harmony-class-fields 啟用“類文字中的 harmony fields” 進展中 bool --harmony-static-fields 啟用“類字面中的 harmony 靜態字段” 進展中 bool --harmony-await-optimization 啟用“harmony await 佔用 1 個 tick” 進展中 bool --harmony-locale 啟用“Intl....

Node.js 流

學習流的作用以及為什麼它們如此重要以及如何使用它們。 什麼是流 為什麼使用流 流的一個例子 pipe() 基於流的 Node.js API 不同類型的流 如何創建可讀流 如何創建可寫流 如何從可讀流中獲取數據 如何將數據發送到可寫流 告訴可寫流您已經結束寫入 什麼是流 流是 Node.js 應用程序的基本概念之一。它們是一種以高效方式處理讀取/寫入文件、網絡通信或任何類型的端到端信息交換的方法。 流不是 Node.js 獨有的概念。它們在數十年前引入了 Unix 操作系統,程序可以通過管道運算符(|)相互交互地傳遞流。 例如, 在傳統的方式中,當您要求程序讀取一個文件時,文件被從頭到尾讀入內存,然後進行處理。 使用流,您可以分塊讀取它,處理其內容,而無需將其全部保留在內存中。 Node.js 的 stream 模塊 提供了所有流 API 的基礎。 為什麼使用流 流主要提供了兩個優勢,與其他數據處理方法相比: 內存效率:您不需要在能夠處理數據之前將大量數據加載到內存中。 時間效率:只要有數據可用,開始處理數據所需的時間遠小於等到整個數據有效負載可用時的時間。 流的一個例子 一個典型的例子是從磁盤讀取文件。 使用 Node fs 模塊,當建立一個新的連接到您的 HTTP 服務器時,您可以讀取一個文件並在 HTTP 上提供它: const http = require('http'); const fs = require('fs'); const server = http.createServer(function (req, res) { fs.readFile(__dirname + '/data.txt', (err, data) => { res.end(data); }); }); server....

Node.js 核心模塊

Node.js 提供了一系列的核心模塊,這些模塊是 Node.js 平臺的一部分,並與 Node.js 安裝一同提供。 以下是其中一些模塊的詳細資訊: 名稱 描述 assert 提供一組有用於測試的斷言函數 buffer 提供處理包含二進制數據的緩衝區的能力 child_process 提供生成子進程的能力 console 提供簡單的調試控制台 cluster 允許將一個 Node.js 進程分為多個工作進程,以充分利用多核系統 crypto 提供加密功能 dgram 提供 UDP 數據報插座的實現 dns 提供名稱解析和 DNS 查詢 events 提供管理事件的 API fs 提供與文件系統交互的 API http 提供 HTTP 客戶端/服務器的實現 http2 提供 HTTP/2 客戶端/服務器的實現 https 提供 HTTPS 客戶端/服務器的實現 net 提供異步網絡 API os 提供與操作系統相關的實用方法和屬性 path 提供處理文件和目錄路徑的實用工具 perf_hooks 用於啟用性能指標的收集 process 提供關於當前 Node.js 進程的信息和控制 querystring 提供解析和格式化 URL 查詢字符串的實用工具 readline 提供從可讀流中讀取數據的界面 repl 提供獨立程序或可包含在其他應用中的 REPL(Read-Eval-Print-Loop)實現 stream 用於處理流式數據的抽象接口 string_decoder 提供將緩衝區對象解碼為字符串的 API timers 提供調度在未來某個時間點調用函數的功能 tls 提供 Transport Layer Security(TLS)和 Secure Socket Layer(SSL)協議的實現 tty 提供在文本終端中進行 I/O 操作的功能 url 提供 URL 解析和解析的實用工具 util 支持 Node....

Node.js 簡介

這篇文章是關於 Node.js 的入門指南,Node.js 是一個運行在伺服器端的 JavaScript 執行環境。Node.js 是建立在 Google Chrome V8 JavaScript 引擎之上,主要用於建立網頁伺服器,但不僅限於此。 概述 [Node.js 的最佳特性](#node.js 的最佳特性) 快速 簡單 JavaScript V8 異步平台 大量的函式庫 [一個 Node.js 應用程式範例](#一個 Node.js 應用程式範例) [Node.js 框架和工具](#node.js 框架和工具) Node.js 是一個在伺服器上運行的 JavaScript 執行環境。 Node.js 是開源的、跨平台的,自從在2009年推出以來,它已經變得非常流行,現在在網頁開發中扮演著重要的角色。如果以 GitHub 上的 stars 數量作為流行度指標,擁有58000+ stars就意味著非常受歡迎。 Node.js 運行 V8 JavaScript 引擎,該引擎是 Google Chrome 的核心,而 Node.js 可以利用使 Chrome JavaScript 執行時非常高速的工程師的工作,這使得 Node.js 可以受益於巨大的性能改進和即時編譯。由於這一點,運行在 Node.js 中的 JavaScript 代碼可以非常高效。 Node.js 的應用程式由單個進程運行,不為每個請求創建新的線程。Node.js 的標準庫提供了一組異步 I/O 原語,可以防止 JavaScript 代碼阻塞,通常情況下 Node.js 的庫都是使用非阻塞的範例來編寫,使得阻塞行為成為異常而不是正常行為。 當 Node....

Node.js,開發與生產環境的差異

了解如何為生產和開發環境設置不同的配置。 你可以為生產與開發環境設置不同的配置。 Node.js 假設它一直在開發環境中運行。但你可以通過設置 NODE_ENV=production 的環境變量,告訴 Node.js 你正在生產環境中運行。 通常,在 shell 中執行以下命令即可完成此操作: export NODE_ENV=production 但最好將其放在您的 shell 配置文件中(例如使用 Bash shell 的 .bash_profile),以便在系統重新啟動時此設置仍然有效。 你還可以在應用程序初始化命令之前加上環境變量: NODE_ENV=production node app.js 這個環境變量是一個經常在外部庫中使用的約定。 將環境設置為 production 通常可以確保: 日誌保持在最低限度的關鍵級別 融入更多的緩存層以優化性能 例如,Express 使用的模板庫 Pug 如果 NODE_ENV 沒有設置為 production,則會在調試模式下編譯。在開發模式下,每次請求都會編譯 Express 視圖,而在生產模式下則會被緩存。這只是其中一個例子,還有很多其他例子。 Express 提供了特定於環境的配置鉤子,根據 NODE_ENV 變量的值自動調用: app.configure('development', () => { //... }) app.configure('production', () => { //... }) app.configure('production', 'staging', () => { //... }) 例如,你可以使用這個來為不同模式設置不同的錯誤處理程序: app.configure('development', () => { app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); }) app....

Node.js中的錯誤處理

如何在Node.js應用程式執行期間處理錯誤 Node.js中的錯誤通過異常處理。 建立異常 使用throw關鍵字來建立異常: throw value JavaScript執行此行時,正常程式流程將中斷,控制權會返回到最近的異常處理器。 通常在用戶端程式碼中,value可以是任何JavaScript值,包括字串、數字或對象。 在Node.js中,我們不會拋出字串,而是拋出錯誤對象。 錯誤對象 錯誤對象是Error對象的實例,或是擴展了Error類別的對象,這些類別提供在錯誤核心模組中。 throw new Error('Ran out of coffee') 或者 class NotEnoughCoffeeError extends Error { //... } throw new NotEnoughCoffeeError 處理異常 異常處理器是一個try/catch語句。 在try區塊中的代碼行引發的任何異常都在相應的catch區塊中進行處理: try { //代碼行 } catch (e) { } 此示例中的e是異常值。 您可以添加多個處理器,可以捕獲不同類型的錯誤。 捕獲未捕獲的異常 如果在執行程序期間拋出未捕獲的異常,程序將崩潰。 為了解決這個問題,你可以聽取process對象上的uncaughtException事件: process.on('uncaughtException', (err) => { console.error('There was an uncaught error', err) process.exit(1) //根據Node文檔,這是必需的 }) 您無需匯入process核心模組,因為它會自動注入。 使用承諾處理異常 使用承諾,您可以鏈接不同的操作,並在結尾處理錯誤: doSomething1() .then(doSomething2()) .then(doSomething3()) .catch(err => console.error(err)) 您如何知道錯誤發生在哪裡?實際上,您並不知道,但您可以在調用的每個函數(doSomethingX)中處理錯誤,在錯誤處理器內部拋出一個新錯誤,將調用外部的catch處理器: const doSomething1 = () => { //....

Node.js事件循環

事件循環是了解Node.js最重要的方面之一。 為什麼這個很重要?因為它解釋了Node.js為什麼可以是非同步的並且具有非阻塞的I/O,也解釋了Node.js的"殺手級應用",這正是使它變得如此成功的原因。 Node.js的JavaScript代碼運行在單個線程上,一次只能發生一件事。 這實際上是一種很有幫助的限制,因為它簡化了編程,不需要擔心並發問題。 您只需注意如何編寫代碼,避免阻塞線程的任何事情,例如同步網絡調用或無限循環。 總的來說,在大多數瀏覽器中,每個瀏覽器標簽都有一個事件循環,以確保每個進程都是隔離的,避免網頁中的無限循環或重型處理導致整個瀏覽器被阻塞。 環境管理多個並發的事件循環,以處理API調用等。Web Worker也運行在它們自己的事件循環中。 您只需要關心您的代碼將運行在一個單獨的事件循環上,並根據這一點來編寫代碼,以避免阻塞它。 阻塞事件循環 任何需要太長時間才能將控制權交還給事件循環的JavaScript代碼將會阻塞頁面上的任何JavaScript代碼的執行,甚至阻塞UI線程,使用戶無法點擊、滾動頁面等。 在JavaScript中,幾乎所有的I/O原語都是非阻塞的,例如網絡請求、文件系統操作等。阻塞是例外,這就是為什麼JavaScript在很大程度上基於回調,最近則是基於Promise和async/await的原因。 調用堆疊 調用堆疊是一個後進先出(LIFO)的隊列。 事件循環會不斷檢查調用堆疊,以查看是否有需要運行的函數。 在這個過程中,它將找到的每個函數調用添加到調用堆疊中,並按順序執行每個函數。 您可能熟悉調試器或瀏覽器控制台中的錯誤堆疊跟踪,瀏覽器通過查找調用堆疊中的函數名稱來告訴您哪個函數產生了當前的調用,如下圖所示: 一個簡單的事件循環解釋 讓我們舉個例子: const bar = () => console.log('bar') const baz = () => console.log('baz') const foo = () => { console.log('foo') bar() baz() } foo() 這段代碼將打印出: foo bar baz 如預期一樣。 當代碼運行時,首先調用foo(),在foo()內部,我們首先調用bar(),然後調用baz()。 此時,調用堆疊如下: 事件循環在每次迭代時檢查調用堆疊,並執行其中的所有函數,直到調用堆疊為空。 排隊函數的執行 上面的示例看起來很正常,沒有什麼特別之處,JavaScript找到要執行的東西,按順序執行它們。 讓我們來看看如何延遲一個函數,直到堆疊清空。 setTimeout(() => {}, 0)的用法是調用一個函數,但是在代碼中的其他函數執行完畢之後再執行它。 請看下面的例子: const bar = () => console.log('bar') const baz = () => console.log('baz') const foo = () => { console....