webpack入門和實戰(一):webpack配置及技巧

1、全面理解webpack
一、什麼是 webpack?
webpack是近期最火的一款模塊加載器兼打包工具,它能把各類資源,例如JS(含JSX)、coffee、樣式(含less/sass)、圖片等都做爲模塊來使用和處理,它能有Grunt或Gulp全部基本功能。 webpack的官網是 https://webpack.github.io/  ,文檔地址是https://webpack.github.io/docs,官網對webpack的定義是MODULE BUNDLER,他的目的就是把有依賴關係的各類文件打包成一系列的靜態資源。 請看下圖:
二、webpack 的優點
其優點主要能夠歸類爲以下幾個:
  1. webpack 是以 commonJS 的形式來書寫腳本滴,但對 AMD/CMD 的支持也很全面,方便舊項目進行代碼遷移。
  2. 支持不少模塊加載器的調用,可使模塊加載器靈活定製,好比babel-loader加載器,該加載器能使咱們使用ES6的語法來編寫代碼;less-loader加載器,能夠將less編譯成css文件;
  3. 開發便捷,能替代部分 grunt/gulp 的工做,好比打包、壓縮混淆、圖片轉base64等。
  4. 能夠經過配置打包成多個文件,有效的利用瀏覽器的緩存功能提高性能。
三、wepback它的目標是是什麼?
webpack它能將依賴的模塊轉化成能夠表明這些包的靜態文件
  • 將依賴的模塊分片化,而且按需加載
  • 解決大型項目初始化加載慢的問題
  • 每個靜態文件均可以當作一個模塊
  • 能夠整合第三方庫
  • 可以在大型項目中運用
  • 能夠自定義切割模塊的方式

四、webpack較之其餘相似工具備什麼不一樣?css

  • 有同步和異步兩種不一樣的加載方式
  • Loader,加載器能夠將其餘資源整合到JS文件中,經過這種方式,能夠講全部的源文件造成一個模塊
  • 優秀的語法分析能力,支持 CommonJs AMD 規範
  • 有豐富的開源插件庫,能夠根據本身的需求自定義webpack的配置

五、webpack爲何要將全部資源放在一個文件裏面?html

咱們知道,對於瀏覽器來講,加載的資源越少,響應的速度也就越快,因此有時候咱們爲了優化瀏覽器的性能,會盡量的將資源合併到一個主文件app.js裏面。可是這致使的很大的缺點:vue

  • 當你的項目十分龐大的時候,不一樣的頁面不能作到按需加載,而是將全部的資源一併加載,耗費時間長,性能下降。
  • 會致使依賴庫之間關係的混亂,特別是大型項目時,會變得難以維護和跟蹤。好比:哪些文件是須要A模塊加載完後才能執行的?哪些頁面會受到多個樣式表同時影響的? 等許多問題。

而webpack能夠很好的解決以上缺點,由於它是一個十分聰明的模塊打包系統,當你正確配置後,它會比你想象中的更強大,更優秀。node

2、開啓wbpack之旅
安裝步驟以下:

一、生成package.json文件;jquery

先裝好node和npm,由於webpack是一個基於node的項目。而後首先咱們須要在根目錄下生成package.json文件,須要進入項目文件內根目錄下執行以下命令:npm init

如上經過一問一答的方式後會在根目錄下生成package.json文件,以下所示:webpack

2 . 經過全局安裝webpack
執行命令以下:npm install -g webpack 以下所示:
在c盤下會生成node_modules文件夾中會包含webpack,此時此刻咱們可使用webpack命令了;
在常規項目中把webpack依賴加入到package.json
npm init npm install webpack --save
更詳盡的安裝方法個能夠參考 webpack安裝
3. 配置webpack
每一個目錄下都必須有一個webpack.config.js,它的做用就比如Gulpfile.js、或者 Gruntfile.js,就是一個項目配置,告訴webpack須要作什麼。
首先先貼上一個比較完整的webpack.config.js的代碼,再詳細介紹:
//詳細的webpack.config.js結構分析:
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var TransferWebpackPlugin = require('transfer-webpack-plugin');

