手摸手的教你配置一個基於webpack4的react開發環境

前言

webpack做爲現代前端技術的基石,相信絕大部分的前端開發者都據說或是在項目中使用過。可是因爲如今各類各樣cli工具的出現,可以掌握webpack基本配置和使用的人,可能就不那麼多了。javascript

最開始接觸webpack仍是在之前的angular.js項目中,以後從angular.js轉到react後一直使用的create-react-app進行項目初始化。須要改動webpack配置時也是在使用eject命令暴露出webpack config進行修改,一直沒有本身從零開始配置過。在這期間angular.js升級成爲Angular,jQuery逐漸被歷史淘汰,Vue也從一個後期之秀成爲如今的當紅前端框架。不得不說,前端技術的更新迭代速度真的能夠用飛速來形容了。在如此快速的更新速度下,做爲一個前端開發人員,必定要緊跟技術的步伐,時刻保持着學習狀態,才能保證本身在大潮流中不掉隊。這也是我寫這篇文章的初衷,用來記錄本身的學習成果。css

要注意的是,本文不會贅述現代前端開發中的一些基礎知識,如 npm依賴管理、模塊化等基礎知識。因此,若你並無據說過webpack,或不知道它是什麼,那麼建議你仍是先了解一下基礎知識。若對webpack已經瞭如指掌,那麼也大可沒必要看這篇文章。不過大佬如果願意指導一番,我也是很是開心的!!^_^html

正文

簡介

webpack是什麼?前端

本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(static module bundler)。在 webpack 處理應用程序時,它會在內部建立一個依賴圖(dependency graph),用於映射到項目須要的每一個模塊,而後將全部這些依賴生成到一個或多個bundle。—— 來自 webpack 官方文檔java

簡單的說,webpack就是一個現代前端開發的打包機。現代前端很是流行使用模塊化的方式開發,webpack所作的就是將各個js模塊合理的打包成bundle或者chunk。在打包的過程當中,能夠經過loader的方式,將新的js語法、CSS預處理語言等轉換成更容易被瀏覽器支持的形式。node

webpack是基於nodejs的,在絕大部分時,在使用時須要爲它寫一個配置文件。這個配置文件的主要結構以下:react

module.exports = {
    mode: 'development'      // 模式配置
    entry: '',               // 入口文件
    output: {},              // 出口文件
    module: {},              // 處理對應模塊
    plugins: [],             // 對應的插件
    devServer: {},           // 開發服務器配置(僅在開發中使用)
}
複製代碼

接下來,咱們就來一步步的完成這些配置。linux

準備

初始化和安裝

在指定文件夾下執行 npm init 進行初始化。webpack

mkdir webpackDemo&&npm initgit

由於項目並非一個要發佈到npm的項目,因此執行npm init後只用一路回車便可。

安裝webpack和react的依賴:

npm install --save-dev webpack react react-dom

在webpack4以後的版本中,還須要安裝webpack-cli,具體方法同上。

建立初始目錄結構和文件

在項目根目錄建立config文件夾,並在內建立webpack.config.js。

打開根目錄下的package.json 配置scripts:

"scripts": {
    "build": "webpack --mode production --config ./config/webpack.config.js",
  }
複製代碼

配置scripts腳本是爲了後期在執行過程當中只用在命令行中輸入 npm '腳本中指定配置' 就可以完成命令行的輸入操做。好比輸入 npm build,就會自動執行 "webpack --mode production --config ./config/webpack.config.js" 這一長串的操做。

建立代碼文件夾和react的入口文件:

在項目根目錄中建立src文件夾,並在內建立index.js、App.js、index.css。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css'


ReactDOM.render(
  <App />,
  document.getElementById('root')
);
複製代碼

App.js

import React from 'react';

export default class App extends React.Component {
    render() {
        return <div>
            <p className="text">動手搭建一個基於webpack4的react開發環境</p>
        </div>
    }
}
複製代碼

index.css

.text{
    color:'red'
}
複製代碼

完成上述操做後,項目目錄結構應該像下面這樣

webpackDemo
│   node_modules
└───config
    │   webpack.config.js
└───src
    │   index.js
    │   index.css
    │   App.js
    package.json
複製代碼

如今,咱們完成了簡單的初始化工做,下面開始瞭解webpack吧。

模式 (mode)

mode是webpack4中新增的概念,它有三個選項:developmentproductionnone,用來設置webpack的優化方式。

development

