webpack快速掌握教程

轉載http://yijiebuyi.com/blog/46fb97b11fb8f4055e0b04d1cecb1f69.htmljavascript

#爲何用webpackcss

若是咱們 前端 javascript 能像 node.js 同樣 require 去引用一個依賴包,那麼前端的世界就不會像如今這麼亂html

如今爲何亂?前端


假設: a.js 依賴 b.js b.js 依賴 c.js c.js 依賴 d.jsjava


若是在咱們前端去引用這些依賴的時候,每每是這樣的:node

<script src='a.js'></script>
<script src='b.js'></script>
<script src='c.js'></script>
<script src='d.js'></script>

上面的引用方式形成一個問題webpack

不亂你進入哪一個頁面,這些js 都要去加載…形成沒必要要的浪費es6

下面咱們來介紹 webpackweb

CommonJs與AMD

在一開始,咱們先講一下它和以往咱們所用的模塊管理工具備什麼不同。在最開始的階段,Js並無這些模塊機制,各類Js處處飛,得不到有效妥善的管理。後來前端圈開始制定規範,最耳熟能詳的是CommonJs和AMD。正則表達式

CommonJs是應用在NodeJs,是一種同步的模塊機制。它的寫法大體以下:

var firstModule = require("firstModule");

//your code...

module.export = anotherModule

AMD的應用場景則是瀏覽器,異步加載的模塊機制。require.js的寫法大體以下:

define(['firstModule'], function(module){
   
   //your code...
   return anotherModule
})

其實咱們單比較寫法,就知道CommonJs是更爲優秀的。它是一種同步的寫法,對Human友好,並且代碼也不會繁瑣臃腫。但更重要的緣由是,隨着npm成爲主流的JavaScript組件發佈平臺,愈來愈多的前端項目也依賴於npm上的項目,或者自身就會發布到npm平臺。因此咱們對如何可使用npm包中的模塊是咱們的一大需求。因此browserify工具就出現了,它支持咱們直接使用require()的同步語法去加載npm模塊。

固然咱們這裏不得不說的是,ES2015(ES6)裏也有了本身的模塊機制,也就是說ES6的模塊機制是官方規定的,咱們經過babel(一種6to5的編譯器)可使用比較多的新特性了,包括咱們提到的模塊機制,而它的寫法大體以下:

import {someModule} from "someModule";

// your codes...

export anotherModule;

固然上面的寫法只是最基本的,還有其餘的不一樣加載模塊的寫法,能夠看一下阮一峯老師的ECMAScript 6 入門或者babel的相關文檔Learn ES2015。

功能特性

browserify的出現很是棒,但webpack更勝一籌!

咱們來看看webpack支持哪些功能特性:

  • 支持CommonJs和AMD模塊,意思也就是咱們基本能夠無痛遷移舊項目。
  • 支持模塊加載器和插件機制,可對模塊靈活定製。特別是我最愛的babel-loader,有效支持ES6。
  • 能夠經過配置,打包成多個文件。有效利用瀏覽器的緩存功能提高性能。
  • 將樣式文件和圖片等靜態資源也可視爲模塊進行打包。配合loader加載器,能夠支持sass,less等CSS預處理器。
  • 內置有source map,即便打包在一塊兒依舊方便調試。
  • 看完上面這些,能夠想象它就是一個前端工具,可讓咱們進行各類模塊加載,預處理後,再打包。以前咱們對這些的處理是放在grunt或gulp等前端自動化工具中。有了webpack,咱們無需藉助自動化工具對模塊進行各類處理,讓咱們工具的任務分的更加清晰。

咱們看一下官方對webpack理解的圖。 webpack.jpg

任何靜態資源均可以視做模塊,而後模塊之間也能夠相互依賴,經過webpack對模塊進行處理後,能夠打包成咱們想要的靜態資源。

既然已經大體知道爲何咱們要使用webpack了,咱們接下來就開始使用webpack吧!

#開始使用webpack

首先新建一個webpack101的項目,咱們將在webpack101這裏開展咱們接下來的各項學習。

$ npm init // 用於初始化項目的package.json

//初始化文件目錄:
webpack101
     src
         entry.js
         module1.js
     index.html
     package.json
     webpack.config.js

安裝webpack

咱們經過npm來將webpack安裝到全局

$ npm install webpack -g

webpack配置

webpack是須要進行配置的,咱們在使用webpack的時候,會默認webpack.config.js爲咱們的配置文件。因此接下來,咱們新建這個js文件。

// webpack.config.js
var path = require("path");

module.exports = {
    entry: '../src/entry.js', //演示單入口文件
    output: {
        path: path.join(__dirname, 'out'),  //打包輸出的路徑
        filename: 'bundle.js',              //打包後的名字
        publicPath: "./out/"                //html引用路徑,在這裏是本地地址。
    }
};

編寫入口文件

接下來就編寫咱們的入口文件entry.js和第一個模塊文件module1.js。咱們一切從簡,裏面只用來加載一個Js模塊