module.exports = {
    devtool: 'source-map',//因爲打包後的代碼是合併之後的代碼,不利於排錯和定位,只須要在config中添加,這樣出錯之後就會採用source-map的形式直接顯示你出錯代碼的位置。
    //noParse:[/jquery/],//表示跳過jquery,不對其進行編譯,這樣能夠提升打包的速度
    //頁面入口文件配置
    entry: {
        page1: "./src/index.js",
        //page2: ["./src/index.js", "./src/main.js"],支持數組形式,將加載數組中的全部模塊,但以最後一個模塊做爲輸出
    },
    //入口文件輸出配置
    output: {
        path: "dist/js/page",
        filename: "[name].bundle.js",// page1.bundle.js 和 page2.bundle.js,並存放到 ./dist/js/page 文件夾下。
        publicPath: "/dist/"	//網站運行時的訪問路徑。
    },
    resolveLoader: {
        //指定默認的loader路徑,不然依賴走到上游會找不到loader
        root: path.join(__dirname, 'node_modules'),
        alias: {//給本身寫的loader設置別名
            "seajs-loader": path.resolve( __dirname, "./web_modules/seajs-loader.js" )
        }
    },
    //新建一個開發服務器,而且當代碼更新的時候自動刷新瀏覽器。
    devServer: {
        historyApiFallback: true,
        noInfo: true,
        hot: true,
        inline: true,
        progress: true,
        port:9090 //端口你能夠自定義
    },
    module: {
        // module.loaders 是最關鍵的一塊配置。它告知 webpack每一種文件都須要使用什麼加載器來處理:
        loaders: [
        { test: /\.css$/, loader: 'style-loader!css-loader' },//.css 文件使用 style-loader 和 css-loader 來處理.
        //{ test: /\.css$/, loader: 'style!css' },其餘寫法一、"-loader"實際上是能夠省略不寫的,多個loader之間用「!」鏈接起來。
        //{ test: /\.css$/, loaders: ["style", "css"] },其餘寫法二、用loaders數組形式;
        //.scss 文件使用 style-loader、css-loader 和 sass-loader 來編譯處理。
        //在chrome中咱們經過sourcemap能夠直接調試less、sass源文件文件
        { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
        { test: /\.less$/, loader: 'style!css!less?sourceMap'},//.less 文件使用 style-loader、css-loader 和 less-loader 來編譯處理
        //.js 文件使用babel-loader來編譯處理,設置exclude用來排除node_modules這個文件夾中的代碼
        { test: /\.js$/, loader: 'babel!jsx',exclude: /node_modules/ }, 
        { test: /\.jsx$/, loader: "jsx-loader?harmony" },//.jsx 文件使用 jsx-loader 來編譯處理
        { test: /\.json$/,loader: 'json'},
        //{ test: /\.(png|jpg|jpeg|gif)$/, loader: 'url-loader?limit=8192'}, //圖片文件使用 url-loader 來處理,小於8kb的直接轉爲base64
        {test: /\.(png|jpg|gif|svg)$/,loader: 'url',
            query: {limit: 10000,name: '[name].[ext]?[hash]'}//設置圖片名稱擴展名
        },
        { test: /\.jade$/, loader: "jade-loader" },//.jade 文件使用 jade-loader 來編譯處理
        { test: /\.ejs$/, loader: "ejs-loader" },//.ejs 文件使用 ejs-loader 來編譯處理 
        { test: /\.handlebars$/, loader: "handlebars-loader" },//.handlebars 文件使用handlebars-loader來編譯處理handlebars模板文件
        { test: /\.dot$/, loader: "dot-loader" },//.dot 文件使用 dot-loader 來編譯處理dot模板文件
        { test: /\.vue$/, loader: "vue-loader" },//.vue 文件使用 vue-loader 來編譯處理
        { test: /\.coffee$/, loader: 'coffee-loader' },//.coffee 文件使用 coffee-loader 來編譯處理
        { test: /\.html$/,loader: 'vue-html'},
        { test: /\.woff$/,loader: "url?limit=10000&minetype=application/font-woff"},
        { test: /\.ttf$/,loader: "file"},
        { test: /\.eot$/,loader: "file"},
        { test: /\.svg$/,loader: "file"}
        ]
    },
    //份內置插件和外置插件
    plugins: [
        //使用了一個 CommonsChunkPlugin 的插件,它用於提取多個入口文件的公共腳本部分,而後生成一個common.js來方便多頁面之間進行復用。
  		new webpack.optimize.CommonsChunkPlugin('common.js'),
		new webpack.optimize.UglifyJsPlugin({//壓縮文件
	      compressor: {
	        warnings: false,//supresses warnings, usually from module minification
	      },
	      except: ['$super', '$', 'exports', 'require']    //排除關鍵字(可選)
	    }),
	    new webpack.DefinePlugin({// definePlugin 接收字符串插入到代碼當中, 因此你須要的話能夠寫上 JS 的字符串
             __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
             __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
        }),
        new webpack.ProvidePlugin({//把一個全局變量插入到全部的代碼中,支持jQuery plugin的使用;使用ProvidePlugin加載使用頻率高的模塊
             //provide $, jQuery and window.jQuery to every script
             $: "jquery",
             jQuery: "jquery",
             "window.jQuery": "jquery"
         }),
	    new webpack.NoErrorsPlugin(), //容許錯誤不打斷程序
	    new TransferWebpackPlugin([ //把指定文件夾下的文件複製到指定的目錄
	      {from: 'www'}
	    ], path.resolve(__dirname,"src")),
	    new HtmlwebpackPlugin({//用於生產符合要求的html文件;
	       title: 'Hello World app',
           filename: 'assets/admin.html'
	    })
	],
    //其它解決方案配置
    resolve: {
        root: 'E:/github/flux-example/src', //絕對路徑, 查找module的話從這裏開始查找(可選)
        extensions: ['', '.js', '.html', '.css', '.scss'], //自動擴展文件後綴名,意味着咱們require模塊能夠省略不寫後綴名
        alias: {                            //模塊別名定義,方便後續直接引用別名,無須多寫長長的地址//後續直接 require('AppStore') 便可
            AppStore : 'js/stores/AppStores.js',
            ActionType : 'js/actions/ActionType.js',
            AppAction : 'js/actions/AppAction.js'
        },
 		modulesDirectories: [//取相對路徑,因此比起 root ,因此會多不少路徑。查找module(可選)
             'node_modules',
             'bower_components',
             'lib',
             'src'
        ]
    }
	
};

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    //爲組件分配ID,經過這個插件webpack能夠分析和優先考慮使用最多的模塊,併爲它們分配最小的ID
    new webpack.optimize.OccurenceOrderPlugin()
  ])
}

