摘要:教程如何使用打包通過這個系列教程一步一步學習如何使用更小更快的取代和打包文件。安裝并且創建配置文件。提示是告訴我們實際需要哪些插件的集合。通過下面的命令安裝兩個插件更新然后,引入插件并添加進配置注意屬性是為了幫助模塊遷移到的一部分。
教程:如何使用Rollup打包JavaScript
通過這個系列教程一步一步學習如何使用更小更快的Rollup取代webpack和Browserify打包JavaScript文件。
這周,我們要使用Rollup構建我們的第一個項目,Rollup是一個打包JavaScript(和樣式,不過下周才會做)的構建工具。
通過這個教程,我們的Rollup將能夠:
合并scripts代碼,
刪除多余代碼,
編譯成對舊瀏覽器友好的代碼,
支持在瀏覽器中使用Node模塊,
能使用環境變量,
盡可能的壓縮,減少文件大小。
準備工作至少懂一點JavaScript的話將會更好理解。
對ES2015 modules有基本了解,不過不了解也無妨。
在你的設備上要有npm。(還沒有?在這下載Node.js)
Rollup是什么?用他們自己的話說:
Rollup是下一代JavaScript模塊打包工具。開發者可以在你的應用或庫中使用ES2015模塊,然后高效地將它們打包成一個單一文件用于瀏覽器和Node.js使用。
和Browserify和webpack很像。
你也可以稱Rollup是一個構建工具,可以和像Grunt和Gulp等一起配置使用。但是,需要注意的一點是當你使用Grunt和Gulp來處理像打包JavaScript這樣的任務時,這些工具的底層還是使用了像Rollup,Browserify或webpack這些東西。
為什么應該關注Rollup?Rollup最令人激動的地方,就是能讓打包文件體積很小。這么說很難理解,更詳細的解釋:相比其他JavaScript打包工具,Rollup總能打出更小,更快的包。
因為Rollup基于ES2015模塊,比webpack和Browserify使用的CommonJS模塊機制更高效。這也讓Rollup從模塊中刪除無用的代碼,即tree-shaking變得更容易。
當我們引入擁有大量函數和方法的三方工具或者框架時tree-shaking會變得很重要。想想lodash或者jQuery,如果我們只使用一個或者兩個方法,就會因為加載其余內容而產生大量無用的開銷。
Browserify和webpack就會包含大量無用的代碼。但是Rollup不會 - 它只會包括我們真正用到的東西。
更新 (2016-08-22): 澄清一下,Rollup只能對ES模塊上進行tree-shaking。CommonJS模塊 - 像lodash和jQuery那樣寫的模塊不能進行tree-shaking。然而,tree-shaking不是Rollup在速度/性能上唯一的優勢。可以看Rich Harris的解釋和Nolan Lawson的補充了解更多。
還有一個大新聞。
Part I: 如何使用Rollup處理并打包JavaScript文件注意: 由于Rollup很高效,webpack 2 也將支持tree-shaking。
為了展示Rollup如何使用,讓我們通過構建一個簡單的項目來走一遍使用Rollup打包JavaScript的過程。
STEP 0: 創建一個包含將被編譯的JavaScript和CSS的項目.為了開始工作,我們需要一些用來處理的代碼。這個教程里,我們將用一個小應用,可從GitHub獲取。
目錄結構如下:
learn-rollup/ ├── src/ │ ├── scripts/ │ │ ├── modules/ │ │ │ ├── mod1.js │ │ │ └── mod2.js │ │ └── main.js │ └── styles/ │ └── main.css └── package.json
你可以在終端執行下面的命令下載這個應用,我們將在這個教程中使用它。
# Move to the folder where you keep your dev projects. cd /path/to/your/projects # Clone the starter branch of the app from GitHub. git clone -b step-0 --single-branch https://github.com/jlengstorf/learn-rollup.git # The files are downloaded to /path/to/your/projects/learn-rollup/STEP 1: 安裝Rollup并且創建配置文件。
第一步,執行下面的命令安裝Rollup:
npm install --save-dev rollup
然后,在learn-rollup文件夾下新建rollup.config.js。在文件中添加如下內容。
export default { entry: "src/scripts/main.js", dest: "build/js/main.min.js", format: "iife", sourceMap: "inline", };
說說每個配置項實際上做了什么:
entry — 希望Rollup處理的文件路徑。大多數應用中,它將是入口文件,初始化所有東西并啟動應用。
dest — 編譯完的文件需要被存放的路徑。
format — Rollup支持多種輸出格式。因為我們是要在瀏覽器中使用,需要使用立即執行函數表達式(IIFE)[注1]
sourceMap — 調試時sourcemap是非常有用的。這個配置項會在生成文件中添加一個sourcemap,讓開發更方便。
測試Rollup配置NOTE: 對于其他的format選項以及你為什么需要他們,看Rollup’s wiki。
當創建好配置文件后,在終端執行下面的命令測試每項配置是否工作:
./node_modules/.bin/rollup -c
在你的項目下會出現一個build目錄,包含js子目錄,子目錄中包含生成的main.min.js文件。
在瀏覽器中打開build/index.html可以看到打包文件正確生成了。
完成第一步后我們的示例項目的狀態。
看看打包出來的文件注意:現在,只有現代瀏覽器下不會報錯。為了能夠在不支持ES2015/ES6的老瀏覽器中運行,我們需要添加一些插件。
事實上Rollup強大是因為它使用了“tree-shaking”,可以在你引入的模塊中刪除沒有用的代碼。舉個例子,在src/scripts/modules/mod1.js中的sayGoodbyeTo()函數在我們的應用中并沒有使用 - 而且因為它從不會被使用,Rollup不會將它打包到bundle中:
(function () { "use strict"; /** * Says hello. * @param {String} name a name * @return {String} a greeting for `name` */ function sayHelloTo( name ) { const toSay = `Hello, ${name}!`; return toSay; } /** * Adds all the values in an array. * @param {Array} arr an array of numbers * @return {Number} the sum of all the array values */ const addArray = arr => { const result = arr.reduce((a, b) => a + b, 0); return result; }; // Import a couple modules for testing. // Run some functions from our imported modules. const result1 = sayHelloTo("Jason"); const result2 = addArray([1, 2, 3, 4]); // Print the results on the page. const printTarget = document.getElementsByClassName("debug__output")[0]; printTarget.innerText = `sayHelloTo("Jason") => ${result1} ` printTarget.innerText += `addArray([1, 2, 3, 4]) => ${result2}`; }()); //# sourceMappingURL=data:application/json;charset=utf-8;base64,...
其他的構建工具則不是這樣的,所以如果我們引入了一個像lodash這樣一個很大的庫而只是使用其中一兩個函數時,我們的包文件會變得非常大。
比如使用webpack的話,sayGoodbyeTo()也會打包進去,產生的打包文件比Rollup生成的大了兩倍多。
STEP 2: 配置babel支持JavaScript新特性。現在我們已經得到能在現代瀏覽器中運行的包文件了,但是在一些舊版本瀏覽器中就會崩潰 - 這并不理想。
幸運的是,Babel已發布了。這個項目編譯JavaScript新特性(ES6/ES2015等等)到ES5, 差不多在今天的任何瀏覽器上都能運行。
如果你還沒用過Babel,那么你的開發生涯要永遠地改變了。使用JavaScript的新方法讓語言更簡單,更簡潔而且整體上更友好。
那么讓我們為Rollup加上這個過程,就不用擔心上面的問題了。
INSTALL THE NECESSARY MODULES. 安裝必要模塊首先,我們需要安裝Babel Rollup plugin和適當的Babel preset。
# Install Rollup’s Babel plugin. npm install --save-dev rollup-plugin-babel # Install the Babel preset for transpiling ES2015 using Rollup. npm install --save-dev babel-preset-es2015-rollup
創建.babelrc提示: Babel preset是告訴Babel我們實際需要哪些babel插件的集合。
然后,在項目根目錄(learn-rollup/)下創建一個.babelrc文件。在文件中添加下面的JSON:
{ "presets": ["es2015-rollup"], }
它會告訴Babel在轉換時哪些preset將會用到。
更新rollup.config.js為了讓它能真正工作,我們需要更新rollup.config.js。
在文件中,importBabel插件,將它添加到新配置屬性plugins中,這個屬性接收一個插件組成的數組。
// Rollup plugins import babel from "rollup-plugin-babel"; export default { entry: "src/scripts/main.js", dest: "build/js/main.min.js", format: "iife", sourceMap: "inline", plugins: [ babel({ exclude: "node_modules/**", }), ], };
為避免編譯三方腳本,通過設置exclude屬性忽略node_modules目錄。
檢查輸出文件全部都安裝并配置好后,重新打包一下:
./node_modules/.bin/rollup -c
再看一下輸出結果,大部分是一樣的。但是有一些地方不一樣:比如,addArray()這個函數:
var addArray = function addArray(arr) { var result = arr.reduce(function (a, b) { return a + b; }, 0); return result; };
Babel是如何將箭頭函數(arr.reduce((a, b) => a + b, 0))轉換成一個普通函數的呢?
這就是編譯的意義:結果是相同的,但是現在的代碼可以向后支持到IE9.
STEP 3: 添加ESLint檢查常規JavaScript錯誤注意: Babel也提供了babel-polyfill,使得像Array.prototype.reduce()這些方法在IE8甚至更早的瀏覽器也能使用。
在你的項目中使用linter是個好主意,因為它強制統一了代碼風格并且能幫你發現很難找到的bug,比如花括號或者圓括號。
在這個項目中,我們將使用ESLint。
安裝模塊為使用ESLint,我們需要安裝ESLint Rollup plugin:
npm install --save-dev rollup-plugin-eslint生成一個.eslintrc.json
為確保我們只得到我們想檢測的錯誤,首先要配置ESLint。很幸運,我們可以通過執行下面的命令自動生成大多數配置:
$ ./node_modules/.bin/eslint --init ? How would you like to configure ESLint? Answer questions about your style ? Are you using ECMAScript 6 features? Yes ? Are you using ES6 modules? Yes ? Where will your code run? Browser ? Do you use CommonJS? No ? Do you use JSX? No ? What style of indentation do you use? Spaces ? What quotes do you use for strings? Single ? What line endings do you use? Unix ? Do you require semicolons? Yes ? What format do you want your config file to be in? JSON Successfully created .eslintrc.json file in /Users/jlengstorf/dev/code.lengstorf.com/projects/learn-rollup
如果你按上面展示的那樣回答問題,你將在生成的.eslintrc.json中得到下面的內容:
{ "env": { "browser": true, "es6": true }, "extends": "eslint:recommended", "parserOptions": { "sourceType": "module" }, "rules": { "indent": [ "error", 4 ], "linebreak-style": [ "error", "unix" ], "quotes": [ "error", "single" ], "semi": [ "error", "always" ] } }修改.eslintrc.json
然而我們需要改動兩個地方來避免項目報錯。
使用2空格代替4空格。
后面會使用到ENV這個全局變量,因此要把它加入白名單中。
在.eslintrc.json進行如下修改 — 添加globals屬性并修改indent屬性:
{ "env": { "browser": true, "es6": true }, "globals": { "ENV": true }, "extends": "eslint:recommended", "parserOptions": { "sourceType": "module" }, "rules": { "indent": [ "error", 2 ], "linebreak-style": [ "error", "unix" ], "quotes": [ "error", "single" ], "semi": [ "error", "always" ] } }更新rollup.config.js
然后,引入ESLint插件并添加到Rollup配置中:
// Rollup plugins import babel from "rollup-plugin-babel"; import eslint from "rollup-plugin-eslint"; export default { entry: "src/scripts/main.js", dest: "build/js/main.min.js", format: "iife", sourceMap: "inline", plugins: [ babel({ exclude: "node_modules/**", }), eslint({ exclude: [ "src/styles/**", ] }), ], };檢查控制臺輸出
第一次,當執行./node_modules/.bin/rollup -c時,似乎什么都沒發生。因為這表示應用的代碼通過了linter,沒有問題。
但是如果我們制造一個錯誤 - 比如刪除一個分號 - 我們會看到ESLint是如何提示的:
$ ./node_modules/.bin/rollup -c /Users/jlengstorf/dev/code.lengstorf.com/projects/learn-rollup/src/scripts/main.js 12:64 error Missing semicolon semi ? 1 problem (1 error, 0 warnings)
一些包含潛在風險和解釋神秘bug的東西立刻出現了,包括出現問題的文件,行和列。
但是它不能排除我們調試時的所有問題,很多由于拼寫錯誤和疏漏產生的bug還是要自己花時間去解決。
STEP 4: 添加插件處理非ES模塊如果你的依賴中有任何使用Node風格的模塊這個插件就很重要。如果沒有它,你會得到關于require的錯誤。
添加一個Node模塊作為依賴在這個小項目中不引用三方模塊很正常,但實際項目中不會如此。所以為了讓我們的Rollup配置變得真正可用,需要保證在我們的代碼中也能引用是三方模塊。
舉個簡單的例子,我們將使用debug包添加一個簡單的日志打印器到項目中。先安裝它:
npm install --save debug
注意:因為它是會在主程序中引用的,應該使用--save參數,可以避免在生產環境下出現錯誤,因為devDependencies在生產環境下不會被安裝。
然后在src/scripts/main.js中添加一個簡單的日志:
// Import a couple modules for testing. import { sayHelloTo } from "./modules/mod1"; import addArray from "./modules/mod2"; // Import a logger for easier debugging. import debug from "debug"; const log = debug("app:log"); // Enable the logger. debug.enable("*"); log("Logging is enabled!"); // Run some functions from our imported modules. const result1 = sayHelloTo("Jason"); const result2 = addArray([1, 2, 3, 4]); // Print the results on the page. const printTarget = document.getElementsByClassName("debug__output")[0]; printTarget.innerText = `sayHelloTo("Jason") => ${result1} `; printTarget.innerText += `addArray([1, 2, 3, 4]) => ${result2}`;
到此一切都很好,但是當運行rollup時會得到一個警告:
$ ./node_modules/.bin/rollup -c Treating "debug" as external dependency No name was provided for external module "debug" in options.globals – guessing "debug"
而且如果在查看index.html,會發現一個ReferenceError拋出了:
默認情況下,三方的Node模塊無法在Rollup中正確加載。
哦,真糟糕。完全無法運行。
因為Node模塊使用CommonJS,無法與Rollup直接兼容。為解決這個問題,需要添加一組處理Node模塊和CommonJS模塊的插件。
安裝模塊圍繞這個問題,我們將在Rollup中新增兩個插件:
rollup-plugin-node-resolve,運行加載node_modules中的三方模塊。
rollup-plugin-commonjs,將CommonJS模塊轉換成ES6,防止他們在Rollup中失效。
通過下面的命令安裝兩個插件:
npm install --save-dev rollup-plugin-node-resolve rollup-plugin-commonjs更新rollup.config.js.
然后,引入插件并添加進Rollup配置:
// Rollup plugins import babel from "rollup-plugin-babel"; import eslint from "rollup-plugin-eslint"; import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; export default { entry: "src/scripts/main.js", dest: "build/js/main.min.js", format: "iife", sourceMap: "inline", plugins: [ resolve({ jsnext: true, main: true, browser: true, }), commonjs(), eslint({ exclude: [ "src/styles/**", ] }), babel({ exclude: "node_modules/**", }), ], };
檢查控制臺輸出注意: jsnext屬性是為了幫助Node模塊遷移到ES2015的一部分。main和browser 屬性幫助插件決定哪個文件應該被bundle文件使用。
執行./node_modules/.bin/rollup -c重新打包,然后再檢查瀏覽器輸出:
成功了!日志現在打印出來了。
STEP 5: 添加插件替換環境變量環境變量使開發流程更強大,讓我們有能力做一些事情,比如打開或關閉日志,注入僅在開發環境使用的腳本等等。
那么讓Rollup支持這些功能吧。
在main.js中添加ENV變量讓我們通過一個環境變量控制日志腳本,讓日志腳本只能在非生產環境下使用。在src/scripts/main.js中修改log()的初始化方式。
// Import a logger for easier debugging. import debug from "debug"; const log = debug("app:log"); // The logger should only be disabled if we’re not in production. if (ENV !== "production") { // Enable the logger. debug.enable("*"); log("Logging is enabled!"); } else { debug.disable(); }
然而,重新打包(./node_modules/.bin/rollup -c)后檢查瀏覽器,會看到一個ENV的ReferenceError。
不必驚訝,因為我們沒有在任何地方定義它。如果我們嘗試ENV=production ./node_modules/.bin/rollup -c,還是不會成功。因為那樣設置的環境變量只是在Rollup中可用,不是在Rollup打包的bundle中可用。
我們需要使用一個插件將環境變量傳入bundle。
安裝模塊安裝rollup-plugin-replace插件,它本質上只是做了查找-替換的工作。它能做很多事情,但現在我們只需要讓它簡單地找到出現的環境變量并將其替換成實際的值。(比如,所有在bundle出現的ENV變量都會被替換成"production" )。
npm install --save-dev rollup-plugin-replace更新rollup.config.js
在rollup.config.js中引入插件并且添加到插件列表中。
配置非常簡單:只需添加一個鍵值對的列表,key是將被替換的字符串,value是應該被替換成的值。
// Rollup plugins import babel from "rollup-plugin-babel"; import eslint from "rollup-plugin-eslint"; import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; import replace from "rollup-plugin-replace"; export default { entry: "src/scripts/main.js", dest: "build/js/main.min.js", format: "iife", sourceMap: "inline", plugins: [ resolve({ jsnext: true, main: true, browser: true, }), commonjs(), eslint({ exclude: [ "src/styles/**", ] }), babel({ exclude: "node_modules/**", }), replace({ exclude: "node_modules/**", ENV: JSON.stringify(process.env.NODE_ENV || "development"), }), ], };
在我們的配置中,將找打所有出現的ENV并且替換成process.env.NODE_ENV - 在Node應用中最普遍的設置環境變量的方法 - 或者 "development"中的一個。使用JSON.stringify()確保值被雙引號包裹,如果ENV沒有的話。
為了確保不會和三方代碼造成問題,同樣設置exclude屬性來忽略node_modules目錄和其中的全部包。(幸虧@wesleycoder先在這上面踩坑了。)
檢查結果首先,重新打包然后在瀏覽器中檢查。控制臺日志會顯示,就像之前一樣。很棒 - 這意味著我們的默認值生效了。
為了展示新引入的能力,我們在production模式下運行命令:
NODE_ENV=production ./node_modules/.bin/rollup -c
注意: 在Windows上,使用SET NODE_ENV=production ./node_modules/.bin/rollup -c防止在設置環境變量時報錯。
當刷新瀏覽器后,控制臺沒有任何日志打出了:
不改變任何代碼的情況下,使用一個環境變量禁用了日志插件。
STEP 6: 添加UglifyJS壓縮減小生成代碼體積這個教程中最后一步是添加UglifyJS來減小和壓縮bundle文件。可以通過移除注釋,縮短變量名和其他壓縮換行等方式大幅度減少bundle的大小 - 會讓文件的可讀性變差,但提高了網絡間傳輸的效率。
安裝插件我們將使用UglifyJS壓縮bundle,通過rollup-plugin-uglify插件。
通過下面命令安裝:
npm install --save-dev rollup-plugin-uglify更新rollup.config.js
然后添加Uglify到Rollup配置。為了開發環境下可讀性更好,設置代碼丑化僅在生產環境下使用:
// Rollup plugins import babel from "rollup-plugin-babel"; import eslint from "rollup-plugin-eslint"; import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; import replace from "rollup-plugin-replace"; import uglify from "rollup-plugin-uglify"; export default { entry: "src/scripts/main.js", dest: "build/js/main.min.js", format: "iife", sourceMap: "inline", plugins: [ resolve({ jsnext: true, main: true, browser: true, }), commonjs(), eslint({ exclude: [ "src/styles/**", ] }), babel({ exclude: "node_modules/**", }), replace({ ENV: JSON.stringify(process.env.NODE_ENV || "development"), }), (process.env.NODE_ENV === "production" && uglify()), ], };
我們使用了短路運算,很常用(雖然也有爭議)的條件性設置值的方法。[注4]
在我們的例子中,只有在NODE_ENV是"production"時才會加載uglify()。
檢查壓縮過的bundle保存配置文件,讓我們在生成環境下運行Rollup:
NODE_ENV=production ./node_modules/.bin/rollup -c
注意: 在Windows上,使用SET NODE_ENV=production ./node_modules/.bin/rollup -c防止在設置環境變量時報錯。
輸出內容并不美觀,但是更小了。這有build/js/main.min.js的截屏,看起來像這樣:
丑化過的代碼確實能更高效地傳輸。
之前,我們的bundle大約42KB。使用UglifyJS后,減少到大約29KB - 在沒做其他優化的情況下節省了超過30%文件大小。
接下來的內容在這個系列的下一節,我們將了解通過Rollup和PostCSS處理樣式,并且添加live reloading來實時看見我們的修改。
Further Reading 擴展閱讀The cost of small modules - 這篇文章讓我開始對Rollup感興趣,因為它展示了一些Rollup相比webpack和Browserify的優勢。
Rollup’s getting started guide
Rollup’s CLI docs
A list of Rollup plugins
注1: 這是一個非常難理解的概念,所以沒全理解也不要有壓力。簡單來說,我們希望我們的代碼在他們自己的作用域中,防止和其它腳本的沖突。IIFE是一個包括我們的代碼在自身作用域的一個[閉包]。
注2:It’s important to keep in mind, though, that when we’re dealing with such a small example app it doesn’t take much to double a file size. The comparison at this point is ~3KB vs. ~8KB.
注3:作為曾經花數小時找bug然后發現拼錯一個變量名的人,不需要夸大使用linter帶來的效率提升。
注4:舉個例子,使用這種方法來賦默認值時非常常見的。(比如var foo = maybeThisExists || "default";)
這篇文章的代碼放在GitHub上。你可以fork 這個倉庫進行修改或測試,開issue或者報告bug,或者新建pull request進行建議或者修改。
原文鏈接
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/80976.html
摘要:通過這個教程學習如何使用打包工具配合來取代或處理樣式文件。使用這個命令安裝插件更新。如果你沒有項目的副本,你可以通過這條命令克隆在結束這個狀態下的項目為添加監聽插件。在代碼塊內,添加如下內容簡單起見我省略了文件的大部分內容 通過這個教程學習如何使用JavaScript打包工具Rollup配合PostCSS來取代Grunt或Gulp處理樣式文件。 上一篇文章中,我們完成了使用Rollup...
摘要:前端日報精選了解中的全局對象和全局作用域張鑫旭鑫空間鑫生活子進程你應該知道的一切直出內存泄露問題的追查實踐我他喵的到底要怎樣才能在生產環境中用上模塊化騰訊前端大會大咖說大咖干貨,不再錯過發布發布中文翻譯在使用進行本地開發代碼 2017-07-07 前端日報 精選 了解JS中的全局對象window.self和全局作用域self ? 張鑫旭-鑫空間-鑫生活Node.js 子進程:你應該知道...
摘要:既可以通過一個配置文件使用命令行接口來調用,也可以他自己的使用。使用最簡單的方法就是通過命令行接口。命令縮寫會以監視模式運行。這時運行下將不會有錯誤拋出,包含導入的組件。 介紹 概覽 rollup是一個js打包器,用來將很細碎的js編譯打包成大的復雜的東西,像是一個庫或者一個應用。其使用了ES6自帶的新標準來格式化和打包js代碼,而不是原先的Commonjs或者AMD這類解決方案。ES...
摘要:所以,打包工具就出現了,它可以幫助做這些繁瑣的工作。打包工具介紹僅介紹款主流的打包工具,,,,以發布時間為順序。它定位是模塊打包器,而屬于構建工具。而且在其他的打包工具在處理非網頁文件比如等基本還是需要借助它來實現。 本文當時寫在本地,發現換電腦很不是方便,在這里記錄下。 前端的打包工具 打包工具可以更好的管理html,css,javascript,使用可以錦上添花,不使用也沒關系...
摘要:為何有查閱了的文檔,并沒有找到字段的定義,直到才知道它是中最早就提出的概念。況且目前大部分仍是采用,所以便使用了另一個字段。所以目前主流的打包工具都是支持的,鑒于其優點,字段很有可能加入的規范之中。 引入 最近團隊的一個同學在搞 npm library 源碼的調試插件,因為內部的一個組件庫含有大量的邏輯,在某個項目中不經意就出現一個磨人的 bug,但是組件庫發布都是打包編譯后的代碼,而...
閱讀 2622·2021-10-08 10:04
閱讀 2741·2021-09-06 15:02
閱讀 820·2019-08-30 13:50
閱讀 1553·2019-08-30 13:21
閱讀 2592·2019-08-30 11:15
閱讀 2116·2019-08-29 17:19
閱讀 1584·2019-08-26 13:55
閱讀 1264·2019-08-26 10:15