開發模式,該模式優化了開發速度,提供了詳細的錯誤機制和瀏覽器調試工具。而且關閉了代碼壓縮,使代碼可以更快的構建。

production

生產模式,該模式可以提供更小的代碼包,去除了只在開發階段運行的代碼。自動開啓了代碼混淆壓縮。

配置

module.export = {
  mode:'production' // 'development'||'production'||'none'
}
複製代碼

程序入口 (entry)

在這裏,能夠聲明一個應用的起點。入口能夠有一個或者多個。在單頁應用中,入口通常只有一個。不過也能夠將公共依賴配置成爲單頁應用的入口,這樣單頁應用也能夠有多個入口。而在多頁應用中,通常會有多個入口文件。

一個簡單的單頁應用入口以下:

module.export = {
  mode:'production' // 'development'||'production'||'none',
  entry:'./src/index.js',
}

複製代碼

輸出 (output)

output用來配置項目打包後的文件名稱、路徑。用來告訴webpack怎麼輸出、輸出到哪、叫什麼名字。

const path = require('path');

module.export = {
  mode:'production' // 'development'||'production'||'none',
  entry:'./src/index.js',
  output: {
    // 在bundle中引入註釋 注意:該選項不該該在生產模式中啓用
    pathinfo:true,
    // 全部輸出文件的目標路徑
    // 必須是絕對路徑(使用 Node.js 的 path 模塊)
    path: path.resolve(__dirname, './../build'),
    // 輸出的文件名配置
    filename: "[name].[hash].js"
    }
}
複製代碼

這裏的filename並無給它一個實際的名稱,而是使用模板字符串去設置webpack生成後的文件名稱。這個設置中的[name]表明模塊名稱,在單入口文件中默認爲main。而[hash]則會生成一個模塊標識符的hash,默認是20位,能夠經過[hash:16]的方式指定它的位數。打包後的文件名稱就像這樣main.f236aaeca342dfb1f8dd.js。在生成文件名稱後跟上hash有助於咱們在項目從新部署後因爲引用的文件名稱變了,瀏覽器會去下載新的文件,再也不繼續使用本地的緩存。

loader

webpack的做用就是將前端開發中的各個模塊進行處理以及打包。而loader的做用就是處理webpack中的這些模塊。

webpack中模塊有不少種,常見的有:

  • 模塊化的js文件

  • css/less/sass文件

  • 圖片以及靜態文件

loader在module中配置:

// 示例
const path = require('path');

const appSrc = path.resolve(__dirname, '../src')

module.exports =  {
    mode: 'development',
    // 入口
    entry: './src/index.js',
    // 出口
    output: {
        pathinfo: true,
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        path: path.resolve(__dirname, './../build'),
        // 輸出的文件名配置
        filename: "bundle.js"
    },

    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,     // 用來指定針對的文件類型 支持正則
                exclude: /node_modules/, // 用來指定須要排除的文件夾,優化打包速度
                include: appSrc,         // 指定所包含的文件夾 ,優化打包速度
                loader: "babel-loader", // 針對指定文件使用的loader
            }
        ]
    }
};

複製代碼

要對這些模塊進行處理,就要使用到不一樣的loader。在此以前,先簡單的介紹一下須要使用到的loader。

babel-loader

babel是一個語法轉換器,可以讓你自由的使用JavaScript的最新語法。它可以將咱們所寫的新語法、jsx等轉換成瀏覽器可以友好支持的形式。

要使用babel-loader須要下列依賴,能夠經過執行npm install --save-dev babel-loader @babel/core @babel/preset-react @babel/preset-env安裝它們。

  • babel-loader

  • @babel/core

    babel的核心組件,裏面包含着babel的api。

  • @babel/preset-env

    用來轉義JavaScript語法。

  • @babel/preset-react

    用來轉義react。

配置babel-loader:

const path = require('path');

const appSrc = path.resolve(__dirname, '../src')

module.exports =  {
    mode: 'development',
    // 入口
    entry: './src/index.js',
    // 出口
    output: {
        pathinfo: true,
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        path: path.resolve(__dirname, './../build'),
        // 輸出的文件名配置
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                include: appSrc,
                loader: "babel-loader",
                options: {
                    // 指定babel預處理轉義
                    presets: ["@babel/preset-env", "@babel/preset-react"]
                }
            }
        ]
    }
}
複製代碼

完成上述配置後,還需配置一下babel,讓它可以轉換react和js的新語法。能夠像上面使用webpack配置中的option選項中的presets字段指定babel預處理的方式。