plugins中包含不少的內置插件和外部插件,它們都有各自的功能,用來處理相關的文件,這裏只是羅列了部分,具體用法請看webpack入門和實戰(二):全面理解和運用plugins和loadergit

就像我在前面提到的,webpack.config.js的寫法和在Node裏的寫法相同,咱們主要看的就是文件中的module.exports裏面的內容
  • entry 是指入口文件的配置項,它是一個數組的緣由是webpack容許多個入口點。
  • output是指輸出文件的配置項
    • path - 表示輸出文件的路徑
    • filename - 表示輸出文件的文件名
  • plugins 顧名思義,使用插件能夠給webpack添加更多的功能,使webpack更加的靈活和強大,webpack有兩種類型的插件:
    • webpack內置的插件
// 首先要先安裝webpack模塊
var webpack = require("webpack");
module.exports = {
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false,
      },
    })
};
    •  webpack外置插件
//npm install component-webpack-plugin 先要在安裝該模版
var ComponentPlugin = require("component-webpack-plugin");
module.exports = {
    plugins: [
        new ComponentPlugin()
    ]
}

更多的插件以及插件的用法,你們能夠到webpack的插件上查看。github

  • module 配置處理文件的選項
    • loaders 一個含有wepback中能處理不一樣文件的加載器的數組
      • test 用來匹配相對應文件的正則表達式
      • loaders 告訴webpack要利用哪一種加載器來處理test所匹配的文件
    • loaders 的安裝方法
        $ npm install xxx-loader --save-dev
  • resolve:其它解決方案配置;
    • resolve.root,絕對路徑, 查找module的話從這裏開始查找(可選)
    • resolve.modulesDirectories,取相對路徑,因此比起 root ,因此會多 parse 不少路徑。查找module(可選)
    • resolve.extensions,自動擴展文件後綴名,意味着咱們require模塊能夠省略不寫後綴名
    • resolve.alias,模塊別名定義,方便後續直接引用別名,無須多寫長長的地址
