webpack --- 使用 loaders 處理靜態資源

默認狀況下,webpack 只處理 JS 文件。若是要處理其餘文件,webpack 須要配置 loaders 對文件進行預處理,這樣 webpack 就能處理任意靜態資源。 處理靜態資源的經常使用 webpack loaders 分別有 file-loaderurl-loadercss-loaderstyle-loader ,下面我將結合實例分析這些 loaders 的使用。javascript

1. 建立 webpack 項目

咱們的 webpack 項目目錄以下所示,靜態資源包括圖片和字體,放在 src/assets 目錄下css

webpack 僅僅配置輸入輸出,輸入是 scr/index.js 文件,打包後輸出到 dist 文件夾下,JS 文件最後打包到 dist/js/bundle.js

// webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/bundle.js',
  },
  plugins: [
    new CleanWebpackPlugin() // 爲了測試方便,咱們使用 CleanWebpackPlugin 在下次打包前清除以前的打包文件
  ]
};
// src/index.js
import './style.css'
// src/style.css
#app {
  font-family: 'BalsamiqSans';
  width: 100vw;
  height: 100vh;
}
複製代碼

這時候控制檯運行打包指令 npm run build,報錯,報錯信息以下html

ERROR in ./src/style.css
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file
複製代碼

就如一開始說的,默認狀況下 webpack 只打包 JS 文件,而咱們的入口文件不單單有 JS 文件,還包括 css 文件,因而 webpack 打包報錯了。vue

2. 使用 style-loader css-loader 處理 css 文件

• style-loader 將 css 注入到 DOM 中,style-loader 須要和 css-loader 一塊兒使用java

• css-loader 用來解析 @import 與 url() ,解析方式如同 import / require()webpack

咱們完善 webpack 的配置:git

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
  ]
};
複製代碼

這時候打包成功沒有報錯,可是你會發現,打包後只有一個 bundle.js 文件,css 代碼也注入進了 bundle.js 文件中。咱們能夠經過 MiniCssExtractPlugin 這個 plugin 將 CSS 提取到單獨的文件中。請注意, MiniCssExtractPlugin.loaderstyle-loader 會衝突,當二者同時存在時,會報錯 document is not definedgithub

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css',
    })
  ]
};
複製代碼

成功的打包出了 JS 文件與 CSS 文件,而且以想要的文件路徑輸出了web

3. 使用 file-loader url-loader 處理靜態資源

• file-loader 用來處理靜態資源,例如字體、圖片等等,將資源注入到 webpack 中,而且解析資源的相互依賴npm

• url-loader 功能與 file-loader 相似,而且能夠設置文件大小。當資源小於限制時,可以返回一個 DataURL,也就是以 base64 編碼的形式注入到文件中。簡單來說就是將圖片數據翻譯成一串字符,把這串字符打包進文件中,這樣引入文件就能訪問到圖片了

項目中準備了字體資源與圖片資源,進一步更新 webpack 的配置:

// src/style.css
@font-face {
  font-family: 'BalsamiqSans';
  src: url('./assets/fonts/BalsamiqSans-Bold.ttf');
}
#app {
  font-family: 'BalsamiqSans';
  background: url('./assets/image/mai.png');
  width: 100vw;
  height: 100vh;
}
複製代碼
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          limit: 8900,
          outputPath: 'img'
        },
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf|)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'fonts'
        },
      },
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css',
    })
  ]
};
複製代碼

如預期同樣,咱們成功打包出了 JS 文件與靜態資源文件。

在根目錄的 index.html 中引入 JS 與 CSS,測試看看打包後的資源文件的路徑是否使用正確:

<!DOCTYPE html>
<head>
  <title> webpack-demos </title>
  <link rel="stylesheet" type="text/css" href="./dist/css/main.css">
</head>
<body>
  <div id="app">
    hello world
    <script src="./dist/js/bundle.js"></script>
  </div>
</body>
複製代碼

很不幸,打包後的資源路徑並無找到

查看打包後的 CSS 文件,發現資源的引用路徑都是使用的 絕對路徑 ,好比打包後圖片的真實路徑是 dist/img/mai.png ,而 css 引入的路徑是 dist/css/img/mai.png ,路徑不對,資源就找不到了。

由於配置 css 文件在 dist/css 目錄下,css 文件多了一層結構,修改 webpack 配置:

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          limit: 8900,
          outputPath: 'img'
        },
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf|)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'fonts'
        },
      },
      {
        test: /\.css$/i,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../', // css 多了一層
            }
          },
          'css-loader'],
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css',
    })
  ]
};
複製代碼

這時候,打包後的靜態資源配置路徑引用正常了。

@font-face {
  font-family: 'BalsamiqSans';
  src: url(../fonts/BalsamiqSans-Bold.ttf);
}
#app {
  font-family: 'BalsamiqSans';
  background: url(../img/mai.png);
  width: 100vw;
  height: 100vh;
}
複製代碼

至此,使用 webpack 成功編譯了 JS 文件,圖片字體等資源文件,而且分析處理了靜態資源打包路徑的問題。看到這裏你覺得本文結束了,其實並無。 在 Vue 項目中,靜態資源能夠放置在根目錄的 public 文件夾下、 src/assets 文件夾下,放置在這兩個路徑下有什麼差異呢?

4. webpack 處理靜態資源

webpack 是如何處理靜態資源的?在前面的篇幅中,咱們已經介紹了 loaders 處理靜態資源。Vue 項目中, template 和 css 分別會被 vue-loader 與 css-loader 解析。例如 <img src="./logo.png" />background: url(./logo.png)"./logo.png" 是一個相對資源路徑,將由 Webpack 解析爲模塊依賴。logo.png 不是 JavaScript,看成爲一個模塊依賴時,咱們須要使用 url-loader 與 file-loader 進行處理。因爲這些資源在構建過程當中可能被內聯/複製/重命名,因此它們能夠做爲源代碼的一部分。所以建議將資源文件放在 src 目錄中與其餘源文件一塊兒。其實沒必要專門放在 src/assets ,能夠是基於 模塊/組件 的方式放置資源文件。例如,能夠在每一個放置組件的目錄中存放靜態資源。 放置在 public 目錄下的文件不會被 webpack 處理,它們會直接被複制到最終目錄(默認是 dist/static)下。必須使用絕對路徑引用這些文件。

webpack 是打包模塊化工具,在 webpack 裏一切文件都是模塊。本文介紹了經過 loaders 解析文件,瞭解了經過 file-loaderurl-loadercss-loaderstyle-loader 一步步的處理靜態資源。比較 Vue 項目中放置靜態資源的兩處區別,放置在 src/assets 下的資源在構建的時候會被 webpack 打包到最終輸出文件,適合放置本項目的資源文件。public 下的文件在構建的時候不會被 webpack 處理,將被直接拷貝到最終路徑並引用,因此適合放置一些第三方類庫文件。

參考: Handling Static Assets

相關文章
相關標籤/搜索