webpack入門概念

一 概念javascript

1 入口(entry)css

入口起點(entry point)提示webpack 應該使用那個模塊,來做爲構建其內部依賴圖得開始。進入入口七點後,webpack 會找出那些模塊和庫是入口起點(直接和間接)依賴的。html

每一項依賴隨即被處理,最後輸出到稱之爲bundles的文件中,前端

能夠經過webpack配置中的配置entry屬性,來指指定一個入口起點(或多個入口起點)。默認值爲 ./src。java

webpack.config.文件中node

module.exports = {
  entry:'./path/to/my/entry/file.js'          
}

2 出口(output)webpack

output 屬性告訴webpack再哪裏輸出它所建立的bundles,以及如何命名這些文件,默認值爲 ./dist。基本上,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中,你能夠經過再配置中指定一個output字段,來配置這些處理過程:git

webpack.config.jsgithub

const path = require('path');
module.exports = {
  entry :'./path/to/my/entry/file.js',
  output:{
      path:path.resolve(_dirname,'dist'),
      filename:'my_first_webpack.bundle.js'  
    }  
}

在上面的示例中,咱們經過output.path和output.filename兩個屬性,來告訴webpack bundle的名稱以及咱們想要bundle生成web

(emit)到哪裏。可能你想要了解在代碼最上面導入的path模塊是什麼,它是一個node.js的核心模塊。用於操做文件路徑。

3 loader

loader 讓webpack可以處理那些非javascript文件(webpack自身只理解javascript)。loader能夠將全部類型的文件轉換爲webpacck可以處理的有效模塊,而後你就能夠利用webpack的打包能力,對他們進行處理。

本質上,webpack loader 將全部類型的文件,轉化爲應用程序的依賴圖(和最終的bundle)能夠直接引用的模塊。

注意 ,loader可以import導入任何類型的模塊(例如:.css文件)

在更高層面,在webpack的配置中loader有兩個目標:

1 test 屬性,用於標識出應該被對應的loader進行轉換的某個或某些文件

2 use 屬性, 標識進行轉換時,應該使用哪個loader

weback.config.js

const path = require('path');

const config = {
  output: {
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  }
};

module.exports = config;

以上配置中,對一個單獨的module對象定義了rules屬性,裏面包含了兩個必須屬性:test和use。這告訴webpack編譯器以下信息:

在require()/import 語句中被解析爲'.txt'的路徑時,在你對它進行打包以前,先使用raw-loader轉換一下。

4 插件(plugins)

loader被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境變量。插件接口功能及其強大,能夠用來處理各類各樣的任務。

想要使用一個插件,你只須要require()它,而後把他添加到plugins數組中。多數插件能夠經過選項(option)自定義。你也能夠在一個配置文件中由於不一樣目的而屢次使用同一個插件,這是須要經過使用new操做符來建立他的一個實例。

webpack.config.js

const Htmlwebpackplugin = require('html-webpack-plugin');
const webpack = require('webpack');

const config = {
    module:{
         rules:[
            { test : /\.txt$/,use : 'raw-loader' }
         ]
    },
    plugins:{
       new webpack .optimize.UglifyJsPlugin(),
       new Htmlwebpackplugin({ template: './src/index.html' })
    }
}

module.exports = config;    

5 模式

經過選擇development或production 之中的一個,來設置mode參數,你能夠啓用香英的模式下的webpack內置優化

module.export = {
    mode:'production'
}

二 入口起點

1單個入口(簡寫)語法

用法entry:string|Array<string>

webpack.config.js

const config = {
  entry :'./path/to/my/entry/file.js'  
}
module.exports = config;

entry 屬性的單個入口語法,是下面的簡寫:

const config = {
   entry :{
      main:'./path/to/my/entry/file.js'
    }
};

注意:

當你向 entry 傳入一個數組時會發生什麼?

向 entry 屬性傳入「文件路徑(file path)數組」將建立「多個主入口(multi-main entry)」。在你想要多個依賴文件一塊兒注入,而且將它們的依賴導向(graph)到一個「chunk」時,傳入數組的方式就頗有用。

使用此語法在擴展配置時有失靈活性。

2 對象語法

