1. 程式人生 > >詳解Webpack2的那些路徑

詳解Webpack2的那些路徑

Webpack2 中有很多涉及路徑引數配置,若不知其所以然,很容易混淆出錯。本文儘可能的彙集了 Webpack2 中設計路徑的配置,力爭深入淺出。

context

context 是 webpack 編譯時的基礎目錄,入口起點(entry)會相對於此目錄查詢。

若不配置,預設值為當前目錄,webpack設定 context 預設值程式碼

this.set("context", process.cwd());

process.cwd()即webpack執行所在的目錄(等同package.json所在目錄)。

context 應該配置為絕對路徑,假如入口起點為src/main.js,則可以配置:

{
    context: path.resolve('./src'),
    entry: './main.js'
}

此時 entry 不能再配置為'./src/main.js',因為 webpack 會相對於 context 配置的 src 目錄區查詢入口起點(main.js),而 main.js 就在此目錄下,所以應當將 entry 配置為當前目錄(./)。

context 有什麼實際作用?官方文件的解釋是使得你的配置獨立於工程目錄 「This makes your configuration independent from CWD (current working directory)」。怎麼理解?舉個例子,在分離開發生產配置檔案時候,一般把 webpack.config 放到 build 資料夾下,此時 entry 卻不用考慮相對於 build 目錄來配置,仍然要相對於 context 來配置,這也就是所謂的獨立於工程目錄。

需要注意的是,output 的配置項和 context 沒有關係,但是有些外掛的配置項和 context 有關,後面會說明。

output

output.path

打包檔案輸出的目錄,建議配置為絕對路徑(相對路徑不會報錯),預設值和 context 的預設值一樣,都是process.cwd()。

除了常規的配置方式,還可以在 path 中用使用 [hash] 模板,比如配置:

output: {
    path: path.resolve('./dist/[hash:8]/'),
    filename: '[name].js'
}

打包後的目錄如下:

這裡的 hash 值是編譯過程的 hash,如果被打包進來的內容改變了,那麼 hash 值也會發生改變。這個可以用於版本回滾。你也可以配置為path.resolve(`./dist/${Date.now()}/`)方便做持續整合等。

ouput.publicPath

記得最開始學習 Webpack 的時候,一直沒把 publiPath 理解透徹,甚至還錯誤的認為它和 output.path 有關聯。這個配置項在很多場景是非常重要的,如果不深入理解,就不能靈活運用。

怎麼快速又準確的理解 publicPath,我覺得可以用下面的這個公式來表述:

靜態資源最終訪問路徑 = output.publicPath + 資源loader或外掛等配置路徑

舉例說明:

output.publicPath = '/static/'

// 圖片 url-loader 配置
{
    name: 'img/[name].[ext]'
}
// 那麼圖片最終的訪問路徑為
output.publicPath + 'img/[name].[ext]' = '/static/img/[name].[ext]'

// JS output.filename 配置
{
    filename: 'js/[name].js'
}
// 那麼JS最終訪問路徑為 
output.publicPath + 'js/[name].js' = '/static/js/[name].js'

// CSS 
new ExtractTextPlugin("css/style.css")
// 那麼最終CSS的訪問路徑為
output.publicPath + 'css/style.css' = '/static/css/style.css'

publicPath 預設值為空字串,接下來看其他各種常見的 publicPath 配置的實際意義。

publicPath 設為相對路徑,相對路徑實際上是相對於index.html的路徑,為什麼這麼說?比如publicPath:"./dist/",JS檔名為bundle.js,按上面的公式,最終訪問JS的路徑為./dist/bundle.js, 這個路徑同時也是index.html引用bundle.js的路徑,既然要在index.html通過相對路徑引用bundle.js,那麼index.html的位置就決定了 publicPath 的配置,比如index.html在A資料夾下,而釋出的路徑不想放到A資料夾裡,而是想和A資料夾同級,那麼就應配置為publicPath :"../dist/",這就是相對於index.html的路徑來講,bundle.js在上一層的dist資料夾裡。相對路徑的好處是本地可以訪問,比如一些混合 APP 用的file協議,用絕對路徑肯定是不行的。