也能夠在項目的根目錄建立babel的配置文件.babelrc.babelrc後綴rc來自linux中,使用過linux就知道linux中不少rc結尾的文件,好比.bashrc,rc是run command的縮寫,翻譯成中文就是運行時的命令,表示程序執行時就會來調用這個文件。

babel全部的操做基本都會來讀取這個配置文件,除了一些在回調函數中設置options參數的,若是沒有這個配置文件,會從package.json文件的babel屬性中讀取配置。

.babelrc中添加下列語句:

{
    "presets": ["@babel/preset-env","@babel/preset-react"]
}
複製代碼

url-loader

url-loader和file-loader的做用相似,都是使webpack可以打包靜態文件。url-loader相較於file-loader的功能更強大,它可以使用兩種方式進行打包。

url-loader有一個重要的參數 limit ,這個參數用來設置打包文件大小的限制。當文件小於指定參數時,它可以返回一個DataURL(base64)形勢的文件。當文件大於指定參數時,它將經過file-loader進行打包。

配置url-loader:

const path = require('path');

const appSrc = path.resolve(__dirname, '../src')

module.exports =  {
    mode: 'development',
    // 入口
    entry: './src/index.js',
    // 出口
    output: {
        pathinfo: true,
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        path: path.resolve(__dirname, './../build'),
        // 輸出的文件名配置
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                include: appSrc,
                loader: "babel-loader",
                options: {
                    // 指定babel預處理轉義
                    presets: ["@babel/preset-env", "@babel/preset-react"]
                }
            },
            // url-loader的配置
            {
                test: /\.(png|jpg|gif)$/,
                loader: "url-loader",
                options: {
                    // 設置url-loader轉DataURL的文件大小上限
                    limit: 10000
                }
            }
        ]
    }
}
複製代碼

url-loader還有兩個參數mimetypefallback,這兩個參數使用的並很少,就不在這裏贅述了。

style-loader和css-loader

style-loader和css-loader都是用來處理css文件的,不過它們的做用並不相同。

css-loader:用來讀取css文件的內容,並進行處理 如:minimize。

style-loader:將經過import形式導入到js中的css文件插入到<style></style>標籤內。

在webpack中的配置以下:

const path = require('path');

const appSrc = path.resolve(__dirname, '../src')

module.exports =  {
    mode: 'development',
    // 入口
    entry: './src/index.js',
    // 出口
    output: {
        pathinfo: true,
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        path: path.resolve(__dirname, './../build'),
        // 輸出的文件名配置
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                include: appSrc,
                loader: "babel-loader",
                options: {
                    // 指定babel預處理轉義
                    presets: ["@babel/preset-env", "@babel/preset-react"]
                }
            },
            {
                test: /\.(png|jpg|gif)$/,
                loader: "url-loader",
                options: {
                    // 設置url-loader轉DataURL的文件大小上限
                    limit: 10000
                }
            },
            // 針對css文件配置style-loader和css-loader
            {
                test: /\.css$/,
                include: appSrc,
                use: [
                        'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            // 能夠包含一些配置
                            modules:true|false, // 是否開啓css模塊化,開啓後引入的css文件僅針對當前頁面有效,不會做用到全局
                            minimize: true // 開發模式下應該設爲false,優化打包速度
                        }
                    }
                ]
            }
        ]
    }
}
複製代碼

如上所示,當咱們在針對同一類型的文件配置多個loader時。能夠將loader聲明在一個數組內,數組項能夠是一個對象,也能夠僅僅是一個字符串,這取決於你針對某個loader還有沒有特殊的設置。好比在配置css-loader時,還聲明瞭option選項,並在option選項內開啓了minimize選項。可是在配置style-loader時,僅僅寫了一個字符串。

須要注意的是,數組內loader的執行順序是從數組的最後一項依次向前執行。全部咱們將css-loader配置在了後面,它是先執行的。這更符合處理邏輯,先對css進行處理,再插入到html中。

插件

插件是webpack的一個極其重要的功能,webpack提供了豐富的插件接口,使開發者可以自由的開發插件來拓展webpack的功能。

這裏咱們拿大名鼎鼎的 HtmlWebpackPlugin 來舉例。

設想一個場景,在打包時,須要手動的去建立一個html文件,而後在其中引入打包好的各類文件。即便建立好html文件後,因爲在config中設置了hash形式的打包文件名稱。咱們在每次打包後還須要根據hash名稱的變更去改變html內引入的文件名稱,這是很是低級的重複勞做。