用法:entry :{ [ entryChunkName:string ] : string|Array<string> }

webpack.config.js

const config = {
    entry :{
       app :'./src/app.js',
       vendors:'./src/vendors.js'
    }
}    

對象語法比較繁瑣,然而,這是應用程序中定義入口的最可擴展的方式。

注意:

「可擴展的 webpack 配置」是指,可重用而且能夠與其餘配置組合使用。這是一種流行的技術,用於將關注點(concern)從環境(environment)、構建目標(build target)、運行時(runtime)中分離。而後使用專門的工具(如 webpack-merge)將它們合併。

3 常見場景 

 分離應用程序app和第三方庫入口

webpack.config.js

const config = {
  entry :{
    app:'./src/app.js',
    vendors:'./src/wendors.js'
    }  
}            

這是什麼?告訴咱們webpack從app.js 和vendors.js開始建立依賴圖,這些依賴圖是彼此徹底分離,相互獨立的(每個bundle中都有一個webpack引導(bootstrap))。這種方式比較常見於,只有一個入口起點(不包含vendor)的單頁應用程序中。

 爲何?此設置容許你使用CommonsChunkPlugin從應用程序bundle中提取vendor引用到vendor bundle ,而且把引用vendor的部分替換爲_webpack_require()調用。若是應用程序bundle中沒有vendor代碼,那麼你能夠在webpack中實現被稱爲長效緩存的通用模式

4 多頁面應用程序

webpack.config.js

const config = {
   entry :{
      pageone:'./src/pagone/index.js',
      pagetwo:'./src/pagetwo/index.js',
      pagetree:'./src/pagetree/index.js',
   }
}    

爲何?告訴咱們webpack須要三個獨立分離的依賴圖

爲何?在多頁面應用程序中,(每當頁面跳轉時)服務器將會爲你從新獲取一個新的html文檔,頁面從新加載新文檔,而且資源從新下載,然而,這給了咱們特殊的機會去作不少事情

使用CommonsChunkPlugin 爲每一個頁面間的應用程序共享代碼建立bundle。因爲入口起點增多,多頁應用可以服用入口起點之間的大量代碼/模塊,從而能夠極大地從這些技術中受益

三 輸出 output

配置output 選項能夠控制webpack如何向硬盤寫入編譯文件。注意即便存在多個入口起點,但只指定一個輸出配置。

1 用法

在webpack中配置outpack屬性的最低要求是,將它的值設置爲一個對象,包括一下兩點:

filename:用於輸出文件的文件名;

目標輸出目錄path的絕對路徑;

webpack.config.js

const config={
   output:{
      filename:'bundle.js',
      path:'./home/proj/public/assets'
    }
}
module.export = config;

此配置將一個單獨的 bundle.js 文件輸出到 /home/proj/public/assets 目錄中。

2 多個入口起點

若是配置建立了多個單獨得chunk(例如:使用多個入口起點或者使用像CommonChunkPlugin這樣得插件),則應該使用佔位符來確保每一個文件具備惟一得名稱

{
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}

// 寫入到硬盤:./dist/app.js, ./dist/search.js

3 高級進階

如下是使用 CDN 和資源 hash 的複雜示例:

config.js

output:{
     path: "/home/proj/cdn/assets/[hash]",
     publicPath: "http://cdn.example.com/assets/[hash]/"
}    

在編譯時不知道最終輸出文件的 publicPath 的狀況下,publicPath 能夠留空,而且在入口起點文件運行時動態設置。若是你在編譯時不知道 publicPath,你能夠先忽略它,而且在入口起點設置 __webpack_public_path__

__webpack_public_path__ = myRuntimePublicPath

// 剩餘的應用程序入口

四 模式 mode

提供mode配置選項,告知webpack使用香英模式得內置優化。

string

1 用法

只在配置中提供mode選項:

module.exports = {
   mode:'production'
}

或者從命令中傳參

wbpack --mode=production

支持一下字符串

選項 描述
development

會將 process.env.NODE_ENV 的值設爲 development。啓用 

NamedChunksPlugin 和 NamedModulesPlugin

production

會將 process.env.NODE_ENV 的值設爲 production。啓用 

FlagDependencyUsagePluginFlagIncludedChunksPlugin