// entry.js
require("./module1"); // 使用CommonJs來加載模塊

下一個文件

// module1.js
console.log("Hello Webpack!");

啓動webpack

一切準備好後,咱們僅須要在項目根目錄下,用命令行webpack執行一下便可

// webpack 命令行的幾種基本命令

$ webpack // 最基本的啓動webpack方法
$ webpack -w // 提供watch方法,實時進行打包更新
$ webpack -p // 對打包後的文件進行壓縮,提供production
$ webpack -d // 提供source map,方便調試。

webpack成功運行後,咱們就能夠看到根目錄出現了out文件夾,裏面有咱們打包生成的bundle.js。咱們最後經過在index.html裏對這個文件引入就能夠了。咱們能夠在控制檯看到咱們想要的結果,Hello Webpack !

多模塊依賴

剛纔的例子,咱們僅僅是跑通了webpack經過entry.js入口文件進行打包的例子。下面咱們就來看一下它是否真的支持CommonJs和AMD兩種模塊機制呢?下面咱們新建多幾個js文件吧!

// 修改module1.js
require(["./module3"], function(){
    console.log("Hello Webpack!");
});

下一個文件

// module2.js,使用的是CommonJs機制導出包
module.exports = function(a, b){
    return a + b;
}

下一個文件

// module3.js,使用AMD模塊機制
define(['./module2.js'], function(sum){
    return console.log("1 + 2 = " + sum(1, 2));
})

其實像上面這樣混用兩種不一樣機制很是很差,這裏僅僅是展現用的,在開發新項目時仍是推薦CommonJs或ES2015的Module。固然我我的更傾向於ES2015的模塊機制的~

loader加載器

到了我最喜歡也是最激動人心的功能了!咱們先想一想應用場景,前端社區有許多預處理器供咱們使用。咱們可使用這些預處理器作一些強大的事情,你們都聽過的就是CoffeeScript和Sass了。咱們之前要編譯這些預處理器,就是用gulp進行編譯。可是咱們對這些文件處理其實也挺繁瑣的,webpack能夠一次性解決!

在這裏咱們用Sass和babel編譯ES2015爲例子,看一下loader是如何使用的

安裝loader

咱們第一步就是先要安裝好各個必須的loader,咱們直接看看須要經過npm安裝什麼

$ npm install style-loader css-loader url-loader babel-loader sass-loader file-loader --save-dev

配置loader

安裝完各個loader後,咱們就須要配置一下咱們的webpack.config.js,載入咱們的loader

// webpack.config.js
module.exports = {
    entry: path.join(__dirname, 'src/entry.js'),
    output: {
        path: path.join(__dirname, 'out'),
        publicPath: "./out/",
        filename: 'bundle.js'
    },
    // 新添加的module屬性
    module: {
        loaders: [
            {test: /\.js$/, loader: "babel"},
            {test: /\.css$/, loader: "style!css"},
            {test: /\.(jpgpng)$/, loader: "url?limit=8192"},
            {test: /\.scss$/, loader: "style!css!sass"}
        ]
    }
};

咱們主要看看module的loaders。loaders是一個數組,裏面的每個對象都用正則表達式,對應着一種配對方案。好比匹配到js後綴名就用babel-loader,匹配到scss後綴名的就先用sass,再用css,最後用style處理,不一樣的處理器經過!分隔並串聯起來。這裏的loader是能夠省略掉-loader這樣的,也就是本來應該寫成style-loader!css-loader!sass-loader,固然咱們必須惜字如金,因此都去掉後面的東東。

咱們僅僅是配置一下,已是能夠直接用ES2015和SASS去寫咱們的前端代碼了。在此以前,咱們對src文件夾裏再細分紅js,css,image三個文件夾,處理好分層。話很少說,趕忙試試。

稍微複雜的webpack項目

bebel-loader

// js/es6-module.js
class People{
    constructor(name){
        this.name = name;
    }
    sayhi(){
        console.log(`hi ${this.name} !`);
    }
}
exports.module = People;

寫好模塊後,咱們直接在entry.js入口文件中引入該模塊。

// entry.js

// javascript
require('./js/module1');
let People = require('./js/es6-module');
let p = new People("Yika");
p.sayHi();

// css
require('./css/main.scss');

哈,不能再爽!這下子咱們可使用不少優秀的ES6特性去構建大型的web了。

sass-loader

你們或許注意到了下方的css的require,那就是用來加載Sass樣式的。咱們經過啓動style-loader會將css代碼轉化到 style 標籤內,咱們看一下里面的內容

// css/main.scss
html, body{
    background: #dfdfdf;
}

最後咱們打開index.html觀察咱們全部的結果,首先背景已是淡灰色的,而且控制檯也有咱們想要的內容。咱們經過查看DOM結構,能夠發現head標籤裏多出了style標籤,裏面正是咱們想要定製的樣式

關於對圖片的打包


