成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

也談 webpack 及其開(kāi)發(fā)模式

huhud / 2592人閱讀

摘要:比如通過(guò)安裝實(shí)例一新建一個(gè)然后編輯加入打開(kāi)瀏覽器,看到屏幕輸出會(huì)給每個(gè)模塊一個(gè)唯一的然后通過(guò)存取這些模塊,這些模塊都會(huì)被整合到里面。以上設(shè)置會(huì)輸出一個(gè)的文件。

從模塊化談起

近年來(lái),js開(kāi)發(fā)涌現(xiàn)出了諸多模塊化解決方案,例如以在瀏覽器環(huán)境之外(服務(wù)端)構(gòu)建 JavaScript 生態(tài)系統(tǒng)為目標(biāo)而產(chǎn)生的CommonJS規(guī)范,從CommonJS社區(qū)中獨(dú)立出來(lái)的AMD規(guī)范(異步模塊定義),還有國(guó)人制定的CMD規(guī)范等。隨著遵循AMD規(guī)范的RequireJS的流行,AMD規(guī)范在前端界已被廣泛認(rèn)同。后來(lái),隨著npm社區(qū)的逐漸壯大,CommonJS也越來(lái)越受歡迎,于是產(chǎn)生了統(tǒng)一這兩種規(guī)范的需求,即希望提供一個(gè)前后端跨平臺(tái)的解決方案,也因此產(chǎn)生了UMD(通用模塊定義)規(guī)范。

CommonJS定義的是模塊的同步加載,主要用于Node端;而遵循AMD規(guī)范的RequireJS則是異步加載,適用于瀏覽器端。requirejs是一種在線”編譯” 模塊的方案,相當(dāng)于在頁(yè)面上加載一個(gè)AMD 解釋器,以便于覽器能夠識(shí)別 define、exports、module,而這些東西就是用于模塊化的關(guān)鍵。

1. CommonJS 同步式的require

Node端的模塊加載遵循 CommonJS規(guī)范,該規(guī)范的核心思想是允許模塊通過(guò) require 方法來(lái)加載。

該規(guī)范首先加載所要依賴的其他模塊,然后通過(guò) exportsmodule.exports 來(lái)導(dǎo)出需要暴露的接口。但它的缺點(diǎn)也是顯而易見(jiàn)的,即一個(gè)文件一個(gè)文件的加載很容易發(fā)生阻塞。

require("module");//find from node_modules
require("../file.js");
exports.something = function() {};
module.exports = something;

2. 使你的模塊兼容AMD規(guī)范

//web.js
(function (root, factory) {
        //判斷define是否存在
    if (typeof define === "function" && define.amd) {
        // 存在則使用AMD方式加載模塊
        define(["b"], factory);
    } else {
        // 不存在則使用瀏覽器全局變量暴露模塊 
        root.web = factory(root.b);
    }
}(this, function (b) {
    //use b in some fashion.

    // Just return a value to define the module export.
    // This example returns an object, but the module
    // can return a function as the exported value.
    return {};
}));

定義一個(gè)叫web.js的模塊,依賴于另一個(gè)叫b的模塊。如果你不想支持瀏覽器全局路徑,那么你可以移除root并傳遞this參數(shù)在函數(shù)頂部。

3. define.amd屬性

為了清晰的標(biāo)識(shí)全局函數(shù)(為瀏覽器加載script必須的)遵從AMD編程接口,任何全局函數(shù)應(yīng)該有一個(gè)"amd"的屬性,它的值為一個(gè)對(duì)象。

關(guān)于RequireJS的使用不在本文范圍之內(nèi),因此不展開(kāi)講解,有興趣的請(qǐng)移步我的另一篇文章:

詳解JavaScript模塊化開(kāi)發(fā):https://segmentfault.com/a/1190000000733959#articleHeader15

AMD與異步加載

因?yàn)?b>CommonJS阻塞式的缺點(diǎn),所以并不適合前端。于是有了AMD異步加載模塊的規(guī)范。

Asynchronous Module Definition 規(guī)范其實(shí)只有一個(gè)主要接口 define(id?, dependencies?, factory),它要在聲明模塊的時(shí)候指定所有的依賴 dependencies,并且還要當(dāng)做形參傳到 factory 中,對(duì)于依賴的模塊提前執(zhí)行,依賴前置。

因?yàn)闉g覽器端的需求和同步require的問(wèn)題,所以社區(qū)引進(jìn)了異步模塊加載的規(guī)范,即AMD規(guī)范。

define("module", ["dep1", "dep2"], function(d1, d2) {
  return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });

使你的模塊兼容于UMD規(guī)范:

//UMD,兼容AMD和CommonJS規(guī)范
(function (root, factory) {
  if (typeof exports === "object") {
    // CommonJS
    module.exports = factory(require("b"));
  } else if (typeof define === "function" && define.amd) {
    // AMD
    define(["b"], function (b) {
      return (root.returnExportsGlobal = factory(b));
    });
  } else {
    // 瀏覽器全局變量,root即window
    root.returnExportsGlobal = factory(root.b);
  }
}(this, function (b) {
  // 你的實(shí)際模塊
  return {};
}));

