1. 程式人生 > 其它 >webpack配置專案

webpack配置專案

一、專案初始化

npm init -y
npm install --save-dev webpack
npm install webpack-cli -D

建立 webpack.config.js檔案 在檔案中輸入程式碼:

let path=require("path")		//引用node核心模組 => 路徑
module.exports={
    mode:"production", 			//打包後文件模式 兩種 => development production
    entry:'./src/index.js',		//入口檔案位置
    output:
{ filename:'bundle.[hash:8].js', //檔名稱 path:path.resolve(__dirname,"dist"), //打包後的檔案地址為絕對路徑 名稱為’dist' publicPath:'' //給所有打包檔案引入時加字首,包括css、js、img,如果只想處理圖片可以單獨在url-loader配置中加publicPath } }

執行:

npx webpack

【可選】在package.json檔案中 ,新增指令碼程式碼如下:

"scripts":{
    "build"
:"webpack --config webpack.config.my.js" //可以操作重新命名後的webpack.config.js檔案 }

執行:

npm run build

二、本地服務

使用簡單的服務外掛 webpack-dev-server, 在記憶體中啟動

npm install webpack-dev-server -D

執行:

npx webpack-dev-server

[可選] 在webpack.config.js檔案中新增服務程式碼:

devServer:{				//開發伺服器配置
    port:3000,		//埠號
    progress:true
, //是否顯示進度條 contentBase:'./dist', //伺服器啟動的位置 open:true, //自動開啟瀏覽器 compress:true //gzip壓縮 hot:true //啟動熱更新 }

【可選】在package.json檔案中加入程式碼:

"scripts":{
    "dev":"webpack-dev-server --open"		//新增 --open 自動開啟瀏覽器
 }

執行:

npm run dev

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-9tnQ7kg3-1616136915365)(C:\Users\jfq\AppData\Roaming\Typora\typora-user-images\1614309130932.png)]

此報錯解決方案:

npm uninstall -D webpack-cli
npm install -D [email protected]

三、loader

  • loader 讓 webpack 能夠去處理那些非 JavaScript 檔案(webpack 自身只理解 JavaScript);
  • loader 可以將所有型別的檔案轉換為 webpack 能夠處理的有效模組

在webpack.config.js檔案中配置程式碼:

module.exports = {
  module: {				//模組
    rules: [			//規則
      { test: /\.css$/, use: 'css-loader' }
    ]
 }
};

推薦使用yarn 進行安裝

3.1 處理CSS

包括css less sass 必須在js檔案中匯入 import ‘.css’

3.1.1 處理css檔案

1、安裝 style-loader css-loader 模組

npm install style-loader css-loader -D

2、在webpack.config.js檔案中配置程式碼:

//css-loader  用來解析@import這種語法
//style-loader 用來把css插入 header 標籤中

//loader的執行順序:預設是從右向左,從下向上

module.exports={
    module:{
        rules:[
        	//{test:/\.css$/,use:['style-loader','css-loader']}	//use可以寫成string array object
        	{
                test:/\.css$/,
                use:[{
                    loader:"style-loader",
                    options:{
                        insertAt:"top"		//將css放到body上面;1.0版本已經放棄;現在不使用
                    }
                },
                "css-loader"
                ]
        	}
        ]
    }
}

3.1.2 處理less檔案

1、安裝 style-loader css-loader less-loader 模組 和 less 模組

npm install style-loader css-loader less-loader -D

2、在webpack.config.js檔案中配置程式碼:

module.exports={
    module:{
        rules:[
        	{
                test:/\.less$/,
                use:[
                {
                    loader:"style-loader",
                },
                "css-loader",
                "less-loader"
                ]
        	}
        ]
    }
}

3.1.3 處理sass檔案

  1. 安裝style-loader css-loader sass-loader 模組 和 sass 模組
  2. 用法跟less一樣;

3.1.4 css相容處理

1、安裝 “postcss-loader autoprefixer” 模組

yarn add postcss-loader autoprefixer -D

2、postcss 需要配置文件 postcss.config.js

module.exports = {
    plugins: {
      // 相容瀏覽器,新增字首
      'autoprefixer':{
          overrideBrowserslist: [
            "Android 4.1",
            "iOS 7.1",
            "Chrome > 31",
            "ff > 31",
            "ie >= 8"
            //'last 10 versions', // 所有主流瀏覽器最近10版本用
        ],
        grid: true
      }
    }
}

3、在 “webpack.config.js”檔案中新增配置:

// css
{
  test: /\.css$/, 
  use: [
    MiniCssExtractPlugin.loader,
    'css-loader',   
    'postcss-loader'
  ]
}
// less
{
  test: /\.less$/, 
  use: [
    MiniCssExtractPlugin.loader,
    'css-loader',                   
    'postcss-loader',
    'less-loader'                   
  ]
},

3.2 處理JS

3.2.1 ESLint語法檢測

npm install eslint-config-airbnb-base eslint-plugin-import eslint eslint-loader -D

webpack.config.js中配置

/*
eslint語法檢查:eslint-loader eslint
注意:只檢查自己的js程式碼,第三方的庫是不用檢查的
設定檢查規則:
packag.json中eslintConfig中設定~
   "eslintConfig":{
       "extends":"airbnb-base"
    }
aribnb --> eslint-config-airbnb-base eslint-plugin-import eslint
*/
{
   test:/\.js$/,
   exclude:/node_modules/,
   loader: 'eslint-loader',
   options:{
      fix:true//eslint自動修復格式錯誤
   }
}

3.在package.json中配置eslintConfig

"eslintConfig": {
    "extends": "airbnb-base"
  }

4.如果配置完成後,打包時出現Resolve error: unable to load resolver “node” src\main.js:1:1 錯誤,請安裝下面的依賴後再打包

npm install eslint-import-resolver-node -D

3.2.2 JS相容處理

因為es6語法不相容部分瀏覽器,所以要對專案進行配置

1.安裝依賴

npm install babel-loader @babel/preset-env @babel/core core-js -D //第一三方法安裝這個
npm install  @babel/polyfill -D //第二個方法安裝這個

2.三種方法相容

(1)babel-loader @babel/preset-env @babel/core 相容

​ 只能相容基本的語法,但是像是promise語法,無法進行相容

(2)相容全部js語法 @babel/polyfill

在index.js中引入依賴即可

import ‘@babel/polyfill’

缺點:全部相容造成打包檔案太大

(3)core-js 配合第一種進行按需相容

3.配置詳情(下面是將eslint檢查與js相容配置放在了一起,module中不可以對.js檔案(同一種檔案)進行多次匹配,多次匹配只會匹配第一個,所以要結合在一起)

{
    test:/\.js$/,
    exclude:/node_modules/,
    use:[
 		//要優先執行eslint-loader,可使用配置enforce:'pre' 
        {
            loader: 'eslint-loader',
            options:{
                fix:true	//eslint自動修復格式錯誤
            }
        },
        //js相容性處理:babel-loader @babel/preset-env @babel/core
        {
            loader: 'babel-loader',
            options:{
                //預設:指示babel做怎麼樣的相容性處理
                presets:[
                    [
                        '@babel/preset-env',
                        {
                            // 按需載入
                            useBuiltIns: 'usage',
                            // 指定core-js版本
                            corejs: {
                                version: 3,
                            },
                            // 指定相容瀏覽器版本範圍
                            targets: {
                                chrome: '70', // 谷歌版本70及以上
                                firefox: '62',
                                ie: '9',
                                safari: '10',
                                edge: '17',
                            }
                        }
                    ]
                ]
            }
        }
    ]
},

所以一般採用第一種加第三種組合進行.js檔案相容,也就是上面貼的程式碼。

第二種具體引入方式如下,不建議使用

{
      test:/\.js$/,
      exclude:/node_modules/,
      loader:'babel-loader',
      options:{
           presets:['@babel/preset-env']
      }
}

img

3.3 處理其他檔案

3.2.1 處理路徑

  1. 安裝 file-loader 外掛 可以處理 圖片、字型等
npm install --save-dev file-loader
  1. 在webpack.config.js檔案中新增程式碼配置:
 module.exports = {
    module: {
      rules: [
        {
         test: /\.(png|svg|jpg|gif)$/,  //影象的格式,也可以判斷字型檔案/\.(woff|woff2|eot|ttf|otf)$/
         use: [
          'file-loader'
         ]
        }
      ]
    }
  };

*解析html中的img

yarn add html-loader -D
{
  test: /\.html$/,
  use: 'html-loader'
}

3.2.2 當圖片小於多少,用base64編碼

yarn add url-loader -D
//如果過大,才用file-loader
{
  test: /\.(png|jpg|gif)$/,
  // 當圖片小於多少,用base64,否則用file-loader產生真實的圖片
  use: {
    loader: 'url-loader',
    options: {
      limit: 200 * 1024,          // 小於200k變成base64
    }
  }
}

3.2.3 打包分類

1.圖片分類

{
  test: /\.(png|jpg|gif)$/,
  // 當圖片小於多少,用base64,否則用file-loader產生真實的圖片
  use: {
    loader: 'url-loader',
    options: {
      limit: 1,  // 200k 200 * 1024
      outputPath: 'img/'   // 打包後輸出地址 在dist/img
    }
  }
},

2.css分類

plugins: [
  new MiniCssExtractPlugin({
    filename: 'css/main.css'
  }),
]

3.希望輸出的時候,給這些css、img加上字首,傳到伺服器也能訪問:

output: {
  filename: 'bundle.[hash:8].js',   // [hash:8] 只顯示8位hash
  path: path.resolve(__dirname, 'dist'),
  publicPath: 'http://www.mayufo.cn'  // 給靜態資源統一加
},

如果只處理圖片路徑:

{
  test: /\.(png|jpg|gif)$/,
  // 當圖片小於多少,用base64,否則用file-loader產生真實的圖片
  use: {
    loader: 'url-loader',
    options: {
      limit: 1,  // 200k 200 * 1024
      outputPath: '/img/',   // 打包後輸出地址
      publicPath: 'http://www.mayufo.cn'
    }
  }
}

四、外掛[plugins]

4.1html-webpack-plugin

使用‘html-webpack-plugin’外掛自定義打包html檔案

npm install html-webpack-plugin -D

在webpack.config.js檔案中,新增配置程式碼:

const htmlWebpackPlugin = require('html-webpack-plugin')	//引入外掛

plugins:[		//放置所有的webpack外掛
    new htmlWebpackPlugin({			//用於使用模板打包時生成檔案
        template:'',	//模板檔案
        filename:'',	//打包後生成的檔案
        hash:true,		//新增hash值解決快取問題
        minify:{
            removeAttributeQuotes:true,	//刪除屬性雙引號
            collapseWhitespace:true	//摺疊空行變為一行
        }
    })
]

4.2 mini-css-extract-plugin

抽離css樣式,成單獨檔案

npm install mini-css-extract-plugin -D

在webpack.config.js中配置:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

// 壓縮css

module.exports={
    plugins: [
      new MiniCssExtractPlugin({
          filename: 'css/main.css'		//輸出檔名
      })
    ],
    module:{
        rules:[
            {
              test: /\.css$/,   // css 處理
              use: [
                // {
                //     loader: 'style-loader',
                // },
                // 此時不需要style-loader
                MiniCssExtractPlugin.loader,   // 抽離
                'css-loader', // css-loader 用來解析@import這種語法,
                'postcss-loader'
              ]
            }
        ]
    }   
}

4.3 壓縮css,js程式碼

yarn add optimize-css-assets-webpack-plugin -D
yarn add uglifyjs-webpack-plugin -D

2、在webpack.config.js檔案中配置程式碼:

// 用了`mini-css-extract-plugin`抽離css為link需使用`optimize-css-assets-webpack-plugin`進行壓縮css,使用此方法壓縮了css需要`uglifyjs-webpack-plugin`壓縮js
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")	//壓縮css
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")						//壓縮js

module.exports = {
  optimization: {              // 優化項
    minimizer: [
      new UglifyJsPlugin({     // 優化js
        cache: true,           // 是否快取
        parallel: true,        // 是否併發打包
        // sourceMap: true     // 原始碼對映 set to true if you want JS source maps
      }),
      new OptimizeCSSAssetsPlugin({})    // css 的優化
    ]
  },
  mode: 'production',
  entry: '',
  output: {},
}

五、配置優化項

5.1 模組熱更新(HMR)

只存在於開發環境,哪塊更新只更新那塊

  • 配置熱更新,在devServer中配置hot,開啟HMR功能
 devServer:{
        contentBase: resolve(__dirname,'build'),//自動構建目錄,打包後的資料夾
        compress:true,
        port:3000,
        open:true,
        hot:true		//開啟熱更新
    }

此時樣式檔案已經可以實現熱更新,因為style-loader內部實現了,但是js和html檔案會出現問題。

(1)解決html檔案問題,將entry改為陣列,引入index.html檔案,

html檔案:預設不能使用HMR功能,同時會導致問題:html檔案不能熱更新(不用做HMR功能)

 entry:['./src/index.js','./src/index.html'],

(2)解決js檔案問題,配置js檔案

js檔案:預設不能使用HMR功能 --需要修改js程式碼,新增支援,入口js檔案是沒法處理的,這裡處理非入口的print.js檔案

import print from './print'

print();

if(module.hot){
    //一旦 module.hot 為true,說明開啟了HMR功能。 -->讓HMR功能程式碼失效
    module.hot.accept('./print.js',function(){
        //方法會監聽 print.js檔案變化,一旦發生變化,其他模組不會重新打包構建。
        //會執行後面的回撥函式
        print();
    })
}

5.2除錯工具(devtool)

利於程式碼除錯,顯示報錯準確行數;

devtool: 'source-map'  //cheap-module-souce-map

引數介紹

/**
 * source-map :一種提供原始碼到構建後代碼的對映技術(如果構建後代碼出錯,可以通過對映追蹤原始碼錯誤)
 * [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
 * 
 * source-map:外部
 *  錯誤程式碼準確資訊 和 原始碼的錯誤位置
 * inline-source-map:內聯
 * 錯誤程式碼準確資訊 和 原始碼的錯誤位置
 * 只生成一個內聯source-map
 * hidden-source-map:外部
 * 錯誤程式碼的錯誤原因,但是沒有錯誤位置
 * 不能追蹤原始碼錯誤,只能提示到構建後代碼的錯誤位置
 * eval-source-map:內聯
 * 每個檔案都生成對應的source-map,都在eval
 * 錯誤程式碼準確資訊 和 原始碼的錯誤位置
 * nosources-source-map:外部
 * 能找到錯誤程式碼的準確資訊,但是沒有任何原始碼資訊
 * cheap-source-map:外部
 * 提示錯誤資訊,和原始碼的錯誤位置,但是隻能精確到某一行
 * cheap-module-source-map
 * 錯誤程式碼準確資訊 和 原始碼的錯誤位置
 * module會將loader的source map加入
 * 
 * 內聯 和 外部的區別:1.外部生成了檔案,內聯沒有  2.內聯構建速度更快
 * 
 * 開發環境:速度快,除錯更友好
 *   速度快(eval>inline>cheap>...)
 *      eval-cheap-source-map
 *      eval-source-map
 *   除錯更友好
 *      souce-map
 *      cheap-module-source-map
 *      cheap-source-map
 * 
 *    --> eval-source-map 除錯更友好/  eval-cheap-module-source-map 效能更好
 * 
 * 生產環境:原始碼要不要隱藏?除錯要不要更友好
 *    內聯會讓程式碼體積變的非常大,所以在生產環境中不使用內聯
 *    nosources-source-map 程式碼全部隱藏
 *    hidden-source-map 只隱藏原始碼,會提示構建後代碼錯誤資訊
 * 
 *    -->source-map / cheap-module-souce-map
 */

react專案中devtool配置如下

devtool: isEnvProduction
      ? shouldUseSourceMap
        ? 'source-map'
        : false
      : isEnvDevelopment && 'cheap-module-source-map',

5.3 提高匹配效率 oneOf

提高loader匹配效率,使用方法如下,匹配到一個loader後,後面的就不會再繼續匹配了。

注意:不能有兩個配置處理同一種類型檔案
module:{
        rules:[
            {
                test:/\.js$/,
                exclude:/node_modules/,
                // //優先執行
                enforce:'pre',
                loader:'eslint-loader',
                options:{
                    fix:true
                }
            },
            {
                //下面的loader只會匹配一個,處理效能更好
                //注意:不能有兩個配置處理同一種類型檔案
                oneOf:[
                    {
                        test:/\.css$/,
                        use:[...commenCssLoader]
                    },
                    {
                        test:/\.less$/,
                        use:[...commenCssLoader,'less-loader']
                    },
                ]
            }
        ]
    },

5.4 babel快取

不用重新載入所有的檔案,使用者第二次進入頁面的時候直接讀取快取

  1. 在匹配.js檔案的loader中寫入配置cacheDirectory
{
    test:/\.js$/,
    exclude:/node_modules/,
    loader:'babel-loader',
    options:{
        presets:[
            [
                '@babel/preset-env',
                {
                    useBuiltIns:'usage',
                    corejs:{version:3},
                    targets:{
                        chrome:'70',
                        firefox:'62',
                        ie:'9',
                        safari:'10',
                        edge:'17',
                    }
                }
            ]
        ],
        //開啟babel快取
        //第二次構建時,會讀取之前的快取
        cacheDirectory:true
    }
},
  1. 給輸出的js檔案還有css檔案設定打包輸出名稱
output:{
	filename:'js/build.[contenthash:10].js',
	path:resolve(__dirname,'build')
},
 new MiniCssExtractPlugin({
	filename:'css/build.[contenthash:10].css'
}),

配置詳情

/**
 * babel快取
 *   cacheDirectory:true
 * 檔案資源快取
 *   hash:每次webpack構建時會生成一個唯一的hash值。
 *      問題:因為js和css同時使用一個hash值。
 *        如果重新打包,會導致所有快取失效。(可能只改變了一個檔案)
 *   chunkhash:根據chunk生成的hash值。如果打包來源於同一個chunk,那麼hash值就一樣
 *      問題:js和css的hash值還是一樣的。因為css是在js中被引用的,兩個同屬一個chunk
 *   contenthash: 根據檔案的內容生成hash值。不同檔案hash值一定不一樣
 */

5.5 tree shaking(樹搖)

去除無用程式碼(未使用的程式碼)

自動開啟條件:

  1. 必須使用es6模組化。
  2. 開啟mode:production環境。
  3. 在package.json中配置sideEffects
/**
  * tree shaking(樹搖):
  * 去除無用程式碼(未使用的程式碼)
  * 自動開啟條件:1.必須使用es6模組化。2.開啟mode:production環境。
  * 作用:減少程式碼體積
  * 
  * 在package.json中配置
  * "sideEffects":false 所有程式碼都沒有副作用 (都可以進行tree shaking)
  *   問題:可能會把css/ @babel/polyfill (副作用)檔案幹掉
  *   解決:
  *     "sideEffects":["*.css"]
  */

六、打包多頁應用

// 多入口
let path = require('path')let HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    home: './src/index.js',
    other: './src/other.js'
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html',
      filename: 'home.html',
      chunks: ['home']
    }),
    new HtmlWebpackPlugin({
      template: './index.html',
      filename: 'other.html',
      chunks: ['other', 'home']   // other.html 裡面有 other.js & home.js
    }),
  ]
}