3、利用webpack實如今頁面上合理使用打包事後的js文件和圖片
示例以下:
webpack_test目錄結構以下:
最終完成版的目錄結構爲:
 index.html代碼以下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo1</title>
</head>
<body>
    <div id="content"></div>
    <img src="./build/img/demo.png">
    <script src="./build/js/index.js"></script>
</body>
</html>

index.js代碼以下:web

require('./index.css');

index.css代碼以下:正則表達式

#content{
    width:121px;
    height:140px;
    background-color: red;
}
demo.png本身隨便找一張便可;
根據webpack.config.js的配置狀況,操做步驟以下:
  • 全局安裝webpack,npm install webpack -g
  • 進入到webpack_test目錄下,初始化生成package.json文件,npm init
  • 須要安裝的loader有css-loader、style-loader、url-loader,webpack, npm install css-loader style-loader url-loader webpack--save-dev
  • 執行webpack,生成打包事後的build/js/index.js,build/img/demo.png
  • 在index.html中引入便可

效果以下:

 源碼地址爲: http://download.csdn.net/detail/wdlhao/9612173,有須要的同窗能夠自行下載練習;
 4、理解webpack支持commonJS和AMD/CMD兩種模塊機制進行打包
  1.AMD/CMD模式:
     AMD 規範在這裏: https://github.com/amdjs/amdjs-api/wiki/AMD,CMD 規範在這裏: https://github.com/seajs/seajs/issues/242
  • AMD(Asynchronous Module Definition) 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。(即RequireJS模塊規範)
RequireJS是一個工具庫,主要用於客戶端的模塊管理。它可讓客戶端的代碼分紅一個個模塊,實現異步或動態加載,從而提升代碼的性能和可維護性。它的模塊管理遵照 AMD規範(Asynchronous Module Definition)。RequireJS的基本思想是,經過define方法,將代碼定義爲模塊;經過require方法,實現代碼的模塊加載。首先,將require.js嵌入網頁,而後就能在網頁中進行模塊化編程了。<script data-main="scripts/main" src="scripts/require.js"></script>上面代碼的data-main屬性不可省略,用於指定主代碼所在的腳本文件,在上例中爲scripts子目錄下的main.js文件。用戶自定義的代碼就放在這個main.js文件中。
  • CMD(Common Module Definition )是 SeaJS 在推廣過程當中對模塊定義的規範化產出。(即SeaJS模塊規範)
SeaJS是一個遵循CMD規範的JavaScript模塊加載框架,能夠實現JavaScript的模塊化開發及加載機制。
  • CommonJS Modules/2.0 規範,是 BravoJS 在推廣過程當中對模塊定義的規範化產出。
CommonJS API定義不少普通應用程序(主要指非瀏覽器的應用)使用的API,從而填補了這個空白。它的終極目標是提供一個相似Python,Ruby和Java標準庫。這樣的話,開發者可使用CommonJS API編寫應用程序,而後這些應用能夠運行在不一樣的JavaScript解釋器和不一樣的主機環境中。在兼容CommonJS的系統中,你能夠實用JavaScript程序開發:
  • 服務器端JavaScript應用程序
  • 命令行工具
  • 圖形界面應用程序
  • 混合應用程序(如,Titanium或Adobe AIR)

還有很多⋯⋯這些規範的目的都是爲了 JavaScript 的模塊化開發,特別是在瀏覽器端的。目前這些規範的實現都能達成瀏覽器端模塊化開發的目的。

 二、AMD/CMD模式區別

2.1從官方推薦的寫法上面得出:

CMD ----- 依賴就近

Js代碼 
//CMD 
define(function(require,exports,module){ 
   var a = require('./a'); 
   a.doSomthing(); 
});

AMD ----- 依賴前置

Js代碼 
//AMD 
define(['./a','./b'],function(a,b){ 
//...... 
a.doSomthing(); 
//...... 
b.doSomthing(); 
})

固然AMD也支持CMD的寫法。

2.二、執行順序上:

    • CMD是延遲執行,推崇的是as lazy as possible
    • AMD是提早執行,requireJS從2.0開始能夠延遲執行
2.三、api設計角度:
    • CMD的API推崇職責單一,沒有全局的require
    • AMD的API默認是一個當多個用:好比require有全局的和局部的
相關文章
相關標籤/搜索