ModuleConcatenationPluginNoEmitOnErrorsPlugin

OccurrenceOrderPluginSideEffectsFlagPlugin 和 UglifyJsPlugin.

 

 

 

 

 

 

 

 

 

mode: development

// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}

mode: production

// webpack.production.config.js
module.exports = {
+  mode: 'production',
-  plugins: [
-    new UglifyJsPlugin(/* ... */),
-    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
-    new webpack.optimize.ModuleConcatenationPlugin(),
-    new webpack.NoEmitOnErrorsPlugin()
-  ]
}

五 loader 

loader用於對模塊得源代碼進行轉換。loader可使你在import或‘加載’模塊時預處理文件。所以,loader 相似於其實他構建工具中‘任務task’,並提供了處理前端構建步驟得強大方法。loader能夠將文件從不一樣得語言(如:typeScript)轉換成javascript,或將內聯圖像轉換爲data url 。loader甚至容許你直接在javascript模塊中inport  CSS文件!

1 示例

你可使用 loader 告訴 webpack 加載 CSS 文件,或者將 TypeScript 轉爲 JavaScript。爲此,首先安裝相對應的 loader:

npm install --save-dev css-loader
npm install --save-dev ts-loader

而後指示 webpack 對每一個 .css 使用 css-loader,以及對全部 .ts 文件使用 ts-loader

webpack.config.js

module.exports = {
    module :{
      rules:[
       {test:/\.css$/,use:'css-loader'},
       {test:/.\ts$/,use:'ts-loader'}
      ]
   }
}

2 使用 loader

在你的應用程序中,有三種使用 loader 的方式:

配置:在 webpack.config.js 文件中指定 loader。

內聯:在每一個 import 語句中顯式指定 loader。

CLI:在 shell 命令中指定它們。

3 配置

 module.rules容許你在webpack中指定多個loader。這是展現loader得一種簡明方式。而且有助於使代碼變得更加簡潔,同時讓你對各個loader有個全局得概覽:

 module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }

4 內聯

能夠在import語句或者任何等效於 import 語句的方式中指定loader。使用!將資源中的loader分開,分開的每一個部分都至關於當前目錄解析,

import Styles from 'style-loader!css-loader?modules!./styles.css';

經過前置全部規則及使用 !。能夠對應覆蓋到配置中的任意loader。

選項能夠傳遞查詢參數,例如 ?key=value&foo=bar,或者一個 JSON 對象,例如 ?{"key":"value","foo":"bar"}

注意 : 儘量使用 module.rules,由於這樣能夠減小源碼中的代碼量,而且能夠在出錯時,更快地調試和定位 loader 中的問題。

5 CLI

經過CLI來使用loader

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

這會對 .jade文件使用 jade-loader 對.css文件使用style-loader和css-loader

6 loader特性

  • loader支持鏈式傳遞,可以對資源使用流水線,一組鏈式得loader將按照相反得順序執行。loader鏈中得第一個loader返回值給下一個loader。在最後一個webpack所逾期得javaScript。
  • loader能夠是同步得也能夠是異步的。
  • loader運行在Node.js中,而且可以執行任何可能操做。
  • loader接收查詢參數。用於對loader傳遞配置。
  • loader也可以使用option對象進行配置。
  • 除了使用package.js常見得main屬性。還能夠將普通得npm模塊導出爲loader,作法實在package.js裏定義一個loader字段。
  • 插件(plugin)能夠爲loader帶來更多特性
  • loader可以產生額外得任意文件。

loader 經過(loader)預處理函數,爲 JavaScript 生態系統提供了更多能力。 用戶如今能夠更加靈活地引入細粒度邏輯,例如壓縮、打包、語言翻譯和其餘更多。

7 解析loader

loader 遵循標準的模塊解析。多數狀況下,loader 將從模塊路徑(一般將模塊路徑認爲是 npm installnode_modules)解析。