咱們以前也說,webpack對與靜態資源來講,也是看做模塊來加載的。CSS咱們是已經看過了,那圖片是怎麼做爲模塊打包加載進來呢?這裏咱們能夠想到,圖片咱們是用url-loader加載的。咱們在css文件裏的url屬性,其實就是一種封裝處理過require操做。固然咱們還有一種方式就是直接對元素的src屬性進行require賦值


div.img{
    background: url(../image/xxx.jpg)
}

//或者
var img = document.createElement("img");
img.src = require("../image/xxx.jpg");
document.body.appendChild(img);

上述兩種方法都會對符合要求的圖片進行處理。而要求就是在url-loader後面經過query參數的方式實現的,這裏就是說只有不大於8kb的圖片纔會打包處理成Base64的圖片。關於query,請看文檔:Query parameters

{test: /\.(jpgpng)$/, loader: "url?limit=8192"}

打包成多個資源文件

咱們在開發多頁面的站點的時候,仍是須要但願能有多個資源文件的。這樣咱們就能夠有效利用緩存提高性能,作到文件按需加載。如何寫入口文件,這裏就再也不贅述了,咱們直接看如何對webpack.config.js進行修改

// webpack.config.js

entry: {
    page1: "entry.js",
    page2: "entry2.js"
},
output: {
    path: path.join(__dirname, 'out'),
    publicPath: "./out/",
    filename: '[name].js'
}

這裏重點關注兩個地方,entry屬性能夠是一個對象,而對象名也就是key會做爲下面output的filename屬性的[name]。固然entry也能夠是一個數組,更多用法均可以去webpack的官方文檔進行查看。

固然webpack也考慮到公共模塊的利用,咱們利用插件就能夠智能提取公共部分,以提供咱們瀏覽器的緩存複用。咱們只須要在webpack.config.js添加下面的代碼便可

// 修改添加,webpack.config.js
var webpack = require('webpack');
module.exports = {
    // ....省略各類代碼
        plugins: [
            new webpack.optimize.CommonsChunkPlugin('common.js')
        ]
}

咱們作個小測試,讓第二個入口文件也加載咱們以前的es6-module.js。而後咱們用webpack進行打包,就發現生成的common.js裏是有相應代碼的。咱們須要手動在html上去加載common.js,而且是必需要最早加載

獨立出css樣式

若是咱們但願樣式經過 link 引入,而不是放在 style 標籤內呢,即便這樣作會多一個請求。這個時候咱們就要配合插件一塊兒使用啦,咱們一塊兒來看看

$ npm install extract-text-webpack-plugin --save-dev

安裝完插件就要配置webpack.config.js了。咱們添加如下代碼

var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
    // ...省略各類代碼
    module: {
        loaders: [
            {test: /\.js$/, loader: "babel"},
            {test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")},
            {test: /\.(jpgpngsvg)$/, loader: "url?limit=8192"},
            {test: /\.scss$/, loader: "style!css!sass"}
        ]
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin('common.js'),
        new ExtractTextPlugin("[name].css")
    ]
}

爲了區分開用<link>連接和用 style ,咱們這裏以CSS後綴結尾的模塊用插件。咱們重點關注一下使用了ExtractTextPlugin的模塊,在ExtractTextPlugin的extract方法有兩個參數,第一個參數是通過編譯後經過style-loader單獨提取出文件來,而第二個參數就是用來編譯代碼的loader

固然,插件也支持全部獨立樣式打包成一個css文件。增長多一個參數便可

new ExtractTextPlugin("style.css", {allChunks: true})

至於怎樣加載樣式是最佳實踐,這個就要本身平時多思考了。多站點多樣式的時候,是作到一次性打包加載呢,仍是按需加載呢?我這裏就建議一項,主頁儘可能作到最精簡,畢竟決定用戶存留時間

總結

前端社區不斷髮展,愈來愈趨向於組件化的發展。經過webpack,咱們就能體驗到one component one module的開發感受。固然如何更好的使用webpack仍是要經過不斷的思考總結,才能找到最優的方案web

 


 

模塊化 JavaScript

若是我想用 ES6 的方式引入某個 es6 模塊,好比:

import $ from 'whatever';
怎麼辦?瀏覽器目前還不提供原生支持,webpack 原生也僅支持 CommonJS 的那種寫法,但藉助 babel-loader ,咱們能夠加載 es6 模塊:

安裝 babel-loader

npm install babel-loader babel-core babel-preset-es2015 --save-dev
配置 webpack.config.js

在 module.exports 值中添加 module:

module.exports = {
entry: {
app: ['./main.js']
},
output: {
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.js$/,
loaders: ['babel?presets[]=es2015'],
exclude: /node_modules/
}]
}
}
這樣咱們就能夠在咱們的 js 文件中使用 ES6 語法,babel-loader 負責翻譯。

上面的方法,是在 webpack.config.js 文件中給某一類型文件定義加載器,咱們還能夠在代碼中直接指定:

import $ from 'babel!whatever'
固然,前一種方法會更優雅。

 

更多資料: 易懂的 webpack 使用教程  https://juejin.im/entry/574fe7c579bc440052f6d805

相關文章
相關標籤/搜索