HtmlWebpackPlugin 爲咱們解決了這個問題。HtmlWebpackPlugin 可以根據咱們提供的模板自動生成html文件,並引入打包後的內容。

下面介紹一下HtmlWebpackPlugin的使用過程。

安裝:npm install --save-dev html-webpack-plugin

安裝完成後,先在項目的根目錄建立一個文件夾public,在其中建立一個模板文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
複製代碼

而後在webpack中配置插件:

const path = require('path');

const appSrc = path.resolve(__dirname, '../src')
// 引入html-webpack-plugin插件
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports =  {
    mode: 'development',
    // 入口
    entry: './src/index.js',
    // 出口
    output: {
        pathinfo: true,
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        path: path.resolve(__dirname, './../build'),
        // 輸出的文件名配置
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                include: appSrc,
                loader: "babel-loader",
                options: {
                    // 指定babel預處理轉義
                    presets: ["@babel/preset-env", "@babel/preset-react"]
                }
            },
            {
                test: /\.(png|jpg|gif)$/,
                loader: "url-loader",
                options: {
                    // 設置url-loader轉DataURL的文件大小上限
                    limit: 10000
                }
            },
            // 針對css文件配置style-loader和css-loader
            {
                test: /\.css$/,
                include: appSrc,
                use: [
                        'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            // 能夠包含一些配置

                            minimize: true // 開發模式下應該設爲false,優化打包速度
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        // HTML模板文件處理插件
        new HtmlWebpackPlugin({
            file: 'index.html', // 生成的文件名稱
            template: 'public/index.html' // 指定模板文件
        })
    ],
}
複製代碼

如今在命令行中執行npm build,webpack將打包src目錄內的文件。並將在根目錄生成一個build文件,將打包的內容輸出在裏面。

這時候,咱們其實已經完成了webpack的基本配置。可是如今的配置是基於development模式進行打包的,沒有進行壓縮,很顯然這並不能作爲一個可發佈的版本。要修改成生產模式其實也很簡單,能夠經過兩種方式去實現。

  1. 修改配置文件中的mode選項,將development修改成production。

  2. 刪除配置中的mode選項,修改package.json scripts中的build項爲 webpack --mode production --config ./config/webpack.config.js

在配置2中,使用--mode 可以爲webpack-cli設置打包模式。修改後再次打包,這時候代碼通過webpack production模式的優化,進行了混淆壓縮,變成了發佈版本。

devServer

在平常的開發過程當中,確定不能每修改一點東西就從新build一次,這樣開發效率會受到很大的影響。這時須要啓動一個服務,來監聽文件的變更。當文件保存時就從新打包,同時幫咱們自動刷新瀏覽器,方便咱們及時觀察到更新。

要完成上述操做有幾種方式,這裏只介紹其中的一種,使用 webpack-dev-server 插件。

執行 npm install --save-dev webpack-dev-server 安裝插件,在module.explot中添加配置項 devServer

devServer的配置項有不少,這裏大概的介紹其中幾種經常使用的配置:

  • contentBase: '',告訴服務器從哪一個目錄中提供內容

  • https: true|false, 是否啓用https

  • compress: true|false, 是否啓用壓縮

  • host: '127.0.0.1', 指定host地址

  • port: 23333, 指定端口

  • overlay: true|false, 當出現編譯器錯誤或警告時,在瀏覽器中顯示全屏覆蓋層。

  • progress: true|false, 將運行進度輸出到控制檯。

將devServer添加到配置中:

const path = require('path');

const appSrc = path.resolve(__dirname, '../src')
// 引入html-webpack-plugin插件
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports =  {
    // 入口
    entry: './src/index.js',
    // 出口
    output: {
        pathinfo: true,
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        path: path.resolve(__dirname, './../build'),
        // 輸出的文件名配置
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                include: appSrc,
                loader: "babel-loader",
                options: {
                    // 指定babel預處理轉義
                    presets: ["@babel/preset-env", "@babel/preset-react"]
                }
            },
            {
                test: /\.(png|jpg|gif)$/,
                loader: "url-loader",
                options: {
                    // 設置url-loader轉DataURL的文件大小上限
                    limit: 10000
                }
            },
            // 針對css文件配置style-loader和css-loader
            {
                test: /\.css$/,
                include: appSrc,
                use: [
                        'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            // 能夠包含一些配置

                            minimize: true // 開發模式下應該設爲false,優化打包速度
                        }
                    }
                ]
            }
        ]
    },
    devServer: {
        // HOST
        host: '127.0.0.1',
        // 端口
        port: 23333,
        // 報錯提示在網頁遮罩層
        overlay: true,
        // 顯示運行進度
        progress: true,
    },
    plugins: [
        // HTML模板文件處理插件
        new HtmlWebpackPlugin({
            file: 'index.html', // 生成的文件名稱
            template: 'public/index.html' // 指定模板文件
        })
    ]
}
複製代碼

