webpack實用配置


前面的話

  上文介紹了webpack入門,本文將詳細介紹webpack實用配置

 

版本號

  以entry.js打包為bundle.js為例,出口的filename可以設置為[id]、[name]、[hash]、[chunkhash]等替換形式,如下所示

var webpack = require('webpack');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: '[id]-[name]-[hash].js'//出口名稱
  }
}

  則出口文件為0-main-0c1dce21f6c5db455fb4.js

  如果index.html要引用打包后的js文件,由於文件名稱不確定,並不好解決。這時,就需要使用html-webpack-plugin插件。該插件並不是內置插件,所以需要安裝

npm install html-webpack-plugin

  HtmlWebpackPlugin簡化了HTML文件的創建,以便為webpack包提供服務。這對於在文件名中包含每次會隨着變異會發生變化的哈希的webpack bundle尤其有用

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: '[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'match',//生成的html文件的標題為'match'
      filename: 'index.html'//生成的html文件名稱為'index.html'
    })
  ]
}

  通過以上的配置,如果在當前路徑,index.html不存在,則生成;如果存在,則替換

  [注意]如果htmlwebpackplugin不進行配置,參數為空, plugins: [new HtmlWebpackPlugin()]。默認地,生成的html文件名稱為'index.html',標題為'Webpack APP' 

【標簽位置】

  htmlwebpackplugin插件的常用設置是設置script標簽插入的位置,默認插入到body標簽中,但可以使用inject:'head',設置插入到head標簽中

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      inject:'head',//將script標簽插入到head標簽中
      filename: 'index-[hash].html',//生成的html文件名稱為'index.html'
    })
  ]
}

【圖標設置】

  設置favicon屬性,可以設置網頁的小圖標

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      favicon:'./icon.ico'
    })
  ]
}

【壓縮】

  設置minify屬性,可以壓縮html文件,默認為false,即不壓縮

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      minify:{
          removeComments: true,//刪除注釋
          collapseWhitespace:true//刪除空格
      }
    })
  ]
}

  使用webpack打包后的index.html代碼如下

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Webpack App</title></head><body><script type="text/javascript" src="js/0-main-8128c0c26a4449da7a05.js"></script></body></html>

 

模板文件

  HtmlWebpackPlugin除了提供模塊版本號的功能,還可以使用模板文件

  例如,模板文件為template.html,內容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>template</title>
</head>
<body>
<script src="test.js"></script>
<div>test</div>    
</body>
</html>

  webpack配置文件如下

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index-[hash].html',//生成的html文件名稱為'index.html'
      template:'template/template.html'//模板文件為'template.html'
    })
  ]
}

  生成的index-[hash].html以'template.html'文件為模板

  [注意]如果在htmlwebpackplugin中使用了模板,則指定title不會生效,因為要以模板的title為准  

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      title:'test',
      filename: 'index-[hash].html',//生成的html文件名稱為'index.html'
      template:'template/template.html'//模板文件為'template.html'
    })
  ]
}

【傳參】

  模塊文件當然是可以傳參的,一般地,使用ejs語法。例如,在模板文件中,使用<%= htmlWebpackPlugin.options.title %>,即可讀取htmlWebpackPlugin插件中'title'屬性的值

  [注意]模板文件中的'htmlWebpackPlugin'是固定的,不能隨意更改。與webpack.config.js文件中,require()該插件的命名無關

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      title:'test',
      template:'template/template.html',//模板文件為'template.html'
      dateData: new Date() 
    })
  ]
}
//template.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><%= htmlWebpackPlugin.options.title  %></title>
</head>
<body>
<div><%=htmlWebpackPlugin.options.dateData %></div>
</body>
</html>

【模板組件】

  下面利用模板組件組合成一個html文件,以ejs模板語言為例

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      template:'template/template.html'})
  ]
}
//template.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<div>
    <% include  template/header.html %>
</div>
<ul>  
    <% var arr = [1,2,3,4,5] %>
    <% for(var i = 0; i < arr.length; i++){ %>  
        <li><%=arr[i] %></li>  
    <% } %>  
</ul>  
<div>
    <% include  template/footer.html %>
