摘要:比如通過安裝實(shí)例一新建一個然后編輯加入打開瀏覽器,看到屏幕輸出會給每個模塊一個唯一的然后通過存取這些模塊,這些模塊都會被整合到里面。以上設(shè)置會輸出一個的文件。
從模塊化談起
近年來,js開發(fā)涌現(xiàn)出了諸多模塊化解決方案,例如以在瀏覽器環(huán)境之外(服務(wù)端)構(gòu)建 JavaScript 生態(tài)系統(tǒng)為目標(biāo)而產(chǎn)生的CommonJS規(guī)范,從CommonJS社區(qū)中獨(dú)立出來的AMD規(guī)范(異步模塊定義),還有國人制定的CMD規(guī)范等。隨著遵循AMD規(guī)范的RequireJS的流行,AMD規(guī)范在前端界已被廣泛認(rèn)同。后來,隨著npm社區(qū)的逐漸壯大,CommonJS也越來越受歡迎,于是產(chǎn)生了統(tǒng)一這兩種規(guī)范的需求,即希望提供一個前后端跨平臺的解決方案,也因此產(chǎn)生了UMD(通用模塊定義)規(guī)范。
CommonJS定義的是模塊的同步加載,主要用于Node端;而遵循AMD規(guī)范的RequireJS則是異步加載,適用于瀏覽器端。requirejs是一種在線”編譯” 模塊的方案,相當(dāng)于在頁面上加載一個AMD 解釋器,以便于覽器能夠識別 define、exports、module,而這些東西就是用于模塊化的關(guān)鍵。
1. CommonJS 同步式的require
Node端的模塊加載遵循 CommonJS規(guī)范,該規(guī)范的核心思想是允許模塊通過 require 方法來加載。
該規(guī)范首先加載所要依賴的其他模塊,然后通過 exports 或 module.exports 來導(dǎo)出需要暴露的接口。但它的缺點(diǎn)也是顯而易見的,即一個文件一個文件的加載很容易發(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 {}; }));
定義一個叫web.js的模塊,依賴于另一個叫b的模塊。如果你不想支持瀏覽器全局路徑,那么你可以移除root并傳遞this參數(shù)在函數(shù)頂部。
3. define.amd屬性
為了清晰的標(biāo)識全局函數(shù)(為瀏覽器加載script必須的)遵從AMD編程接口,任何全局函數(shù)應(yīng)該有一個"amd"的屬性,它的值為一個對象。
關(guān)于RequireJS的使用不在本文范圍之內(nèi),因此不展開講解,有興趣的請移步我的另一篇文章:
AMD與異步加載詳解JavaScript模塊化開發(fā):https://segmentfault.com/a/1190000000733959#articleHeader15
因?yàn)?b>CommonJS阻塞式的缺點(diǎn),所以并不適合前端。于是有了AMD異步加載模塊的規(guī)范。
Asynchronous Module Definition 規(guī)范其實(shí)只有一個主要接口 define(id?, dependencies?, factory),它要在聲明模塊的時候指定所有的依賴 dependencies,并且還要當(dāng)做形參傳到 factory 中,對于依賴的模塊提前執(zhí)行,依賴前置。
因?yàn)闉g覽器端的需求和同步require的問題,所以社區(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對象是否存在。
然后判斷是否支持AMD格式(require是否存在),存在則使用AMD方式加載
若前兩個都不存在,則將模塊暴露到全局,Node即global,瀏覽器即window。
例如,創(chuàng)建一個兼容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 很相似,盡量保持簡單,并與 CommonJS 和 Node.js 的 Modules 規(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 moduleECMAScript6 內(nèi)建的用法:
import "jquery"; export function doStuff() {} module "localModule" {}為什么只載入JavaScript文件?
為什么模塊化系統(tǒng)只幫助開發(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)樯厦孢@些動機(jī),所以有了webpack。
webpackwebpack是一款模塊封裝工具(module bundler,是打包工具,也是模塊加載工具,各種資源都可以當(dāng)成模塊來處理),webpack 會將模塊與其他相關(guān)聯(lián)的模塊,函數(shù)庫,其他需要預(yù)編譯的文件等整合,編譯輸出此模塊的靜態(tài)資源文件。
// webpack.config.js `like=>` gulpfile.js/gruntfile.js module.exports = { entry: "./entry.js", output: { path: __dirname, filename: "bundle.js" }, //module 對象用于添加loaders module: { //一個用于加載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: 一個loaders數(shù)組An array of loaders as string
"include" 通常被用于匹配目錄:
include: [ path.resolve(__dirname, "app/src"), path.resolve(__dirname, "app/test") ],
簡單的說,webpack會把我們常用的 .less, .scss, .jade, .jsx 等等文件編譯成純 js + 圖片(圖片有時也可以被編譯成 base64 格式的 dataUrl)。
webpack的優(yōu)勢和特點(diǎn):
將依賴項(xiàng)分塊,按需加載
盡可能減少初始化載入的時間
使每一個靜態(tài)資源都能夠作為組件使用
有能力整合其他第三方函數(shù)庫為模塊
高度可配置化
適合大型項(xiàng)目
webpack擁有更聰明的解析工具可以處理幾乎所有的第三方函數(shù)庫。甚至允許在相依性設(shè)定上使用表達(dá)式,例如: require("./templates/" + name + ".jade"),這幾乎能處理大部分的模塊化標(biāo)準(zhǔn)(CommonJS, AMD)。
webpack常用命令webpack 最基本的啟動webpack命令 webpack -w 提供watch方法,實(shí)時進(jìn)行打包更新 webpack -p 對打包后的文件進(jìn)行壓縮 webpack -d 提供SourceMaps,方便調(diào)試 webpack --colors 輸出結(jié)果帶彩色,比如:會用紅色顯示耗時較長的步驟 webpack --profile 輸出性能數(shù)據(jù),可以看到每一步的耗時 webpack --display-modules 默認(rèn)情況下 node_modules 下的模塊會被隱藏,加上這個參數(shù)可以顯示這些被隱藏的模塊在項(xiàng)目中使用webpack
首先在項(xiàng)目根目錄新建一個package.json或者通過$ npm init指令來產(chǎn)生:
接著通過npm指令安裝webpack:
$ npm install webpack --save-dev or => $ cnpm i webpack -g
單純的編譯指令
$ webpack配置對象內(nèi)容
context:用來指明entry選項(xiàng)的基礎(chǔ)目錄(絕對路徑)。默認(rèn)值為process.cmd(),即webpack.config.js文件所在路徑
對象entry
定義了打包后的入口文件,可以是數(shù)組(所有文件打包生成一個filename文件),對象或者字符串
{ entry: { page1: "./page1", page2: ["./entry1", "./entry2"] }, output: { // 在 output.filename 中使用 [name]或者[id],當(dāng)使用多個entry points時 filename: "[name].bundle.js", path: "dist/js/page", chunkFilename: "[id].bundle.js" //chunkFilename是非主入口的文件名 } }
該段代碼最終會生成一個page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夾下
chunkFilename是非主入口的文件名,當(dāng)按需異步加載模塊的時候,這時生成的文件名是以chunkname配置的
output:該參數(shù)是個對象,定義了輸出文件的位置及名字:
path: 打包文件存放的絕對路徑
publicPath: 網(wǎng)站運(yùn)行時的訪問路徑URL
filename:打包后的文件名
你可以使用
// webpack.config.js module.exports = { output: { filename: "[name].bundle.js" } }
接著執(zhí)行如下命令:
$ webpack index=./entry.js >> Output a file that is named index.bundle.js
對象output
表示欲輸出的路徑,其會被映射到設(shè)定檔中的 output.path 以及 output.filename
output.filename:指定每一個在磁盤上輸出的文件名,不允許指定絕對路徑
output.path:輸出絕對路徑目錄(必須)
output.publicPath:指定在瀏覽器端引用的文件公開URL地址
對象resolve
webpack在構(gòu)建包的時候會按目錄進(jìn)行文件的查找,resolve屬性中的extensions數(shù)組可用于配置程序可以自行補(bǔ)全哪些文件后綴。extensions 第一個是空字符串,對應(yīng)不需要后綴的情況。比如,為了查找CoffeeScript文件,你的數(shù)組應(yīng)當(dāng)包含字符串".coffee"。使用extensions,在引入模塊的時候就不需要寫后綴,會自動補(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") },
對象externals
當(dāng)我們想在項(xiàng)目中require一些其他的類庫或者API,而又不想讓這些類庫的源碼被構(gòu)建到運(yùn)行時文件中,
這在實(shí)際開發(fā)中很有必要。此時我們就可以通過配置externals參數(shù)來解決這個問題:
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會在頁面中插入一個內(nèi)聯(lián)的標(biāo)簽去引入樣式。當(dāng)你require圖片的時候,bundle文件會包含圖片的url,并通過require()返回圖片的url。
當(dāng)然,你需要在webpack.config.js里做相應(yīng)的配置:
// webpack.config.js module.exports = { entry: "./entry.js",//入口文件 output: { path: "./build", // 輸出js和圖片的目錄 publicPath: "http://mycdn.com/", // 用來生成圖片的地址 filename: "bundle.js" }, module: { loaders: [ { test: /.less$/, loader: "style-loader!css-loader!less-loader" }, // 用!去鏈?zhǔn)秸{(diào)用loader { test: /.css$/, loader: "style-loader!css-loader" }, { test: /.scss$/,loaders: ["style", "css", "sass"]} {test: /.(png|jpg)$/, loader: "url-loader?limit=8192"} // 內(nèi)聯(lián)的base64的圖片地址,圖片要小于8k,直接的url的地址則不解析 ] } };
當(dāng)然,你需要先通過npm包來安裝這些loader,webpack會通過test查找匹配文件,然后加載相應(yīng)的loader。比如通過npm安裝sass loader:
$ npm install sass-loader node-sass webpack --save-dev實(shí)例一
新建一個content.js
// content.js module.exports = "It works from content.js";
然后編輯 entry.js 加入 require
// File: entry.js document.write(require("./content.js"));
打開瀏覽器,看到屏幕輸出:"It works from content.js";
Webpack 會給每個模塊一個唯一的 ID 然后通過 ID 存取這些模塊,這些模塊都會被整合到 bundle.js 里面。
webpack插件和使用方法介紹1. CommonsChunkPlugin合并公共代碼
它用于提取多個入口文件的公共腳本部分,然后生成一個 公共文件來方便多頁面之間進(jìn)行復(fù)用。以下是該插件的使用方法和webpack的具體用法介紹:
var webpack = require("webpack"); var path = require("path"); var commonsPlugin = new webpack.optimize.CommonsChunkPlugin("common.js"); var config = { //Webpack 本身內(nèi)置了一些常用的插件,還可以通過 npm 安裝第三方插件。 plugins: [commonsPlugin], //頁面入口文件配置 entry: { index : "./index.js" }, //入口文件輸出配置 output: { path: "dist/js/page", filename: "[name].js" }, //module 的作用是添加loaders module: { //加載器配置 loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /.css$/, loader: "style-loader!css-loader" },//test屬性匹配css文件 //.js 文件使用 jsx-loader 來編譯處理 { test: /.js$/, loader: "jsx-loader?harmony" }, //.scss 文件使用 style-loader、css-loader 和 sass-loader 來編譯處理 { test: /.scss$/, loader: "style!css!sass?sourceMap"}, //圖片文件使用 url-loader 來處理,小于8kb的直接轉(zhuǎn)為base64 { test: /.(png|jpg)$/, loader: "url-loader?limit=8192"}, {//處理字體 test: /.(woff2?|otf|eot|svg|ttf)$/i, }, loader: "style!css"http://加載style和css loader ] }, //其它解決方案配置 resolve: { root: "/Users/trigkit4/webpack", //絕對路徑 extensions: ["", ".js", ".json", ".scss"],//文件擴(kuò)展名 //模塊別名定義,方便后續(xù)直接引用別名 alias: { a : "./assets/a.js", // require(“a”)即可引用該模塊 b : "./assets/b.js", c : "./assets/c.js" } } }; module.exports = config;
Webpack中將打包后的文件都稱之為Chunk。這個插件可以將多個打包后的資源中的公共部分打包成多帶帶的文件。這里指定公共文件輸出為common.js
Webpack 本身只能處理 JavaScript 模塊,如果要處理其他類型的文件,就需要使用loader進(jìn)行轉(zhuǎn)換。
不同模塊的加載是通過模塊加載器(webpack-loader)來統(tǒng)一管理的。
!用來定義loader的串聯(lián)關(guān)系,”-loader”是可以省略不寫的,多個loader之間用“!”連接起來,但所有的加載器都需要通過npm來加載。
2. UglifyJsPlugin壓縮js文件
//webpack.config.js //...other webpack settings plugins: [ new Webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ]
3. Extract Text Plugin
大家都知道在 webpack 中 CSS 是可以被 require() 的,webpack 會自動生成一個 標(biāo)簽并加入到 html 的 標(biāo)簽 中。但是在發(fā)布時,我們可能只希望有一個被打包過后 css 文件。這時 Extract Text Plugin 就能幫助我們完成這項(xiàng)任務(wù)。
//webpack.config.js var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { module: { loaders: [ { test: /.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") } ] }, plugins: [ new ExtractTextPlugin("app.bundle.css") ] }
以上設(shè)置會輸出一個 app.bundle.css 的文件。
4. html-webpack-plugin
webpack中生成HTML的插件。
var HtmlWebpackPlugin = require("html-webpack-plugin") var webpackConfig = { entry: "index.js", output: { path: "dist", filename: "index_bundle.js" }, plugins: [ new HtmlWebpackPlugin({ //根據(jù)模板插入css/js等生成最終HTML favicon: "./src/img/favicon.ico", //favicon路徑,通過webpack引入同時可以生成hash值 filename: "./view/about.html", //生成的html存放路徑,相對于path template: "./src/view/about.html", //html模板路徑 inject: true, //js插入的位置,true/"head"/"body"/false hash: true, //為靜態(tài)資源生成hash值 chunks: ["vendors", "about"],//需要引入的chunk,不配置就會引入所有頁面的資源 minify: { //壓縮HTML文件 removeComments: true, //移除HTML中的注釋 collapseWhitespace: false //刪除空白符與換行符 } }), ] }
詳情:https://www.npmjs.com/package/html-webpack-plugin
5. ProvidePlugin
plugins: [ new webpack.ProvidePlugin({ React: "react", ReactDOM: "react-dom" }) ]
ProvidePlugin 插件可以定義一個共用的插件入口,以后的文件就不需要require("react")也能使用React了。
6. babel loader
Babel-loader能夠?qū)?b>JSX/ES6 文件轉(zhuǎn)為js文件
$ npm install babel-loader babel-core babel-preset-es2015 babel-preset-react --save-dev
配置:
module.exports = { entry: {}, //文件入口 output: { }, //輸出出口 module: { loaders: [ { test:/.js[x]?$/, loader: "babel-loader", exclude:/node_modules/, query:{presets: ["es2015","react"]} }, ] }, plugins: [ ],//編譯的時候所執(zhí)行的插件數(shù)組 devtool : "source-map" //調(diào)試模式 };
插件列表:http://webpack.github.io/docs/list-of-plugins.html
開發(fā)服務(wù)器安裝Webpack開發(fā)服務(wù)器需要多帶帶安裝,同樣是通過npm進(jìn)行:
$ sudo npm install -g webpack-dev-server
可以使用webpack-dev-server直接啟動,也可以增加參數(shù)來獲取更多的功能,
具體配置可以參見官方文檔。在終端輸入:
$ webpack-dev-server
然后打開:http://localhost:8080/webpack-dev-server/index.html
在webpack.config.js里配置:
//使用webpack-dev-server,提高開發(fā)效率 module.exports={ devServer: { contentBase: "./", host: "localhost", port: 9090, //默認(rèn)8080 inline: true, //可以監(jiān)控js變化 hot: true, //熱啟動 } }
詳情:https://webpack.github.io/docs/webpack-dev-server.html
使用browser-sync實(shí)時刷新頁面如果每次更改代碼都要重新執(zhí)行webpack命令不免太過麻煩,所以這里推薦使用browser-sync-webpack-plugin,可以監(jiān)聽代碼變化,實(shí)時刷新頁面。
安裝browser-sync-webpack-plugin:
$ npm install --save-dev browser-sync-webpack-plugin $ webpack --watch
webpack.config.js配置:
var BrowserSyncPlugin = require("browser-sync-webpack-plugin"); module.exports = { // ... plugins: [ new BrowserSyncPlugin({ // browse to http://localhost:3000/ during development, // ./public directory is being served host: "localhost", port: 3000, server: { baseDir: ["public"] } //根目錄就填"./" }) ] }實(shí)例二:react+webpack+es6開發(fā)模式
具體項(xiàng)目地址請移步:https://github.com/hawx1993/react-webpack-demos
在線DEMO:http://hawx1993.github.io/react-webpack-es6-demos
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/79742.html
摘要:在前幾天的阿里內(nèi)部交流活動上,我們的馬總也與其員工討論了話題,包括自己創(chuàng)辦阿里的成長過程。馬總的一番話點(diǎn)醒了一批互聯(lián)網(wǎng)行業(yè)的我們。馬總說馬云提到,能做是一種巨大的福氣,很多公司很多人想都沒有機(jī)會。 最近的一個996話題在互聯(lián)網(wǎng)業(yè)界,可以說是非常的火熱。身為互聯(lián)網(wǎng)人,也在時時關(guān)注的,畢竟和我們的生活息息相關(guān)。在前幾天的阿里內(nèi)部交流活動上,我們的馬總也與其員工討論了996話題,包括自己創(chuàng)辦...
摘要:平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。年以前看這個網(wǎng)址概況在線地址前端開發(fā)群月報提交原則技術(shù)文章新的為主。 平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個網(wǎng)址:http://www.kancloud.cn/jsfron... 概況 在線地址:http://www.kancloud.cn/jsfront/month/82796 JS前端開發(fā)群月報 提交原則: 技...
摘要:平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。年以前看這個網(wǎng)址概況在線地址前端開發(fā)群月報提交原則技術(shù)文章新的為主。 平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個網(wǎng)址:http://www.kancloud.cn/jsfron... 概況 在線地址:http://www.kancloud.cn/jsfront/month/82796 JS前端開發(fā)群月報 提交原則: 技...
閱讀 2212·2021-11-22 13:52
閱讀 3847·2021-11-10 11:36
閱讀 1380·2021-09-24 09:47
閱讀 1088·2019-08-29 13:54
閱讀 3360·2019-08-29 13:46
閱讀 1942·2019-08-29 12:16
閱讀 2108·2019-08-26 13:26
閱讀 3471·2019-08-23 17:10