loader 模塊須要導出爲一個函數,而且使用 Node.js 兼容的 JavaScript 編寫。一般使用 npm 進行管理,可是也能夠將自定義 loader 做爲應用程序中的文件。按照約定,loader 一般被命名爲 xxx-loader(例如 json-loader

六 插件 plugin

插件得目的用於解決loader沒法實現得其餘事.

1 剖析

webpack插件是一個具備apply屬性得JavaScript對象。apply屬性會被webpack compiler 調用,而且comipler對象能夠在整個編譯生命週期訪問。

ConsoleLogOnBuildWebpackPlugin.js

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

class ConsoleLogOnBuildWebpackPlugin {
  apply(compiler){
    compiler.hook.run.tap(pulginName,compilation =>{
       console.log("webpack 構建過程開始!");
    })
  }  
}

注意:compiler hook 的 tap 方法的第一個參數,應該是駝峯式命名的插件名稱。建議爲此使用一個常量,以便它能夠在全部 hook 中複用。

2 用法

因爲插件能夠攜帶參數/選項,你必須在 webpack 配置中,向 plugins 屬性傳入 new 實例。

3 配置

webpack.config.js

const config = {
    entry :'./path/to/my/entry/first.js',
    output:{
        filename:'my-first-webpack.bundle.js',  
        path:path.resolve(_dirname,'dist'),
    },
    module:{
         rules:[
             {
                 test:/.\(js|jsx)$/,
                 use:'babel-loader'
              }
         ]
    },
    plugins:[
       new webpack.optimize.UglifyJsPlugin(),
       new HtmlWebpackPlugin({template:'./src/index.js'})
    ]
};

module.exports = config;                                  

4 Node API

注意:即使使用 Node API,用戶也應該在配置中傳入 plugins 屬性。compiler.apply 並非推薦的使用方式。

const webpack = require('webpack'); //訪問 webpack 運行時(runtime)
const configuration = require('./webpack.config.js');

let compiler = webpack(configuration);
compiler.apply(new webpack.ProgressPlugin());

compiler.run(function(err, stats) {
  // ...
});

七 配置

webpack 的配置文件,是導出一個對象的 JavaScript 文件。此對象,由 webpack 根據對象定義的屬性進行解析。

由於 webpack 配置是標準的 Node.js CommonJS 模塊,你能夠作到如下事情:

  • 經過 require(...) 導入其餘文件
  • 經過 require(...) 使用 npm 的工具函數
  • 使用 JavaScript 控制流表達式,例如 ?: 操做符
  • 對經常使用值使用常量或變量
  • 編寫並執行函數來生成部分配置

請在合適的時機使用這些特性。

雖然技術上可行,但應避免如下作法:

  • 在使用 webpack 命令行接口(CLI)(應該編寫本身的命令行接口(CLI),或使用 --env)時,訪問命令行接口(CLI)參數
  • 導出不肯定的值(調用 webpack 兩次應該產生一樣的輸出文件)
  • 編寫很長的配置(應該將配置拆分爲多個文件)

基本配置

webpack.config.js

var path = require('path');

module.exports = {
  mode: 'development',
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};

八 模塊

1 什麼是webpack模塊?

對比node.js模塊,webpack 模塊 可以以各類方式表達它們得依賴關係,以下幾個例子:

  • ES2015 import 語句
  • CommonJS require() 語句。
  • AMD define 和 require 語句。
  • css/sass/less 文件中的 @import語句。
  • 樣式(url(...))或 HTML 文件(<img src=...>)中的圖片連接(image url)。

2 支持模塊類型

webpack 經過 loader 能夠支持各類語言和預處理器編寫模塊。loader 描述了 webpack 如何處理 非 JavaScript(non-JavaScript) _模塊_,而且在bundle中引入這些_依賴_。 webpack 社區已經爲各類流行語言和語言處理器構建了 loader,包括:

  • CoffeeScript
  • TypeScript
  • ESNext (Babel)
  • Sass
  • Less
  • Stylus

 九 模塊解析

resolver是一個庫,用於幫助找到模塊得絕對路徑。幫助webpack找到bundle中須要引入得模塊代碼,這些代碼在包含在每一個require/import語句中。當打包模塊時,webpack使用enhanced-resolve來解析文件路徑。

1 webpack中的解析規則

使用enhanced-resolve能夠解析三種文件路徑:

2 絕對路徑

 不須要作進一步解析

import "/home/me/file";

import "C:\\User\\me\\file";

3 相對路徑

import "../src/file1";
import "./file2"

在這種狀況下,使用 import 或 require 的資源文件(resource file)所在的目錄被認爲是上下文目錄(context directory)。在 import/require 中給定的相對路徑,會添加此上下文路徑(context path),以產生模塊的絕對路徑(absolute path)。

4 模塊路徑

import "module";
import "module/lib/file";

模塊將會在resolve.modules中指定的全部目錄內搜索,你能夠替換初始模塊路徑,次替換路徑經過使用resolve.alias配置一個別名。

一旦根據上述規則解析路徑後,解析器將檢查路徑是否指向文件或目錄。若是隻想一個文件:

  • 若是路徑具備文件擴展名,則直接將文件打包;
  • 不然,將使用(resolve.extensions)選項做爲文件擴展名來解析,此選項告訴解析器在解析中可以接受那些擴展名(例如:js ,jsx)

若是路徑指向一個文件夾,則採起一下步驟找到具備正確擴展名的正確文件:

  • 若是文件夾中包含package.json文件,則按照順序查找resolve.mainFields 配置選項中指定的字段,而且package.json中的第一個這樣的字段肯定文件路徑。
  • 若是package.json文件不存在或者package.json文件中的main字段沒有返回一個有效路徑,則按照順序查找resolve.mainFields配置選項中指定的文件名,看是否能在import/require目錄下匹配到一個存在的文件名。
  • 文件擴展名經過resolve.estensions 選項採用相似的方法進行解析

webpack根據構建目標爲這些選項採用合理的默認配置。

5 解析loader 【Resolving Loaders】

Loader解析遵循與文件解析器指定的規則相同的規則。可是resolveLoader 配置選項能夠用來爲Loader提供獨立解析規則。

6 緩存

每一個文件系統訪問都被緩存,以便更快觸發對同一文件的多個並行或串行請求。在觀察模式下,只有修改過的文件會從緩存中摘出。若是關閉觀察模式,在每次編譯前清理緩存。

十 依賴圖 【dependency graph】

任什麼時候候,一個文件依賴於另外一個文件,webpack 就把此視爲文件之間有依賴關係。這使得 webpack 能夠接收非代碼資源(non-code asset)(例如圖像或 web 字體),而且能夠把它們做爲_依賴_提供給你的應用程序。

webpack 從命令行或配置文件中定義的一個模塊列表開始,處理你的應用程序。 從這些入口起點開始,webpack 遞歸地構建一個依賴圖,這個依賴圖包含着應用程序所需的每一個模塊,而後將全部這些模塊打包爲少許的 bundle- 一般只有一個 - 可由瀏覽器加載。

十一 構建目標

1 用法

在webpack配置中設置target的值

webpack.config.js

module.exports={
  target:'node'  
}

在上面例子中,使用node webpack 會編譯爲用於[相似Node.js]環境(使用Node.js的require,而不是使用任意的內置模塊(如 fs或path)來加載chunk)。

每一個target 都有各類部署/環境特定的附加項,以支持知足其需求。

2 多個target

webpack不支持向傳入多個字符串,你能夠經過打包兩份分離配置來建立同構的庫:

webpack.config.js

var path = require('path');
var serverConfig = {
    target: 'node',
    output:{
        path:path.rsolve(_dirname,dist);
        fileName:'lib.nade.js'
    }
    ……
};
var clientConfig = {
    target:'web',   // 默認值是 ‘web’ ,可省略
    output:{
        path:path.resolve(_dirname,'dist'),
         filename:'lib.js'
    }
    ……
};

module.exports=[serverConfig ,clientConfig ];

上面的例子將在你的 dist 文件夾下建立 lib.js 和 lib.node.js 文件。

十二 模塊熱替換

模塊熱替換功能會在應用程序過程當中替換,添加或刪除模塊,而無需從新加載整個頁面。主要是經過如下幾種方式,來顯著加快開發速度。

  • 保留在徹底從新加載頁面時丟失應用程序狀態;
  • 只更新變動內容,以節省寶貴的開發時間
  • 調整央視更加快捷,幾乎至關於在瀏覽器調試其中更改樣式
相關文章
相關標籤/搜索