</div>
</body>
</html>
//header.html
<div>我是頭部</div>
//footer.html
<div>我是尾部</div>

  運行結果報錯,提示子模板加載失敗

  這是因為HtmlWebpackPlugin插件並不具備ejs模板語言所有的功能,其中一個就是不能識別<%include %>語句,這時需要安裝一個ejs-compiled-loader

npm install ejs-compiled-loader

  安裝完成后,修改配置文件如下,表示使用ejs-compiled-loader來編譯template.html

  [注意]該插件中的include路徑相對於webpack配置文件的位置,而不是模板文件template.html的位置

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
      template:'ejs-compiled-loader!template/template.html'})
  ]
}

  結果如下

 

多頁面

  對於多頁面來說,一般地,有多個入口文件。不同的html頁面輸出對應不同的入口文件。 插件plugins()是一個數組,每new一個HtmlWebpackPlugin(),就可以輸出一個html頁面。這里有兩個重要的屬性:chunks和excludeChunks,chunks表示所包含的入口文件,excludeChunks表示要排除的入口文件

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: {
      a:'./src/js/a.js',
      b:'./src/js/b.js',
      c:'./src/js/c.js'
  },
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
          filename:'a.html',
          template:'src/template/template.html',
          title:'this is a',
          chunks:['a']
    }),
    new HtmlWebpackPlugin({
          filename:'b.html',
          template:'src/template/template.html',
          title:'this is b',
          chunks:['b']
    }),
    new HtmlWebpackPlugin({
          filename:'c.html',
          template:'src/template/template.html',
          title:'this is c',
          excludeChunks:['a','b']
    }),    
  ]
}

  結果如下

//a.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>this is a</title>
</head>
<body>
<div></div>
<script type="text/javascript" src="js/2-a-9828ea84bd8c12c19b5f.js"></script></body>
</html>

//b.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>this is b</title>
</head>
<body>
<div></div>
<script type="text/javascript" src="js/1-b-9828ea84bd8c12c19b5f.js"></script></body>
</html>

//c.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>this is c</title>
</head>
<body>
<div></div>
<script type="text/javascript" src="js/0-c-9828ea84bd8c12c19b5f.js"></script></body>
</html>

 

內聯

  在前面的例子中,都是以鏈接的形式引入入口文件的。有時,為了追求性能,會將其處理為內聯的形式。這里就需要安裝一個擴展插件html-webpack-inline-source-plugin,專門用來處理入口文件內聯的

$ npm install --save-dev html-webpack-inline-source-plugin

  該插件的使用很簡單,使用require()語句引入后,在插件plugins()新建一個html-webpack-inline-source-plugin對象,然后在html-webpack-plugin對象中添加inlineSource屬性即可

inlineSource: '.(js|css)$' // embed all javascript and css inline
//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');

module.exports = {
  entry: './entry.js',
  output:{
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  plugins: [
    new HtmlWebpackPlugin({
        inlineSource: '.(js|css)$'
    }),
    new HtmlWebpackInlineSourcePlugin()
  ]
}

  結果如下

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  </head>
  <body>
  <script type="text/javascript">/******/ (function(modules) { // webpackBootstrap
/******/     // The module cache
/******/     var installedModules = {};
/******/
/******/     // The require function
/******/     function __webpack_require__(moduleId) {
/******/
/******/         // Check if module is in cache
/******/         if(installedModules[moduleId]) {
/******/             return installedModules[moduleId].exports;
/******/         }
/******/         // Create a new module (and put it into the cache)
/******/         var module = installedModules[moduleId] = {
/******/             i: moduleId,
/******/             l: false,
/******/             exports: {}
/******/         };
/******/
/******/         // Execute the module function
/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/         // Flag the module as loaded
/******/         module.l = true;
/******/
/******/         // Return the exports of the module
/******/         return module.exports;
/******/     }
/******/
/******/
/******/     // expose the modules object (__webpack_modules__)
/******/     __webpack_require__.m = modules;
/******/
/******/     // expose the module cache
/******/     __webpack_require__.c = installedModules;
/******/
/******/     // identity function for calling harmony imports with the correct context
/******/     __webpack_require__.i = function(value) { return value; };
/******/
/******/     // define getter function for harmony exports
/******/     __webpack_require__.d = function(exports, name, getter) {
/******/         if(!__webpack_require__.o(exports, name)) {
/******/             Object.defineProperty(exports, name, {
/******/                 configurable: false,
/******/                 enumerable: true,
/******/                 get: getter
/******/             });
/******/         }
/******/     };
/******/
/******/     // getDefaultExport function for compatibility with non-harmony modules
/******/     __webpack_require__.n = function(module) {
/******/         var getter = module && module.__esModule ?
/******/             function getDefault() { return module['default']; } :
/******/             function getModuleExports() { return module; };
/******/         __webpack_require__.d(getter, 'a', getter);
/******/         return getter;
/******/     };
/******/
/******/     // Object.prototype.hasOwnProperty.call
/******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/     // __webpack_public_path__
/******/     __webpack_require__.p = "";
/******/
/******/     // Load entry module and return exports
/******/     return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {

document.write('It works.')

/***/ })
/******/ ]);</script></body>
</html>

 