須要注意的時,devServer應當用在開發環境中,因此如今須要將以前的配置進行修改。

  1. 在配置中刪除mode項。

  2. 爲package.json的scripts中添加另外一個啓動命令 "start": "webpack-dev-server --open --mode development --config ./config/webpack.config.js"

  3. 將以前的build項改成 webpack --mode production --config ./config/webpack.config.js

如今,執行npm build,webpack將使用production模式進行打包。執行npm start時,將使用development模式進行打包,而且webpack-dev-server將啓動一個服務,監聽文件變動。

如今執行npm start,就能夠開始進行開發了!

進階

在上面的配置中,咱們已經實現了一個react項目開發環境的基本配置。但這遠遠不夠,在實際的項目中,可能會用到不少的工具來優化開發速度。同時也須要針對不一樣的環境寫不一樣的配置,作不一樣的優化等。而且,可能還涉及到代碼分割、壓縮等配置。

下面,咱們來一步步完善webpack的配置。

devtool

webpack中devtool選項用來控制是否生成,以及如何生成 source map。

想要了解source map,能夠看一下這篇文章。簡單的說,source map就是幫助咱們定位到錯誤信息位置的文件。正確的配置source map,可以提升開發效率,更快的定位到錯誤位置。

webpack中devtool有不少種配置,咱們能夠在 這裏 瞭解它。

在開發環境中,更推薦使用cheap-module-eval-source-map,它能幫助咱們準確的定位到錯誤源代碼位置的同時,也能提供更快的構建速度和構建性能。

而在生產環境中,能夠不啓動任何source map(不配置devtool項),也可使用source-map。須要注意的是,不要將source map部署到生產服務器中。

爲svg文件配置loader

通常狀況下,項目都會須要用到圖標。常見的圖標使用方式有不少種,如雪碧圖、字體圖標、svg等。雪碧圖和iconfont的使用方式不須要進行特殊的處理,這裏咱們就再也不贅述。下面介紹一個使用svg圖標的方法。

經過 svgr ,可以直接將svg圖標以react組件的形式引入項目中。

就像這樣:

import React from 'react';
import { ReactComponent as Icon } from './icon.svg';

export default class App extends React.Component {
    render() {
        return <div>
            <Icon width={10} height={10} />
        </div>
    }
}
複製代碼

在react最新版本的cli create-react-app,已近默認集成了svgr。在咱們本身的項目中使用也很簡單,只須要針對 .svg添加loader便可。

{
  test: /\.svg$/,
  use: ['@svgr/webpack'],
}
複製代碼

svgr同時也支持node、react-native等處理方式,能夠經過 svgr文檔來了解。

構建不一樣環境下的配置

在生產環境和開發環境的構建目標差別很大。好比在開發環境中,須要更快的構建速度和更強的錯誤提示。可是在生產環境中,則但願構建的代碼能更小,更輕,更側重於性能。因此,針對不一樣的環境,須要不一樣的配置文件。可是若是將配置徹底拆分開,兩個配置文件中可能會包含不少重複的代碼。這時咱們須要提出公共的配置,爲了將這些配置合併在一塊兒,可使用webpack-merge

下面,咱們開始使用 webpack-merge 進行配置優化。

首先,使用npm安裝依賴 npm install --save-dev webpack-merge

而後,在config文件夾下建立 webpack.config.common.js 、 webpack.config.dev.js 、webpack.config.prod.js。顧名思義,這三個配置表明了通用、開發、生產模式的配置文件。

將以前配置中用到的公共配置提出到 webpack.config.common.js 內:

// webpack.config.common.js

// 打包HTML文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const appSrc = path.resolve(__dirname, '../src')

module.exports = {
    // 入口
    entry: './src/index.js',
    module: {
        rules: [
            {
                // 配置svg圖標loader,能夠在項目中經過組件的形式直接引入svg圖標
                test: /\.svg$/,
                include: appSrc,
                use: ['@svgr/webpack']
            }
        ]
    },
    plugins: [
        // HTML模板文件處理插件
        new HtmlWebpackPlugin({
            file: 'index.html',
            template: 'public/index.html'
        })
    ]
}