UMD規(guī)范實(shí)現(xiàn)的思路:

首先判斷是否支持Node.js模塊格式,即exports對(duì)象是否存在。

然后判斷是否支持AMD格式(require是否存在),存在則使用AMD方式加載

若前兩個(gè)都不存在,則將模塊暴露到全局,Nodeglobal,瀏覽器即window。

例如,創(chuàng)建一個(gè)兼容UMD規(guī)范的jQuery插件:

// Uses CommonJS, AMD or browser globals to create a jQuery plugin.

(function (factory) {
    if (typeof define === "function" && define.amd) {
        // AMD. Register as an anonymous module.
        define(["jquery"], factory);
    } else if (typeof module === "object" && module.exports) {
        // Node/CommonJS
        module.exports = function( root, jQuery ) {
            if ( jQuery === undefined ) {
                // require("jQuery") returns a factory that requires window to
                // build a jQuery instance, we normalize how we use modules
                // that require this pattern but the window provided is a noop
                // if it"s defined (how jquery works)
                if ( typeof window !== "undefined" ) {
                    jQuery = require("jquery");
                }
                else {
                    jQuery = require("jquery")(root);
                }
            }
            factory(jQuery);
            return jQuery;
        };
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    $.fn.jqueryPlugin = function () { return true; };
CMD

Common Module Definition 規(guī)范和 AMD 很相似,盡量保持簡(jiǎn)單,并與 CommonJSNode.jsModules 規(guī)范保持了很大的兼容性。

define(function(require, exports, module) {
  var $ = require("jquery");
  var Spinning = require("./spinning");
  exports.doSomething = ...
  module.exports = ...
})

CMD規(guī)范地址:https://github.com/seajs/seajs/issues/242

ES6 module

ECMAScript6 內(nèi)建的用法:

import "jquery";
export function doStuff() {}
module "localModule" {}
為什么只載入JavaScript文件?

為什么模塊化系統(tǒng)只幫助開(kāi)發(fā)者處理JavaScript?然而還有其他靜態(tài)資源需要被處理,比如:

stylesheets
images
webfonts
html for templating
其他..
coffeescript ? javascript
less stylesheet ? css
jade ? html
i18n ? something
require("./style.css");
require("./style.less");
require("./template.jade");
require("./image.png");

因?yàn)樯厦孢@些動(dòng)機(jī),所以有了webpack

webpack

webpack是一款模塊封裝工具(module bundler,是打包工具,也是模塊加載工具,各種資源都可以當(dāng)成模塊來(lái)處理),webpack 會(huì)將模塊與其他相關(guān)聯(lián)的模塊,函數(shù)庫(kù),其他需要預(yù)編譯的文件等整合,編譯輸出此模塊的靜態(tài)資源文件。

// webpack.config.js `like=>`  gulpfile.js/gruntfile.js

module.exports = {
    entry: "./entry.js",
    output: {
        path: __dirname,
        filename: "bundle.js"
    },
    //module 對(duì)象用于添加loaders
    module: {
        //一個(gè)用于加載loader的數(shù)組
        loaders: [
            { test: /.css$/, loader: "style!css" }
        ]
    }
}; 

module具有如下屬性:

test: 需要滿足的條件A condition that must be met

exclude: 不需要滿足的條件A condition that must not be met

include: 需要滿足的條件A condition that must be met

loader: !用于分隔loaders

loaders: 一個(gè)loaders數(shù)組An array of loaders as string

"include" 通常被用于匹配目錄:

  include: [
    path.resolve(__dirname, "app/src"),
    path.resolve(__dirname, "app/test")
  ],

簡(jiǎn)單的說(shuō),webpack會(huì)把我們常用的 .less, .scss, .jade, .jsx 等等文件編譯成純 js + 圖片(圖片有時(shí)也可以被編譯成 base64 格式的 dataUrl)。

webpack的優(yōu)勢(shì)和特點(diǎn):

將依賴項(xiàng)分塊,按需加載

盡可能減少初始化載入的時(shí)間

使每一個(gè)靜態(tài)資源都能夠作為組件使用

有能力整合其他第三方函數(shù)庫(kù)為模塊

高度可配置化

適合大型項(xiàng)目

webpack擁有更聰明的解析工具可以處理幾乎所有的第三方函數(shù)庫(kù)。甚至允許在相依性設(shè)定上使用表達(dá)式,例如: require("./templates/" + name + ".jade"),這幾乎能處理大部分的模塊化標(biāo)準(zhǔn)(CommonJS, AMD)。

webpack常用命令
webpack 最基本的啟動(dòng)webpack命令
webpack -w 提供watch方法,實(shí)時(shí)進(jìn)行打包更新
webpack -p 對(duì)打包后的文件進(jìn)行壓縮
webpack -d 提供SourceMaps,方便調(diào)試
webpack --colors 輸出結(jié)果帶彩色,比如:會(huì)用紅色顯示耗時(shí)較長(zhǎng)的步驟
webpack --profile 輸出性能數(shù)據(jù),可以看到每一步的耗時(shí)
webpack --display-modules 默認(rèn)情況下 node_modules 下的模塊會(huì)被隱藏,加上這個(gè)參數(shù)可以顯示這些被隱藏的模塊
在項(xiàng)目中使用webpack

首先在項(xiàng)目根目錄新建一個(gè)package.json或者通過(guò)$ npm init指令來(lái)產(chǎn)生:

接著通過(guò)npm指令安裝webpack

$ npm install webpack --save-dev

or => $ cnpm i webpack -g

單純的編譯指令

$ webpack  
配置對(duì)象內(nèi)容

context:用來(lái)指明entry選項(xiàng)的基礎(chǔ)目錄(絕對(duì)路徑)。默認(rèn)值為process.cmd(),即webpack.config.js文件所在路徑

對(duì)象entry

定義了打包后的入口文件,可以是數(shù)組(所有文件打包生成一個(gè)filename文件),對(duì)象或者字符串

{
    entry: {
        page1: "./page1",
        page2: ["./entry1", "./entry2"]
    },
    output: {
        // 在 output.filename 中使用 [name]或者[id],當(dāng)使用多個(gè)entry points時(shí)
        filename: "[name].bundle.js",
        path: "dist/js/page",
        chunkFilename: "[id].bundle.js" //chunkFilename是非主入口的文件名
    }
}

該段代碼最終會(huì)生成一個(gè)page1.bundle.jspage2.bundle.js,并存放到 ./dist/js/page 文件夾下

chunkFilename是非主入口的文件名,當(dāng)按需異步加載模塊的時(shí)候,這時(shí)生成的文件名是以chunkname配置的

output:該參數(shù)是個(gè)對(duì)象,定義了輸出文件的位置及名字:

path: 打包文件存放的絕對(duì)路徑

publicPath: 網(wǎng)站運(yùn)行時(shí)的訪問(wèn)路徑URL

filename:打包后的文件名

你可以使用= 的格式來(lái)替代 entry point 建立一個(gè)別名:

// webpack.config.js
module.exports = {
  output: {
    filename: "[name].bundle.js"
  }
}

接著執(zhí)行如下命令:

$ webpack index=./entry.js
>> Output a file that is named index.bundle.js

對(duì)象output

表示欲輸出的路徑,其會(huì)被映射到設(shè)定檔中的 output.path 以及 output.filename

output.filename:指定每一個(gè)在磁盤(pán)上輸出的文件名,不允許指定絕對(duì)路徑

output.path:輸出絕對(duì)路徑目錄(必須)

output.publicPath:指定在瀏覽器端引用的文件公開(kāi)URL地址

對(duì)象resolve

webpack在構(gòu)建包的時(shí)候會(huì)按目錄進(jìn)行文件的查找,resolve屬性中的extensions數(shù)組可用于配置程序可以自行補(bǔ)全哪些文件后綴。extensions 第一個(gè)是空字符串,對(duì)應(yīng)不需要后綴的情況。比如,為了查找CoffeeScript文件,你的數(shù)組應(yīng)當(dāng)包含字符串".coffee"。使用extensions,在引入模塊的時(shí)候就不需要寫(xiě)后綴,會(huì)自動(dòng)補(bǔ)全

resolve: {
        extensions: ["", ".js", ".jsx",".es6","css","scss","png","jpg"]
    },

resolve.alias 定義別名

alias:{
       "react-dom":path.join(nodeModulesPath,"/dist/react-dom"),
        "redux": path.join(nodeModulesPath,"dist/redux")
    },

對(duì)象externals

當(dāng)我們想在項(xiàng)目中require一些其他的類庫(kù)或者API,而又不想讓這些類庫(kù)的源碼被構(gòu)建到運(yùn)行時(shí)文件中,
這在實(shí)際開(kāi)發(fā)中很有必要。此時(shí)我們就可以通過(guò)配置externals參數(shù)來(lái)解決這個(gè)問(wèn)題:

 externals: {
     "jquery": "jQuery"
 }

這樣我們就可以放心的在項(xiàng)目中使用這些API了:

var $ = require(“jquery”);

配置項(xiàng)詳情:https://webpack.github.io/docs/configuration.html

css樣式和圖片的加載

你可以在你的js文件里引入css文件和圖片,例如:

require("./bootstrap.css");
require("./style.less");
require("../../main.scss");

var img = document.createElement("img");
img.src = require("./myImg.png");

當(dāng)你require了CSS(less或者其他)文件,webpack會(huì)在頁(yè)面中插入一個(gè)內(nèi)聯(lián)的