国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

我他喵的到底要怎樣才能在生產環境中用上 ES6 模塊化?

KaltZK / 1849人閱讀

摘要:因此,你還是需要各種各樣雜七雜八的工具來轉換你的代碼噢,我可去你媽的吧,這些東西都是干嘛的我就是想用個模塊化,我到底該用啥子本文正旨在列出幾種可用的在生產環境中放心使用模塊化的方法,希望能幫到諸位后來者這方面的中文資源實在是忒少了。

原文發表在我的博客上。最近搗鼓了一下 ES6 的模塊化,分享一些經驗 :)

Python3 已經發布了九年了,Python 社區卻還在用 Python 2.7;而 JavaScript 社區正好相反,大家都已經開始把還沒有實現的語言特性用到生產環境中了 (′_ゝ `)

雖然這種奇妙情況的形成與 JavaScript 自身早期的設計缺陷以及瀏覽器平臺的特殊性質都有關系,但也確實能夠體現出 JavaScript 社區的技術棧迭代是有多么屌快。如果你昏迷個一年半載再去看前端圈,可能社區的主流技術棧已經變得它媽都不認識了(如果你沒什么實感,可以看看《在 2016 年學習 JavaScript 是一種怎樣的體驗》這篇文章,你會感受到的,你會的)。

JavaScript 模塊化現狀

隨著 JavaScript 越來越廣泛的應用,朝著單頁應用(SPA)方向發展的網頁與代碼量的愈發龐大,社區需要一種更好的代碼組織形式,這就是模塊化:將你的一大坨代碼分裝為多個不同的模塊。

但是在 ES6 標準出臺之前,由于標準的缺失(連 CSS 都有 @import,JavaScript 卻連個毛線都沒),這幾年里 JavaScript 社區里冒出了各種各樣的模塊化解決方案(群魔亂舞),懵到一種極致。主要的幾種模塊化方案舉例如下:

CommonJS

主要用于服務端,模塊同步加載(也因此不適合在瀏覽器中運行,不過也有 Browserify 之類的轉換工具),Node.js 的模塊化實現就是基于 CommonJS 規范的,通常用法像這樣:

// index.js
const {bullshit} = require("./bullshit");
console.log(bullshit());

// bullshit.js
function someBullshit() {
  return "hafu hafu";
}

modules.export = {
  bullshit: someBullshit
};

而且 require() 是動態加載模塊的,完全就是模塊中 modules.export 變量的傳送門,這也就意味著更好的靈活性(按條件加載模塊,參數可為表達式 etc.)。

AMD

即異步模塊定義(Asynchronous Module Definition),不是那個日常翻身的農企啦

主要用于瀏覽器端,模塊異步加載(還是用的回調函數),可以給模塊注入依賴、動態加載代碼塊等。具體實現有 RequireJS,代碼大概長這樣:

// index.js
require(["bullshit"], words => {
  console.log(words.bullshit());
});

// bullshit.js
define("bullshit", ["dep1", "dep2"], (dep1, dep2) => {
  function someBullshit() {
    return "hafu hafu";
  }

  return { bullshit: someBullshit };
});

可惜不能在 Node.js 中直接使用,而且模塊定義與加載也比較冗長。

ES6 Module?

在 ES6 模塊標準出來之前,主要的模塊化方案就是上述 CommonJS 和 AMD 兩種了,一種用于服務器,一種用于瀏覽器。其他的規范還有:

最古老的 IIFE(立即執行函數);

CMD(Common Module Definition,和 AMD 挺像的,可以參考:與 RequireJS 的異同);

UMD(Universal Module Definition,兼容 AMD 和 CommonJS 的語法糖規范);

等等,這里就按下不表。

ES6 的模塊化代碼大概長這樣:

// index.js
import {bullshit} from "./bullshit";
console.log(bullshit());

// bullshit.js
function someBullshit() {
  return "hafu hafu";
}

export {
  someBullshit as bullshit
};

那我們為啥應該使用 ES6 的模塊化規范呢?

這是 ECMAScript 官方標準(嗯);

語義化的語法,清晰明了,同時支持服務器端和瀏覽器;

靜態 / 編譯時加載(與上面倆規范的動態 / 運行時加載不同),可以做靜態優化(比如下面提到的 tree-shaking),加載效率高(不過相應地靈活性也降低了,期待 import() 也成為規范);

輸出的是值的引用,可動態修改;

嗯,你說的都對,那我tm到底要怎樣才能在生產環境中用上 ES6 的模塊化特性呢?

很遺憾,你永遠無法控制用戶的瀏覽器版本,可能要等上一萬年,你才能直接在生產環境中寫 ES6 而不用提心吊膽地擔心兼容性問題。因此,你還是需要各種各樣雜七雜八的工具來轉換你的代碼:Babel、Webpack、Browserify、Gulp、Rollup.js、System.js ……

噢,我可去你媽的吧,這些東西都tm是干嘛的?我就是想用個模塊化,我到底該用啥子?

本文正旨在列出幾種可用的在生產環境中放心使用 ES6 模塊化的方法,希望能幫到諸位后來者(這方面的中文資源實在是忒少了)。

問題分析

想要開心地寫 ES6 的模塊化代碼,首先你需要一個轉譯器(Transpiler)來把你的 ES6 代碼轉換成大部分瀏覽器都支持的 ES5 代碼。這里我們就選用最多人用的 Babel(我不久之前才知道原來 Babel 就是巴別塔里的「巴別」……)。

用了 Babel 后,我們的 ES6 模塊化代碼會被轉換為 ES5 + CommonJS 模塊規范的代碼,這倒也沒什么,畢竟我們寫的還是 ES6 的模塊,至于編譯生成的結果,管它是個什么屌東西呢(笑)

所以我們需要另外一個打包工具來將我們的模塊依賴給打包成一個 bundle 文件。目前來說,依賴打包應該是最好的方法了。不然,你也可以等上一萬年,等你的用戶把瀏覽器升級到全部支持 HTTP/2(支持連接復用后模塊不打包反而比較好)以及

而目前來看,主要可用的模塊打包工具有這么幾個:

Browserify

Webpack

Rollup.js

本來我還想講一下 FIS3 的,結果去看了一下,人家竟然還沒原生的支持 ES6 Modules,而且 fis3-hook-commonjs 插件也幾萬年沒更新了,所以還是算了吧。至于 SystemJS 這類動態模塊加載器本文也不會涉及,就像我上面說的一樣,在目前這個時間點上還是先用模塊打包工具比較好。

下面分別介紹這幾個工具以及如何使用它們配合 Babel 實現 ES6 模塊轉譯。

Browserify

Browserify 這個工具也是有些年頭了,它通過打包所有的依賴來讓你能夠在瀏覽器中使用 CommonJS 的語法來 require("modules"),這樣你就可以像在 Node.js 中一樣在瀏覽器中使用 npm 包了,可以爽到。而且我也很喜歡 Browserify 這個 LOGO

既然 Babel 會把我們的 ES6 Modules 語法轉換成 ES5 + CommonJS 規范的模塊語法,那我們就可以直接用 Browserify 來解析 Babel 的轉譯生成物,然后把所有的依賴給打包成一個文件,豈不是美滋滋。

不過除了 Babel 和 Browserify 這倆工具外,我們還需要一個叫做 babelify 的東西……好吧好吧,這是最后一個了,真的。

那么,babelify 是拿來干嘛的呢?因為 Browserify 只看得懂 CommonJS 的模塊代碼,所以我們得把 ES6 模塊代碼轉換成 CommonJS 規范的,再拿給 Browserify 去看:這一步就是 Babel 要干的事情了。但是 Browserify 人家是個模塊打包工具啊,它是要去分析 AST(抽象語法樹),把那些 reuqire() 的依賴文件給找出來再幫你打包的,你總不能把所有的源文件都給 Babel 轉譯了再交給 Browserify 吧?那太蠢了,我的朋友。

babelify (Browserify transform for Babel) 要做的事情,就是在所有 ES6 文件拿給 Browserify 看之前,先把它用 Babel 給轉譯一下(browserify().transform),這樣 Browserify 就可以直接看得懂并打包依賴,避免了要用 Babel 先轉譯一萬個文件的尷尬局面。

好吧,那我們要怎樣把這些工具搗鼓成一個完整的工具鏈呢?下面就是喜聞樂見的依賴包安裝環節:

# 我用的 yarn,你用 npm 也差不多
# gulp 也可以全局安裝,方便一點
# babel-preset 記得選適合自己的
# 最后那倆是用來配合 gulp stream 的
$ yarn add --dev babel-cli babel-preset-env babelify browserify gulp vinyl-buffer vinyl-source-stream

這里我們用 Gulp 作為任務管理工具來實現自動化(什么,都 7012 年了你還不知道 Gulp?那為什么不去問問神奇海螺呢?),gulpfile.js 內容如下:

var gulp       = require("gulp"),
    browserify = require("browserify"),
    babelify   = require("babelify"),
    source     = require("vinyl-source-stream"),
    buffer     = require("vinyl-buffer");

gulp.task("build", function () {
    return browserify(["./src/index.js"])
        .transform(babelify)
        .bundle()
        .pipe(source("bundle.js"))
        .pipe(gulp.dest("dist"))
        .pipe(buffer());
});

相信諸位都能看得懂吧,browserify() 第一個參數是入口文件,可以是數組或者其他亂七八糟的,具體參數說明請自行參照 Browserify 文檔。而且記得在根目錄下創建 .babelrc 文件指定轉譯的 preset,或者在 gulpfile.js 中配置也可以,這里就不再贅述。

最后運行 gulp build,就可以生成能直接在瀏覽器中運行的打包文件了。

?  browserify $ gulp build
[12:12:01] Using gulpfile E:wwwrootes6-module-testrowserifygulpfile.js
[12:12:01] Starting "build"...
[12:12:01] Finished "build" after 720 ms

Rollup.js

我記得這玩意最開始出來的時候號稱為「下一代的模塊打包工具」,并且自帶了可大大減小打包體積的 tree-shaking 技術(DCE 無用代碼移除的一種,運用了 ES6 靜態分析語法樹的特性,只打包那些用到了的代碼),在當時很新鮮。

但是現在 Webpack2+ 已經支持了 Tree Shaking 的情況下,我們又有什么特別的理由去使用 Rollup.js 呢?不過畢竟也是一種可行的方法,這里也提一提:

# 我也不知道為啥 Rollup.js 要依賴這個 external-helpers
$ yarn add --dev rollup rollup-plugin-babel babel-preset-env babel-plugin-external-helpers

然后修改根目錄下的 rollup.config.js

import babel from "rollup-plugin-babel";

export default {
  entry: "src/index.js",
  format: "esm",
  plugins: [
    babel({
      exclude: "node_modules/**"
    })
  ],
  dest: "dist/bundle.js"
};

還要修改 .babelrc 文件,把 Babel 轉換 ES6 模塊到 CommonJS 模塊的轉換給關掉,不然會導致 Rollup.js 處理不來:

{
  "presets": [
    ["env", {
      "modules": false
    }]
  ],
  "plugins": [
    "external-helpers"
  ]
}

然后在根目錄下運行 rollup -c 即可打包依賴,也可以配合 Gulp 來使用,官方文檔里就有,這里就不贅述了。可以看到,Tree Shaking 的效果還是很顯著的,經測試,未使用的代碼確實不會被打包進去,比起上面幾個工具生成的結果要清爽多了:

Webpack

對,Webpack,就是那個喪心病狂想要把啥玩意都給模塊化的模塊打包工具。既然人家已經到了 3.0.0 版本了,所以下面的都是基于 Webpack3 的。什么?現在還有搞前端的不知道 Webpack?神奇海螺以下略。

喜聞樂見的依賴安裝環節:

# webpack 也可以全局安裝,方便一些
$ yarn add --dev babel-loader babel-core babel-preset-env webpack

然后配置 webpack.config.js

var path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["env"]
          }
        }
      }
    ]
  }
};

差不多就是這么個配置,babel-loader 的其他 options 請參照文檔,而且這個配置文件的括號嵌套也是說不出話,ZTMJLWC。

然后運行 webpack

?  webpack $ webpack
Hash: 5c326572cf1440dbdf64
Version: webpack 3.0.0
Time: 1194ms
    Asset     Size  Chunks             Chunk Names
bundle.js  2.86 kB       0  [emitted]  main
   [0] ./src/index.js 106 bytes {0} [built]
   [1] ./src/bullshit.js 178 bytes {0} [built]

情況呢就是這么個情況:

Tips: 關于 Webpack 的 Tree Shaking

Webpack 現在是自帶 Tree-Shaking 的,不過需要你把 Babel 默認的轉換 ES6 模塊至 CommonJS 格式給關掉,就像上面 Rollup.js 那樣在 .babelrc 中添加個 "modules": false。原因的話上面也提到過,tree-shaking 是基于 ES6 模塊的靜態語法分析的,如果交給 Webpack 的是已經被 Babel 轉換成 CommonJS 的代碼的話那就沒戲了。

而且 Webpack 自帶的 tree-shaking 只是把沒用到的模塊從 export 中去掉而已,之后還要再接一個 UglifyJS 之類的工具把冗余代碼干掉才能達到 Rollup.js 那樣的效果。

Webpack 也可以配合 Gulp 工作流讓開發更嗨皮,有興趣的可自行研究。目前來看,這三種方案中,我本人更傾向于使用 Webpack,不知道諸君會選用什么呢?

寫在后面

前幾天我在搗鼓 printempw/blessing-skin-server 那坨 shi 一樣 JavaScript 代碼的模塊化的時候,打算試著使用一下 ES6 標準中的模塊化方案,并找了 Google 大老師問 ES6 模塊轉譯打包相關的資源,找了半天,幾乎沒有什么像樣的中文資源。全是講 ES6 模塊是啥、有多好、為什么要用之類的,沒幾個是講到底該怎么在生產環境中使用的(也有可能是我搜索姿勢不對),說不出話。遂撰此文,希望能幫到后來人。

且本人水平有限,如果文中有什么錯誤,歡迎在下方評論區批評指出。

參考鏈接

Getting import/export working ES6 style using Browserify + Babelify + Gulp = -5hrs of life

rollup.js ? guide

使用 webpack 2 tree-shaking 機制時需要注意的細節

webpack+babel 加載 es6 模塊

Documentation - webpack

如何評價 Webpack 2 新引入的 Tree-shaking 代碼優化技術?

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/83871.html

相關文章

  • 2017-07-07 前端日報

    摘要:前端日報精選了解中的全局對象和全局作用域張鑫旭鑫空間鑫生活子進程你應該知道的一切直出內存泄露問題的追查實踐我他喵的到底要怎樣才能在生產環境中用上模塊化騰訊前端大會大咖說大咖干貨,不再錯過發布發布中文翻譯在使用進行本地開發代碼 2017-07-07 前端日報 精選 了解JS中的全局對象window.self和全局作用域self ? 張鑫旭-鑫空間-鑫生活Node.js 子進程:你應該知道...

    import. 評論0 收藏0
  • 我用Python寫了一個郵箱腳本發給班花,沒想到事情鬧大了...

    摘要:大家好,我是辣條。最先審核沒通過,說我腳本涉嫌控制電腦違法違規,經過我再三的溝通之下,完整代碼刪除了,希望能通過審核。 大家好,我是辣條。? 前言 開學沒多久,事又多正愁缺寫博客的素材,這不馬上就來了,憨憨室友又要整活?,看在友(紅)情(包)的份上必須幫忙。 我起初的想法是通過郵箱發送表白...

    luckyyulin 評論0 收藏0
  • 前后端分離下的CAS跨域流程分析

    摘要:這種情況通常發生在反向代理的時候,前端發起請求代理服務器,代理服務器發起請求到,這時候就容易導致域名不一致,請一定要注意這點。 寫在最前 前后端分離其實有兩類: 開發階段使用dev-server,生產階段是打包成靜態文件整個放入后端項目中。 開發階段使用dev-server,生產階段是打包成靜態文件放入單獨的靜態資源服務器中,如nginx。 這兩種方案最大的區別就是生產階段。由于第...

    ckllj 評論0 收藏0
  • 前后端分離下的CAS跨域流程分析

    摘要:這種情況通常發生在反向代理的時候,前端發起請求代理服務器,代理服務器發起請求到,這時候就容易導致域名不一致,請一定要注意這點。 寫在最前 前后端分離其實有兩類: 開發階段使用dev-server,生產階段是打包成靜態文件整個放入后端項目中。 開發階段使用dev-server,生產階段是打包成靜態文件放入單獨的靜態資源服務器中,如nginx。 這兩種方案最大的區別就是生產階段。由于第...

    DevTalking 評論0 收藏0
  • 前后端分離下的CAS跨域流程分析

    摘要:這種情況通常發生在反向代理的時候,前端發起請求代理服務器,代理服務器發起請求到,這時候就容易導致域名不一致,請一定要注意這點。 寫在最前 前后端分離其實有兩類: 開發階段使用dev-server,生產階段是打包成靜態文件整個放入后端項目中。 開發階段使用dev-server,生產階段是打包成靜態文件放入單獨的靜態資源服務器中,如nginx。 這兩種方案最大的區別就是生產階段。由于第...

    jay_tian 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<