babel

  下面使用babel來進行es最新標准的代碼向es5代碼的轉換,首先需要安裝babel核心程序,及babel-loader

npm install babel-loader babel-core 

  在使用babel-loader進行代碼轉換之前,要先了解到ecmascript標准變化很快,且瀏覽器支持情況不同。所以,出現了'es2015'、'es2016'、'es2017'、'latest'、'env(new)'等多個不同的標准。這時,要需要來選擇從哪個標准進行轉換,需要安裝插件babel-preset-env 

npm install babel-preset-env 

  在 webpack 配置對象中,需要添加 babel-loader 到 module 的 loaders 列表中。webpack的配置文件如下所示

const path = require('path');
module.exports = { entry:{ app:'./src/app.js', }, output:{ path:path.resolve(__dirname,'src'), filename: '[name].bundle.js' }, module: { rules: [{ test: /\.js$/, use: { loader: 'babel-loader', options: { presets: ['env'] } } }] }, }

  關於path有兩種寫法,除了上面的配置文件的寫法外,另一種寫法如下所示。但是,盡量不要使用__dirname + '/src'的寫法,在某些參數中,該寫法無法生效

path: __dirname +  "/src"

  在命令行中運行webpack命令進行打包,打包過程如下

  打包前的文件為app.js,內容如下

() => {
  return a + b; }; Array.from('1,2,3'); new Set;

  打包后的文件為app.bundle.js,主要內容如下

/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) { "use strict"; (function () { return a + b; }); Array.from('1,2,3'); new Set(); /***/ }) /******/ ]);

  經過babel轉換后的js文件存在兩個問題:

  1、打包速度較慢

  2、部分ES2017的新語法沒有轉換為ES5的代碼

  下面對這兩個問題分別進行處理

【打包速度】

  loader的test屬性表示該loader必須滿足的條件,上面代碼中使用/\.js$/ 來匹配,也許會去編譯 node_modules 目錄或者其他不需要的源代碼。這樣會大大增加webpack的編譯時間

  要排除 node_modules,就要使用 loaders 配置的 exclude 選項,表示哪些除外,exclude:/node_modules/

module.exports = {
  entry:{
    app:'./src/app.js', }, output:{ path:__dirname+'/src/', filename: '[name].bundle.js' }, module: { rules: [{ test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['env'] } } }] }, }

  [注意]exclude除了支持正則表達式外,還支持字符串形式,寫法如下。如果用__dirname +'/node_modules'的形式則不會生效

const path = require('path');
exclude:path.resolve(__dirname, "node_modules")

  打包過程如下

  當node-modules文件部分較大時,速度提升會更明顯

  除了exclude選項,還可以使用include選項,能夠明確被打包的文件時,使用include將使打包速度更快

module.exports = {
  entry:{
    app:'./src/app.js', }, output:{ path:__dirname+'/src/', filename: '[name].bundle.js' }, module: { rules: [{ test: /\.js$/, include: /src/, use: { loader: 'babel-loader', options: { presets: ['env'] } } }] }, }

  [注意]include的另一種寫法如下所示