publicPath 設為相對於協議url(//)或http地址(http://),比如publicPath:'http://wwww.qinshenxue.com/static/',開發環境當然是不能這麼幹,使用這個的場景是將資源託管到CDN,比如公司的靜態資源伺服器等。

另外publicPath應該以'/'結尾,同時其他loader或外掛的配置不要以'/'開頭。

webpack-dev-server

publicPath

上面講過 webpack 的 publicPath,那麼這裡的 publicPath 和 上面的publicPath是不是一回事呢?答案是兩者區別很大,首先這裡的publicPath用於開發環境的,因此不會出現配置 http 地址的情況,那這兩者到底有啥區別呢?

我們知道 webpack-dev-server 打包的內容是放在記憶體中,通過express匹配請求路徑,然後讀取對應的資源輸出。這些資源對外的根目錄就是publicPath,可以理解為和 outpu.path 的功能一樣,將所有資源放在此目錄下,在瀏覽器可以直接訪問此目錄下的資源。

但是這個路徑僅僅只是為了提供瀏覽器訪問打包資源的功能,webpack中的loader和外掛仍然是取ouput.publicPath,比如CSS裡面的圖片最終的路徑仍是"/static/img/xxxx.png",這也是為什麼官方推薦 publicPath 和 webpack 配置的保持一致(除了http地址),配置一致才能正常訪問其他靜態資源。

上面的解釋可能還是比較生硬,還是舉幾個例子來說明:

本例將兩處 publicPath 配置成不一樣的,這樣更容易對比理解。

// webpack.config.js
output: {
    path: path.resolve(`./dist/`),
    filename: 'js/[name].js',
    publicPath: '/static/'
}
// api 呼叫 webpack-dev-server
var webpack = require('webpack');
var webpackDevServer = require('webpack-dev-server');
var config = require("./webpack.config");
var compiler = webpack(config);
var server = new webpackDevServer(compiler, {
    hot: true,
    publicPath: '/web/'
});
server.listen(8282, "0.0.0.0")

如何檢視 webpack-dev-server 所有啟動後的資源訪問路徑呢?有個簡單的方法,就是訪問/webpack-dev-server,本例訪問截圖如下:

上面的資源可以點選檢視,你會發現,資源的路徑都是/web/*****,所以在index.html中引入JS的路徑應為/web/js/main.js,同時也能看到,style.css中的圖片路徑仍然為/static/img/****.png,而不是/web/。

html-webpack-plugin

這個外掛的幾處配置受路徑配置影響,因此需要專門說明下。

template

template的路徑是相對於 output.context,原始碼如下:

this.options.template = this.getFullTemplatePath(this.options.template, compiler.context);

因此 template 對應的檔案需要放在 ouput.context 配置的目錄下才能被識別。

filename

filename的路徑是相對於 output.path,原始碼如下:

this.options.filename = path.relative(compiler.options.output.path, filename);

在 webpack-dev-server 中,則相對於 webpack-dev-server 配置的 publicPath。

若 webpack-dev-server 中的 publicPath 和 ouput.publicPath 不一致,在這種配置下使用html-webpack-plugin是有如下問題:

  • 自動引用的路徑仍然以 ouput.publicPath 為準,和 webpack-dev-server 提供的資源訪問路徑不一致,從而不能正常訪問;
  • 瀏覽 index.html 需要加上 webpack-dev-server 配置的 publicPath 才能訪問(http://localhost:8282/web/)。

這兩個問題也反推出了最方便的配置為:

  • ouput.publicPath 和 webpack-dev-server 的publicPath 均配置為'/',vue-cli 就是這種配置
  • template 放在根目錄,html-webpack-plugin 不用修改引數的路徑,filename 採用預設值。

總結

目前就針對上面基礎路徑做了簡單的解釋說明,如有錯誤,請不吝指出,後續若發現其他相關路徑配置,再作補充。