<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
當使用JavaScript框架或庫時,程式碼中可能會存在許多未使用的函數和變數,這些未使用的程式碼會使應用程式的檔案大小變大,從而影響應用程式的效能。Tree shaking可以解決這個問題,它可以通過檢測和刪除未使用的程式碼來減小檔案大小並提高應用程式效能。
接下來我們將通過兩種方式實現Tree shaking
1、首先,你需要使用ES6模組來匯出和匯入程式碼。ES6模組可以靜態分析,從而使Tree shaking技術成為可能。例如,在一個名為“math.js”的檔案中,你可以使用以下程式碼來匯出函數:
export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } export function multiply(a, b) { return a * b; }
2、在應用程式入口處標記使用的程式碼: 在應用程式的入口處,你需要標記使用的程式碼。這可以通過建立一個名為"usedExports"的集合來實現,其中包含你在入口檔案中使用的匯出。
import { add } from './math.js'; const usedExports = new Set([add]);
在這個範例中,我們建立了一個名為"usedExports"的集合,並將我們在應用程式入口檔案中使用的add函數新增到集合中。
3、遍歷並檢測未使用的程式碼: 在應用程式的所有模組中遍歷匯出並檢查它們是否被使用。你可以使用JavaScript的反射API來實現這一點。以下是程式碼範例:
function isUsedExport(exportName) { return usedExports.has(eval(exportName)); } for (const exportName of Object.keys(exports)) { if (!isUsedExport(exportName)) { delete exports[exportName]; } }
在這個範例中,我們定義了一個isUsedExport函數來檢查是否使用了給定的匯出名稱。然後,我們遍歷應用程式中的所有匯出,並將每個匯出的名稱作為引數傳遞給isUsedExport函數。如果匯出沒有被使用,則從exports物件中刪除該匯出。
4、最後,我們需要在控制檯中呼叫一些函數以確保它們仍然可以正常工作。由於我們只在"usedExports"集合中新增了add函數,因此subtract()和multiply()函數已經被刪除了。
假設我們有以下的 source
程式碼:
import { sum } from './utils'; export function add(a, b) { return sum(a, b); } export const PI = 3.14;
我們首先需要使用 @babel/parser
將原始碼解析成 AST:
const parser = require("@babel/parser"); const fs = require("fs"); const sourceCode = fs.readFileSync("source.js", "utf8"); const ast = parser.parse(sourceCode, { sourceType: "module", });
接著,我們需要遍歷 AST 並找到所有被使用的匯出變數和函數:
// 建立一個 Set 來儲存被使用的匯出 const usedExports = new Set(); // 標記被使用的匯出 function markUsedExports(node) { if (node.type === "Identifier") { usedExports.add(node.name); } else if (node.type === "ExportSpecifier") { usedExports.add(node.exported.name); } } // 遍歷 AST 樹並標記被使用的匯出 function traverse(node) { if (node.type === "CallExpression") { markUsedExports(node.callee); node.arguments.forEach(markUsedExports); } else if (node.type === "MemberExpression") { markUsedExports(node.property); markUsedExports(node.object); } else if (node.type === "Identifier") { usedExports.add(node.name); } else if (node.type === "ExportNamedDeclaration") { if (node.declaration) { if (node.declaration.type === "FunctionDeclaration") { usedExports.add(node.declaration.id.name); } else if (node.declaration.type === "VariableDeclaration") { node.declaration.declarations.forEach((decl) => { usedExports.add(decl.id.name); }); } } else { node.specifiers.forEach((specifier) => { usedExports.add(specifier.exported.name); }); } } else if (node.type === "ImportDeclaration") { node.specifiers.forEach((specifier) => { usedExports.add(specifier.local.name); }); } else { for (const key of Object.keys(node)) { // 遍歷物件的屬性,如果屬性的值也是物件,則遞迴呼叫 traverse 函數 if (key !== "loc" && node[key] && typeof node[key] === "object") { traverse(node[key]); } } } } // 遍歷整個 AST 樹 traverse(ast);
在這裡,我們建立了一個 Set
來儲存被使用的匯出,然後遍歷 AST 樹並標記被使用的匯出。具體來說,我們會:
我們通過遍歷 AST 樹並呼叫 markUsedExports
函數來標記被使用的匯出,最終將這些匯出儲存在 usedExports
Set 中。
接下來,我們需要遍歷 AST 並刪除未被使用的程式碼:
// 移除未使用的程式碼 function removeUnusedCode(node) { // 處理常式宣告 if (node.type === "FunctionDeclaration") { if (!usedExports.has(node.id.name)) { // 如果該函數未被使用 node.body.body = []; // 將該函數體清空 } } // 處理變數宣告 else if (node.type === "VariableDeclaration") { node.declarations = node.declarations.filter((decl) => { return usedExports.has(decl.id.name); // 過濾出被使用的宣告 }); if (node.declarations.length === 0) { // 如果沒有被使用的宣告 node.type = "EmptyStatement"; // 將該宣告置為 EmptyStatement } } // 處理匯出宣告 else if (node.type === "ExportNamedDeclaration") { if (node.declaration) { // 處理常式匯出宣告 if (node.declaration.type === "FunctionDeclaration") { if (!usedExports.has(node.declaration.id.name)) { // 如果該函數未被使用 node.declaration.body.body = []; // 將該函數體清空 } } // 處理變數匯出宣告 else if (node.declaration.type === "VariableDeclaration") { node.declaration.declarations = node.declarations.filter((decl) => return usedExports.has(decl.id.name); // 過濾出被使用的宣告 }); if (node.declaration.declarations.length === 0) { // 如果沒有被使用的宣告 node.type = "EmptyStatement"; // 將該宣告置為 EmptyStatement } } else { // 處理匯出的具體內容 node.specifiers = node.specifiers.filter((specifier) => { return usedExports.has(specifier.exported.name); // 過濾出被使用的內容 }); if (node.specifiers.length === 0) { // 如果沒有被使用的內容 node.type = "EmptyStatement"; // 將該宣告置為 EmptyStatement } } } // 處理匯入宣告 else if (node.type === "ImportDeclaration") { node.specifiers = node.specifiers.filter((specifier) => { return usedExports.has(specifier.local.name); // 過濾出被使用的宣告 }); if (node.specifiers.length === 0) { // 如果沒有被使用的宣告 node.type = "EmptyStatement"; // 將該宣告置為 EmptyStatement } } // 處理表示式語句 else if (node.type === "ExpressionStatement") { if (node.expression.type === "AssignmentExpression") { if (!usedExports.has(node.expression.left.name)) { // 如果該表示式未被使用 node.type = "EmptyStatement"; // 將該語句置為 EmptyStatement } } } // 處理其他情況 else { for (const key of Object.keys(node)) { if (key !== "loc" && node[key] && typeof node[key] === "object") { removeUnusedCode(node[key]); // 遞迴處理子節點 } } } } removeUnusedCode(ast); // 執行移除未使用程式碼的
在這裡,我們遍歷 AST 並刪除所有未被使用的程式碼。具體地,我們會:
最後,我們將修改後的 AST 重新轉換回 JavaScript 程式碼:
const { transformFromAstSync } = require("@babel/core"); const { code } = transformFromAstSync(ast, null, { presets: ["@babel/preset-env"], }); console.log(code);
這裡我們使用了 @babel/core
將 AST 轉換回 JavaScript 程式碼。由於我們使用了 @babel/preset-env
,它會自動將我們的程式碼轉換成 ES5 語法,以便於在各種瀏覽器上執行。
這只是一個簡單的例子,實際上還有很多細節需要處理,比如處理 ES modules、CommonJS 模組和 UMD 模組等。不過,這個例子可以幫助我們理解 Tree Shaking 的工作原理,以及如何手動實現它。
以上就是Tree Shaking實現方法指南的詳細內容,更多關於Tree Shaking實現的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45