const path = require('path');
include: path.resolve(__dirname, 'src')

  打包過程如下

  耗費時間有所減小

  cacheDirectory選項值默認為false,當為true時,指定的目錄將用來緩存 loader 的執行結果。之后的 webpack 構建,將會嘗試讀取緩存,來避免在每次執行時,可能產生的、高性能消耗的 Babel 重新編譯過程

const path = require('path');
module.exports = { entry: { app: './src/app.js', }, output: { path: path.resolve(__dirname, 'src'), filename: '[name].bundle.js' }, module: { rules: [{ test: /\.js$/, include: path.resolve(__dirname, 'src'), use: { loader: 'babel-loader', options: { presets: ['env'], cacheDirectory:true } } }] }, }

  耗費時間減少了100ms,效果很好

  解決了babel編譯速度后,下面來解決ES新語法不被轉換的問題

【babel-polyfill】

  Babel默認只轉換新的JavaScript句法(syntax),而不轉換新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉碼。

  舉例來說,ES6在Array對象上新增了Array.from方法。Babel就不會轉碼這個方法。如果想讓這個方法運行,必須使用babel-polyfill。babel-polyfill是一個全局墊片,為開發應用准備的

npm install babel-polyfill

  在腳本頭部加入下面代碼即可使用

import 'babel-polyfill';

  app.js的文件內容如下

import 'babel-polyfill';
() => { return a + b; }; Array.from('1,2,3'); new Set;

  由下圖所示,轉換后的文件大小超過了200kb

【babel-plugin-transform-runtime】

  相當於babel-polyfill來說,babel-plugin-transform-runtime更加適用,它是一個局部墊片,為開發框架准備

npm install babel-plugin-transform-runtime babel-runtime

  app.js文件如下所示

() => {
  return a + b; }; Array.from('1,2,3'); new Set;

  配置文件如下所示

const path = require('path');
module.exports = { entry: { app: './src/app.js', }, output: { path: path.resolve(__dirname, 'src'), filename: '[name].bundle.js' }, module: { rules: [{ test: /\.js$/, include: path.resolve(__dirname, 'src'), use: { loader: 'babel-loader', options: { presets: ['env'], cacheDirectory:true, plugins: ['transform-runtime'] } } }] }, }

  轉換過程如下所示

   轉換后的文件app.bundle.js主要內容如下所示

(function () {
  return a + b; }); (0, _from2.default)('1,2,3'); new _set2.default();

 

CSS

  在webpack入門博文中由介紹過CSS插件的簡單使用,接下來將詳細介紹

  首先,要安裝css-loader和style-loader,css-loader用於讀取並加載css文件,style-loader將它插入到頁面中

  [特別注意]在處理css時,最好不要使用include、exclude等屬性。include、exclude屬性是加快babel轉換速度的,和css沒什么關系,而且會添亂

npm install css-loader style-loader
//app.js
require('./css/common.css');
//common.css
body{margin: 0;background-color: red}
//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/app.js',
  output:{
    path: __dirname,//出口路徑
    filename: 'js/[name].bundle.js'//出口名稱
  },
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[ 'style-loader', 'css-loader' ]
          }
      ]
  },
  plugins: [
    new HtmlWebpackPlugin({})
  ]
}

  效果如下

【自動前綴】

  頁面加載CSS往往並不像上面的情況這么簡單,需要處理很多問題,其中一個就是瀏覽器前綴問題。對於某些屬性來說,比如transform,不同瀏覽器的版本對其支持程度不同,瀏覽器前綴也不同。這時,就需要能夠根據實際情況,自動增加前綴,而postcss-loader就是這樣的工具,而且功能要強大的多

  首先,先安裝postcss-loader

npm install postcss-loader

  然后,安裝postcss的自動前綴的插件autoprefixer

npm install autoprefixer

  配置如下

//common.css
body{transform: scale(0);background-color: red}
//app.js
require('./css/common.css');
//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/app.js',
  output:{
    path: __dirname,//出口路徑
    filename: 'js/[name].bundle.js'//出口名稱
  },
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[ 'style-loader', 
                    'css-loader',                    
                    {
                        loader: 'postcss-loader',
                        options: {plugins: [require('autoprefixer')]}            
                    }
                 ]
          }
      ]
  },
  plugins: [
    new HtmlWebpackPlugin({})
  ]
}

  結果如下

  如果css文件中出現@import,則有兩種處理方式,一種是將postcss文件單獨寫成配置文件postcss.config.js