複製代碼

開發環境下的配置:

const merge = require('webpack-merge');
// 引入公共配置文件
const common = require('./webpack.config.common.js');
const path = require('path');

const appSrc = path.resolve(__dirname, '../src')

module.exports = merge(common, {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    // 出口
    output: {
        pathinfo: true,
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        // chunk名稱配置
        chunkFilename: '[name].chunk.js',
        // 輸出的文件名配置
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                // exclude: /node_modules/,
                include: appSrc,
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env", "@babel/preset-react"]
                }
            },
            // 針對靜態文件
            {
                test: /\.(png|jpg|gif)$/,
                loader: "url-loader",
                options: {
                    limit: 8192,
                    name: 'static/[name].[hash:8].[ext]',
                }
            },
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader',
                        options: {
                            minimize: false
                        }
                    }
                ]
            }
        ]
    },
    devServer: {
        // HOST
        host: '127.0.0.1',
        // 端口
        port: 23333,
        // 報錯提示在網頁遮罩層
        overlay: true,
        // 顯示運行進度
        progress: true,
    }
})

複製代碼

生產環境配置文件:

const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.config.common.js');
// 每次執行打包 先清除以前的打包文件
const CleanWebpackPlugin = require('clean-webpack-plugin');

const appSrc = path.resolve(__dirname,'../src')

module.exports = merge(common, {
    mode: 'production',
    // 出口
    output: {
        pathinfo: false,
        chunkFilename: 'js/[name].chunk.js',
        // 全部輸出文件的目標路徑
        // 必須是絕對路徑(使用 Node.js 的 path 模塊)
        path: path.resolve(__dirname, './../build'),
        filename: "js/[name].[chunkhash:8].js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                include: appSrc,
                // exclude: /node_modules/,
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env", "@babel/preset-react"]
                }
            },
            // 針對靜態文件
            {
                test: /\.(png|jpg|gif)$/,
                loader: "url-loader",
                options: {
                    limit: 10000,
                    name: 'static/[name].[hash:8].[ext]',
                }
            },
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader',
                        options: {
                            minimize: true
                        }
                    }
                ]
            }

        ]
    },
    plugins: [
        // 打包前清除以前的build目錄
        new CleanWebpackPlugin(['build'], path.resolve(__dirname, '../'))
    ]
});
複製代碼

如今配置已經修改完成,咱們還須要修改一下package.json,讓啓動命令去引用不一樣的配置文件。

將開發模式的啓動配置修改成 "start": "webpack-dev-server --open --mode development --config ./config/webpack.config.dev.js"

生產模式的啓動配置修改成 "build": "webpack --mode production --config ./config/webpack.config.prod.js",

如今咱們使用npm start命令啓動項目,運行的是webpack.config.dev.js文件,這是開發配置文件,咱們能夠在裏面作一些針對開發模式的優化。

使用npm build命令啓動項目,運行的是webpack.config.prod.js文件,這是生產配置文件,咱們能夠在裏面作一些針對生產模式的優化。

防止打包文件的重複

執行build命令打包文件時,會在項目的根目錄下生成build目錄,並在其中生成打包文件。當執行屢次build後,會發現因爲項目名稱的hash值不一樣,build目錄下可能存在多個版本打包後的文件。要解決這個問題,可使用插件 clean-webpack-plugin

首先安裝插件 npm i clean-webpack-plugin --save-dev

配置以下:

const CleanWebpackPlugin = require('clean-webpack-plugin')

// webpack config
{
  plugins: [
    new CleanWebpackPlugin(['build'], path.resolve(__dirname, '../'))
  ]
}
複製代碼

配置完插件後,再執行npm build命令。會發現每次打包前,build目錄都會被刪除,而後從新建立。

注意,該插件只用於生產環境配置。

總結

到這裏,咱們實現了webpack的基礎的配置,以及各類概念的掃盲。其實這隻能算是基礎用法,要實現一個真正完善的webpack配置確定遠遠不止這些。這篇文章的面向對象爲初學者,全部在這裏就不過多的介紹那些比較複雜的概念。

在掌握了上述基礎配置後,你們能夠嘗試着進行一些更深刻的學習,如optimization、tree shaking、生產環境下的構建速度優化等。

相關文章
相關標籤/搜索