//common.css
@import './flex.css';
body{transform: scale(0);background-color: red}
//flex.css
body{display:flex;}
//app.js
require('./css/common.css');

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/app.js',
  output:{
    path: __dirname,//出口路徑
    filename: 'js/[name].bundle.js'//出口名稱
  },
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[ 'style-loader', 
                  { loader: 'css-loader',
                    options: {importLoaders: 1} 
                  },
                'postcss-loader'
                ]
          }
      ]
  },
  plugins: [
    new HtmlWebpackPlugin({})
  ]
}

//postcss.config.js
module.exports = {
 plugins:[require('autoprefixer')]
}

  結果如下

  另一種需要安裝postcss-import插件

npm install postcss-import
//common.css
@import './flex.css';
body{transform: scale(0);background-color: red}
//flex.css
body{display:flex;}
//app.js
require('./css/common.css');

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/app.js',
  output:{
    path: __dirname,//出口路徑
    filename: 'js/[name].bundle.js'//出口名稱
  },
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[ 'style-loader', 
                  { loader: 'css-loader',
                    options: {importLoaders: 1 } 
                  },
                  {
                    loader: 'postcss-loader',
                    options: {plugins: [
                          require('postcss-import'),
                          require('autoprefixer')
                        ]
                    }     
                  }
                ]
          }
      ]
  },
  plugins: [
    new HtmlWebpackPlugin({})
  ]
}

  結果如下

【sass】

  首先,需要安裝sass-loader及node-sass

   [注意]關於node-sass安裝的問題移步至此

npm install sass-loader node-sass

  由於sass-loader中已經自帶了關於@import處理的問題。所以,不需要css-loader及postcss-loader的額外處理

//layer.scss
@import './flex.scss';
body{
    background-color:green;
    div{
        width: 400px;
    }
}
//flex.scss
.flex{display:flex;}
//app.js
require('./components/layer/layer.scss');

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/app.js',
  output:{
    path: __dirname,//出口路徑
    filename: 'js/[name].bundle.js'//出口名稱
  },
  module:{
      rules:[
          {
              test:/\.scss$/,
              use:[    'style-loader', 
                      'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {plugins: [require('autoprefixer')]}            
                    },
                    'sass-loader'
                 ]
          }
      ]
  },
  plugins: [
    new HtmlWebpackPlugin({})
  ]
}

  結果如下

【分離CSS】

  默認地,CSS作為模塊資源被打包到入口js文件中。有時,需要把CSS文件分離出來,這時就需要用到extract-text-webpack-plugin插件

npm install extract-text-webpack-plugin

  該插件的配置如下

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  entry: './src/app.js',
  output:{
    path: __dirname,//出口路徑
    filename: 'js/[name].bundle.js'//出口名稱
  },
  module:{
      rules:[
          {
                  test:/\.scss$/,
                use: ExtractTextPlugin.extract({
                  fallback: 'style-loader',
                  use:[ 'css-loader',
                        {
                            loader: 'postcss-loader',
                            options: {plugins: [require('autoprefixer')]}            
                        },
                        'sass-loader'
                     ]
                })              
          }
      ]
  },
  plugins: [
    new HtmlWebpackPlugin({}),
    new ExtractTextPlugin("styles.css")
  ]
}

  結果如下,該插件將入口文件中引用的 *.css,移動到獨立分離的 CSS 文件。因此,你的樣式將不再內嵌到 JS bundle 中,而是會放到一個單獨的 CSS 文件(即 styles.css)當中。 如果樣式文件大小較大,這會做更快提前加載,因為 CSS bundle 會跟 JS bundle 並行加載

 

 

圖片資源

  webpack在處理圖片、音樂、電影等資源文件時,需要使用file-loader

npm install file-loader

  默認情況下,使用file-loader生成的文件的文件名就是文件內容的MD5哈希值並保留原始擴展名

  file-loader的配置項如下所示

name  [hash].[ext] 為文件配置自定義文件名模板
context this.options.context 配置自定義文件 context,默認為 webpack.config.js context
publicPath  __webpack_public_path__ 為文件配置自定義 public 發布目錄
outputPath 'undefined' 為文件配置自定義 output 輸出目錄
useRelativePath false 如果希望為每個文件生成一個相對 url 的 context 時,應該將其設置為 true
emitFile true 默認情況下會生成文件,可以通過將此項設置為 false 來禁止(例如,使用了服務端的 packages)

  以引入圖片資源例,有以下幾種情況

  1、通過css文件的background屬性引入

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  module:{

      rules:[
          {
              test:/\.css$/,
              use:[ 'style-loader', 'css-loader' ]
          },
          {
              test:/\.(png|jpg|gif|svg)$/i,
              use:'file-loader'
          }
      ]
  },  
  plugins: [
    new HtmlWebpackPlugin()
  ]
}
//entry.js
require('./src/css/common.css');
//common.css
body{background: url('../img/eg_bulbon.gif')}

  結果如下

  2、通過模板html文件img標簽引入,這時需要使用${require('')}將相對路徑包裹一次

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname,//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[ 'style-loader', 'css-loader' ]
          },
          {
              test:/\.(png|jpg|gif|svg)$/i,
              use:'file-loader'
          }
      ]
  },  
  plugins: [
    new HtmlWebpackPlugin({
        template:'template/template.html'
    })
  ]
}
//template.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<img src="${require('../src/img/eg_bulbon.gif')}" alt="">
</body>
</html>

  結果如下

  3、若模板使用ejs-compiled-loader插件,則無法使用${require('')}語句,需要使用HtmlWebpackPlugin傳參來構造絕對路徑

//webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './entry.js', //入口文件
  output: {
    path: __dirname + '/dist',//出口路徑
    filename: 'js/[id]-[name]-[hash].js'//出口名稱
  },
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[ 'style-loader', 'css-loader' ]
          },
          {
              test:/\.(png|jpg|gif|svg)$/i,
              use:'file-loader'
          }
      ]
  },  
  plugins: [
    new HtmlWebpackPlugin({
        template:'ejs-compiled-loader!template/template.html',
        file:__dirname
    })
  ]
}
//template.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<div>
    <% include  template/header.html %>
</div>
</body>
</html>
//header.html
<img src="<%=htmlWebpackPlugin.options.file%>\src\img\eg_bulbon.gif" alt="">

  結果如下

【file-loader參數】

  文件名模板占位符有如下幾種

[ext] 資源擴展名
[name] 資源的基本名稱
[path] 資源相對於 context 查詢參數或者配置的路徑
[hash] 內容的哈希值,默認為十六進制編碼的 md5
[<hashType>:hash:<digestType>:<length>] 可選配置
  其他的 hashType, 即 sha1, md5, sha256, sha512
  其他的 digestType, 即 hex, base26, base32, base36, base49, base52, base58, base62, base64
  length 字符的長度
[N] 當前文件名按照查詢參數 regExp 匹配后獲得到第 N 個匹配結果
{
  test:/\.(png|jpg|gif|svg)$/i,
  use:[{
              loader:'file-loader',
            options: {
                name:'[name]-[hash:5].[ext]'
            }  
        }]
}

  或者

{
  test:/\.(png|jpg|gif|svg)$/i,
  use:['file-loader?name=[name]-[hash:5].[ext]']
}

  結果如下

【url-loader】

  url-loader功能類似於file-loader,但是在文件大小(單位byte)低於指定的限制時,可以返回一個dataURL

  可以通過傳遞查詢參數(query parameter)來指定限制(默認為不限制)

  如果文件大小超過限制,將轉為使用 file-loader,所有的查詢參數也會傳過去

npm install url-loader

  圖片的大小為1.1kb,下面將限制設置為2000,則圖片將以base64格式傳遞

{
  test:/\.(png|jpg|gif|svg)$/i,
  use:['url-loader?limit=2000']
}

  結果如下

  如果將限制大小設置為1000,圖片以src的形式傳遞

{
  test:/\.(png|jpg|gif|svg)$/i,
  use:[{
              loader:'url-loader',
            options: {
                limit:1000,
                name:'[name]-[hash:5].[ext]'
            }  
        }]
}

【image-webpack-loader】

  使用image-webpack-loader來壓縮圖片

npm install image-webpack-loader

  image-webpack-loader的配置項如下

 options: {
        mozjpeg: {
          progressive: true, quality: 65 }, optipng: { enabled: false, }, pngquant: { quality: 80, speed: 4 }, gifsicle: { interlaced: false, }, webp: { quality: 75 } }

  插件一張大小為4.1kb的名稱為'm.jpg'的圖片,配置如下

{
  test:/\.(png|jpg|gif|svg)$/i,
  use:[
    'url-loader?limit=1000&name=[name]-[hash:5].[ext]',
    'image-webpack-loader'
  ]
}

  結果如下所示,生成大小為3.28kb,名稱為'm-c7083.jpg'的圖片

【雪碧圖】

  在webpack中自動生成雪碧圖,需要使用postcss-sprits插件

npm install postcss-sprites

  配置非常簡單

  "plugins": {
    "postcss-sprites": {
       spritePath: 'dist/assets/imgs/sprites/'
    }
  }
}

 

加載第三方庫

  如果是加載的遠程CDN庫,則在HTML文件內直接使用script標簽引入即可

<script src="https://cdn.bootcss.com/jquery/3.3.1/core.js"></script>

  這樣,在文件中可以直接使用jQuery

  如果jQuery是通過npm保存到本地,則需要使用ProvidePlugin插件來自動加載模塊,而不必到處 import 或 require 

new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery'
})

  然后在我們任意源碼中:

// in a module
$('#item'); // <= 起作用
jQuery('#item'); // <= 起作用
// $ 自動被設置為 "jquery" 輸出的內容

  如果jQuery是保存在一個自定義的目錄中的,則需要還需要設置別名

resolve:{
  alias:{
    jquery$:path.resolve(__dirname,'src/libs/jquery.min.js')
  }
}

  除了使用providePlugin,還可以使用imports-loader

module: {
  rules: [
    {
      test: path.resolve(__dirname,"src/app.js"),
      use: [
    loader: 'imports-loader',
        options: {$:'jquery'}     
   ]
    }
  ]
}

 

代理遠程接口

  使用webpack-dev-server的proxy功能,可以代理遠程接口。實際上,它使用的是http-proxy-middleware插件

  常用參數如下

target:代理指向的地址
changeOrigin:改變源URL(默認false)
headers:設置http請求頭
pathRewrite:重定向接口請求
logLevel:控制台顯示信息

  在 localhost:3000 上有后端服務的話,可以這樣啟用代理:

proxy: {
  "/api": "http://localhost:3000"
}

  如果服務器給出500錯誤,則需要添加changeOrigin

proxy: {
  "/api": {
    target: "http://localhost:3000",
    changeOrigin: true
  }
}

 

實用配置

  下面將使用webpack搭建一個實用的開發環境

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
    entry: './src/app.js',//入口文件
    output:{
        path: __dirname,//出口路徑
        filename: 'js/[name].bundle.js'//出口名稱
    },
    module:{
        rules:[
            {
                test:/\.scss$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                     use:[ 
                             'css-loader',
                            {
                                loader: 'postcss-loader',
                                //自動添加前綴
                                options: {plugins: [require('autoprefixer')]}            
                            },
                            'sass-loader'
                        ]
                })              
            },
            {
                test:/\.js$/,
                include:/\.\/src/,
                use:{
                        loader: 'babel-loader',
                        //將最新標准的js代碼翻譯為es5代碼
                        options:{presets: ['env']}
                    }
            },
            {
                test:/\.(png|jpg|gif|svg)$/i,
                use:[
                        //當圖片大小大於1000byte時,以[name]-[hash:5].[ext]的形式輸出
                        //當圖片大小小於1000byte時,以baseURL的形式輸出
                        'url-loader?limit=1000&name=[name]-[hash:5].[ext]',
                        //壓縮圖片
                        'image-webpack-loader'
                    ]
            }
          ]
    },
    plugins: [
          //使用模板生成html文件
        new HtmlWebpackPlugin({template:'ejs-compiled-loader!template/template.html'}),
        //分離出css到style.css
        new ExtractTextPlugin("style.css")
    ]
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM