webpack4.0 入門篇 - 構(gòu)建前端開發(fā)的基本環(huán)境

image

什么是 webpack

webpack 可以看做是模塊打包機:他做的事情是,分析你的項目結(jié)構(gòu)栏妖,找到 JavaScript 模塊以及其他的一些瀏覽器不能直接運行的擴展語言(Scss罗售、TypeScript 等)辜窑,將其打包為合適的格式以供瀏覽器使用

構(gòu)建就是把源代碼轉(zhuǎn)換成發(fā)布到線上可執(zhí)行的 JavaScript、CSS寨躁、HTML 代碼穆碎,包括以下內(nèi)容:

  • 代碼轉(zhuǎn)換TypeScript 編譯成 JavaScriptSCSS 編譯成 CSS 等等
  • 文件優(yōu)化:壓縮 JavaScript职恳、CSS所禀、HTML 代碼方面,壓縮合并圖片等
  • 代碼分割:提取多個頁面的公共代碼、提取首屏不需要執(zhí)行部分的代碼讓其異步加載
  • 模塊合并:在采用模塊化的項目有很多模塊和文件北秽,需要構(gòu)建功能把模塊分類合并成一個文件
  • 自動刷新:監(jiān)聽本地源代碼的變化葡幸,自動構(gòu)建,刷新瀏覽器
  • 代碼校驗:在代碼被提交到倉庫前需要檢測代碼是否符合規(guī)范贺氓,以及單元測試是否通過
  • 自動發(fā)布:更新完代碼后蔚叨,自動構(gòu)建出線上發(fā)布代碼并傳輸給發(fā)布系統(tǒng)。

構(gòu)建其實是工程化辙培、自動化思想在前端開發(fā)中的體現(xiàn)蔑水。把一系列流程用代碼去實現(xiàn),讓代碼自動化地執(zhí)行這一系列復雜的流程扬蕊。

webpack 的基本概念

  • 入口(entry point): 指示 webpack 應該使用哪個模塊搀别,來作為構(gòu)建其內(nèi)部依賴圖的開始,webpack 會找出有哪些模塊和 library 是入口起點(直接和間接)依賴的尾抑。

    • 默認值是 ./src/index.js歇父,然而,可以通過在 webpack 配置中配置 entry 屬性再愈,來指定一個不同的入口起點(或者也可以指定多個入口起點)榜苫。
  • 出口 output: 屬性告訴 webpack 在哪里輸出它所創(chuàng)建的 bundles,以及如何命名這些文件翎冲,主輸出文件默認為 ./dist/main.js垂睬,其他生成文件的默認輸出目錄是 ./dist

  • loader: 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以將所有類型的文件轉(zhuǎn)換為 webpack 能夠處理的有效模塊抗悍,然后你就可以利用 webpack 的打包能力驹饺,對它們進行處理。

注意缴渊,loader 能夠 import 導入任何類型的模塊(例如 .css 文件)赏壹,這是 webpack 特有的功能,其他打包程序或任務(wù)執(zhí)行器的可能并不支持疟暖。我們認為這種語言擴展是有很必要的卡儒,因為這可以使開發(fā)人員創(chuàng)建出更準確的依賴關(guān)系圖。

  • 插件 plugins: loader 被用于轉(zhuǎn)換某些類型的模塊俐巴,而插件則可以用于執(zhí)行范圍更廣的任務(wù)。插件的范圍包括硬爆,從打包優(yōu)化和壓縮欣舵,一直到重新定義環(huán)境中的變量。插件接口功能極其強大缀磕,可以用來處理各種各樣的任務(wù)缘圈。

  • 模式 mode: 通過選擇 developmentproduction 之中的一個劣光,來設(shè)置 mode 參數(shù),你可以啟用相應模式下的 webpack 內(nèi)置的優(yōu)化

webpack 構(gòu)建過程

  1. 從 Entry 里配置的 Module 開始遞歸解析 Entry 依賴的所有 Module糟把。
  2. 每找到一個 Module绢涡, 就會根據(jù)配置的 Loader 去找出對應的轉(zhuǎn)換規(guī)則。
  3. 對 Module 進行轉(zhuǎn)換后遣疯,再解析出當前 Module 依賴的 Module雄可。
  4. 這些模塊會以 Entry 為單位進行分組,一個 Entry 和其所有依賴的 Module 被分到一個組也就是一個 Chunk缠犀。
  5. 最后 Webpack 會把所有 Chunk 轉(zhuǎn)換成文件輸出数苫。
  6. 在整個流程中 Webpack 會在恰當?shù)臅r機執(zhí)行 Plugin 里定義的邏輯。

開發(fā)環(huán)境和生產(chǎn)環(huán)境

我們在日常的前端開發(fā)工作中辨液,一般都會有兩套構(gòu)建環(huán)境:一套開發(fā)時使用虐急,一套供線上使用。

  • development: 用于開發(fā)的配置文件滔迈,用于定義 webpack dev server 和其他東西
  • production: 用于生產(chǎn)的配置文件止吁,用于定義 UglifyJSPluginsourcemaps

簡單來說燎悍,開發(fā)時可能需要打印 debug 信息敬惦,包含 sourcemap 文件,而生產(chǎn)環(huán)境是用于線上的即代碼都是壓縮后间涵,運行時不打印 debug 信息等仁热。譬如 axios、antd 等我們的生產(chǎn)環(huán)境中需要使用到那么我們應該安裝該依賴在生產(chǎn)環(huán)境中勾哩,而 webpack-dev-server 則是需要安裝在開發(fā)環(huán)境中

平時我們 npm 中安裝的文件中有 -S -D, -D 表示我們的依賴是安裝在開發(fā)環(huán)境的抗蠢,而-S 的是安裝依賴在生產(chǎn)環(huán)境中。

本文就來帶你搭建基本的前端開發(fā)環(huán)境思劳,前端開發(fā)環(huán)境需要什么呢迅矛?

  • 構(gòu)建發(fā)布需要的 HTML、CSS潜叛、JS秽褒、圖片等資源
  • 使用 CSS 預處理器,這里使用 less
  • 配置 babel 轉(zhuǎn)碼器 => 使用 es6+
  • 處理和壓縮圖片
  • 配置熱加載威兜,HMR

以上配置就可以滿足前端開發(fā)中需要的基本配置销斟。下面是本文打包后的效果圖:

image

搭建基本的開發(fā)環(huán)境

安裝

mkdir webpack-dev && cd webpack-dev
npm init -y
npm i webpack webpack-cli -D

添加 scripts

生成了 package.json 文件,在文件中添加

 "scripts": {
    "build": "webpack --mode production"
  }

--mode 模式 (必選椒舵,不然會有 WARNING)蚂踊,是 webpack4 新增的參數(shù)選項,默認是 production

  • --mode production 生產(chǎn)環(huán)境
    • 提供 uglifyjs-webpack-plugin 代碼壓縮
    • 不需要定義 new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }) 默認 production
    • 默認開啟 NoEmitOnErrorsPlugin -> optimization.noEmitOnErrors, 編譯出錯時跳過輸出笔宿,以確保輸出資源不包含錯誤
    • 默認開啟 ModuleConcatenationPlugin -> optimization.concatenateModules, webpack3 添加的作用域提升(Scope Hoisting)
  • --mode development 開發(fā)環(huán)境
    • 使用 eval 構(gòu)建 module, 提升增量構(gòu)建速度
    • 不需要定義 new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }) 默認 development
    • 默認開啟 NamedModulesPlugin -> optimization.namedModules 使用模塊熱替換(HMR)時會顯示模塊的相對路徑

添加了 scripts 之后犁钟,新建src/index.js棱诱,然后執(zhí)行npm run build ,你就會發(fā)現(xiàn)新增了一個 dist 目錄涝动,里邊存放的是 webpack 構(gòu)建好的 main.js 文件迈勋。

ps npm scripts 使用指南

新建 webpack.config.js 文件

要想對 webpack 中增加更多的配置信息,我們需要建立一個 webpack 的配置文件醋粟。在根目錄下創(chuàng)建 webpack.config.js 后再執(zhí)行 webpack 命令靡菇,webpack 就會使用這個配置文件的配置了

配置中具備以下的基本信息:

module.exports = {
  entry: '', // 打包入口:指示 webpack 應該使用哪個模塊,來作為構(gòu)建其內(nèi)部依賴圖的開始
  output: '', // 出口
  resolve: {}, // 配置解析:配置別名昔穴、extensions 自動解析確定的擴展等等
  devServer: {}, // 開發(fā)服務(wù)器:run dev/start 的配置镰官,如端口、proxy等
  module: {}, // 模塊配置:配置loader(處理非 JavaScript 文件吗货,比如 less泳唠、sass、jsx宙搬、圖片等等)等
  plugins: [] // 插件的配置:打包優(yōu)化笨腥、資源管理和注入環(huán)境變量
}

配置打包入口和出口

首先我們往 webpack.config.js 添加點配置信息

const path = require('path')

module.exports = {
  // 指定打包入口
  entry: './src/index.js',

  // 打包出口
  output: {
    path: path.resolve(__dirname, 'dist'), // 解析路徑為 ./dist
    filename: 'bundle.js'
  }
}

上面我們定義了打包入口 ./src/index.js,打包出口為 ./dist, 打包的文件夾名字為bundle.js勇垛,執(zhí)行npm run build命令后脖母,index.js 文件會被打包為 bundle.js 文件。此時隨便建立一個 html 文件引用這個bundle.js就可以看到你在index.js 寫的代碼了闲孤。

path.resolve([...paths]) 方法會把一個路徑或路徑片段的序列解析為一個絕對路徑谆级。

使用 html-webpack-plugin 創(chuàng)建 html 文件

更多情況下我們不希望打包一次,就新建一次 html 文件來引用打包后的文件讼积,這樣顯得不智能或者說當你打包的文件名修改后肥照,引用路徑就會出錯。

這個時候我們就可以使用 html-webpack-plugin 插件來將 HTML 引用路徑和我們的構(gòu)建結(jié)果關(guān)聯(lián)起來勤众。

npm install html-webpack-plugin -D

創(chuàng)建文件public/index.html 修改 webpack.config.js 文件

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html', // 配置輸出文件名和路徑
      template: './public/index.html' // 配置要被編譯的html文件
    })
  ]
}

重新執(zhí)行 npm run build, dist 目錄就會多個 index.html 并引入了 bundle.js.

壓縮 html 文件

修改 webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html', // 配置輸出文件名和路徑
      template: './public/index.html', // 配置要被編譯的html文件
      hash: true,
      // 壓縮 => production 模式使用
      minify: {
        removeAttributeQuotes: true, //刪除雙引號
        collapseWhitespace: true //折疊 html 為一行
      }
    })
  ]
}

打包 css 文件

我們希望使用 webpack 來進行構(gòu)建 css 文件舆绎,,為此们颜,需要在配置中引入 loader 來解析和處理 CSS 文件:

npm install style-loader css-loader -D

新建 src/assets/style/color.css, 修改 webpack.config.js 文件:

module.exports = {
  //...
  module: {
    /**
     * test: 匹配特定條件吕朵。一般是提供一個正則表達式或正則表達式的數(shù)組
     * include: 匹配特定條件。一般是提供一個字符串或者字符串數(shù)組
     * exclude: 排除特定條件
     * and: 必須匹配數(shù)組中的所有條件
     * or: 匹配數(shù)組中任何一個條件,
     * nor: 必須排除這個條件
     */
    rules: [
      {
        test: /\.css$/,
        include: [path.resolve(__dirname, 'src')],
        use: ['style-loader', 'css-loader']
      }
    ]
  }
  //...
}

經(jīng)由上述兩個 loader 的處理后窥突,CSS 代碼會轉(zhuǎn)變?yōu)?JS努溃, 如果需要單獨把 CSS 文件分離出來,我們需要使用 mini-css-extract-plugin 插件

抽取 css 到獨立文件, 自動添加前綴

npm i mini-css-extract-plugin postcss-loader autoprefixer -D

我們在寫 css 時不免要考慮到瀏覽器兼容問題阻问,如 transform 屬性茅坛,需要添加瀏覽器前綴以適配其他瀏覽器。故使用到 postcss-loader 這個 loader则拷, 下面則是相關(guān)的配置

webpack.config.js

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

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/,
        include: [path.resolve(__dirname, 'src')],
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            }
          }
        ]
      }
    ]
  },
  plugins: [
    //...
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
}

打包 less 文件

開發(fā)中通常會用到一門預處理語言贡蓖,這里以less為例,通過less-loader可以打包 less 為 css 文件

npm install less less-loader -D

新建 src/assets/style/index.less, 并且在 src/index.js 中引入 import './assets/style/index.less'

配置 webpack.config.js

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

module.exports = {
  module: {
    rules: [
      // ...
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')] // 添加css中的瀏覽器前綴
            }
          },
          'less-loader'
        ]
      }
    ]
  }
  //...
}

執(zhí)打包命令后就可以發(fā)現(xiàn) index.less 中寫的樣式會和color.css一樣被打包進 main.css中煌茬。

webpack@v4 升級踩坑: 關(guān)于使用 mini-css-extract-plugin 的注意點斥铺。

打包圖片

npm install file-loader url-loader -D

file-loader: 可以用于處理很多類型的文件,它的主要作用是直接輸出文件坛善,把構(gòu)建后的文件路徑返回晾蜘。

url-loader:
如果圖片較多,會發(fā)很多 http 請求眠屎,會降低頁面性能剔交。url-loader 會將引入的圖片編碼,生成 dataURl改衩。相當于把圖片數(shù)據(jù)翻譯成一串字符岖常。再把這串字符打包到文件中,最終只需要引入這個文件就能訪問圖片了葫督。當然竭鞍,如果圖片較大,編碼會消耗性能橄镜。因此 url-loader 提供了一個 limit 參數(shù)偎快,小于 limit 字節(jié)的文件會被轉(zhuǎn)為 DataURl,大于 limit 的還會使用 file-loader 進行 copy洽胶。

  • url-loader 可以看作是增強版的 file-loader晒夹。
  • url-loader 把圖片編碼成 base64 格式寫進頁面,從而減少服務(wù)器請求姊氓。
module.exports = {
  module: {
    rules: [
      // ...
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              outputPath: 'images/', //輸出到images文件夾
              limit: 500 //是把小于500B的文件打成Base64的格式丐怯,寫入JS
            }
          }
        ]
      }
    ]
  }
  //...
}

url-loader 和 file-loader 是什么關(guān)系呢?

簡單地說他膳,url-loader 封裝了 file-loader响逢。url-loader 不依賴于 file-loader,即使用 url-loader 時棕孙,只需要安裝 url-loader 即可舔亭,不需要安裝 file-loader,因為 url-loader 內(nèi)置了 file-loader蟀俊。

通過上面的介紹钦铺,我們可以看到,url-loader 工作分兩種情況:

  • 文件大小小于 limit 參數(shù)肢预,url-loader 將會把文件轉(zhuǎn)為 DataURL矛洞;
  • 文件大小大于 limit,url-loader 會調(diào)用 file-loader 進行處理,參數(shù)也會直接傳給 file-loader沼本。因此我們只需要安裝 url-loader 即可噩峦。

有關(guān) url-loaderfile-loader 的解析:webpack 之圖片引入-增強的 file-loader:url-loader

配置 babel

babel-loader

Babel 是一個讓我們能夠使用 ES 新特性的 JS 編譯工具,我們可以在 webpack 中配置 Babel抽兆,以便使用 ES6识补、ES7 標準來編寫 JS 代碼。

Babel 7 的相關(guān)依賴包需要加上 @babel scope辫红。一個主要變化是 presets 設(shè)置由原來的 env 換成了 @babel/preset-env, 可以配置 targets, useBuiltIns 等選項用于編譯出兼容目標環(huán)境的代碼凭涂。其中 useBuiltIns 如果設(shè)為 "usage",Babel 會根據(jù)實際代碼中使用的 ES6/ES7 代碼贴妻,以及與你指定的 targets切油,按需引入對應的 polyfill,而無需在代碼中直接引入 import '@babel/polyfill'名惩,避免輸出的包過大澎胡,同時又可以放心使用各種新語法特性。

npm i babel-loader @babel/core @babel/preset-env -D

筆者這里配的版本號如下

{
  "babel-loader": "^8.0.4",
  "@babel/core": "^7.1.2",
  "@babel/preset-env": "^7.1.0"
}
  • babel-loader: 用 babel 轉(zhuǎn)換 ES6 代碼需要使用到 babel-loader
  • @babel-preset-env: 默認情況下是等于 ES2015 + ES2016 + ES2017绢片,也就是說它對這三個版本的 ES 語法進行轉(zhuǎn)化滤馍。
  • @babel/core:babel 核心庫

根目錄下新建 .babelrc 文件

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "targets": {
          "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
        },
        "useBuiltIns": "usage"
      }
    ]
  ]
}
  • presets 是一堆 plugins 的預設(shè),起到方便的作用底循。
  • plugins 是編碼轉(zhuǎn)化工具巢株,babel 會根據(jù)你配置的插件對代碼進行相應的轉(zhuǎn)化。

修改 webpack.config.js

module.exports = {
  module: {
    rules: [
      //...
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  }
}

babel/polyfill 和 transform-runtime

Babel 默認只轉(zhuǎn)換新的 JavaScript 句法(syntax)熙涤,而不轉(zhuǎn)換新的 API 阁苞,比如 Iterator、Generator祠挫、Set那槽、Maps、Proxy等舔、Reflect骚灸、Symbol、Promise 等全局對象慌植,以及一些定義在全局對象上的方法(比如 Object.assign)都不會轉(zhuǎn)碼甚牲。

  • babel-polyfill: 如上述所說,對于新的 API蝶柿,你可能需要引入 babel-polyfill 來進行兼容

  • 關(guān)鍵點

    • babel-polyfill 是為了模擬一個完整的 ES2015+環(huán)境丈钙,旨在用于應用程序而不是庫/工具。
    • babel-polyfill 會污染全局作用域

babel-runtime 的作用:

  • 提取輔助函數(shù)交汤。ES6 轉(zhuǎn)碼時雏赦,babel 會需要一些輔助函數(shù),例如 _extend。babel 默認會將這些輔助函數(shù)內(nèi)聯(lián)到每一個 js 文件里星岗, babel 提供了 transform-runtime 來將這些輔助函數(shù)“搬”到一個單獨的模塊 babel-runtime 中填大,這樣做能減小項目文件的大小。
  • 提供 polyfill:不會污染全局作用域伍茄,但是不支持實例方法如 Array.includes

babel-runtime 更像是分散的 polyfill 模塊栋盹,需要在各自的模塊里單獨引入,借助 transform-runtime 插件來自動化處理這一切敷矫,也就是說你不要在文件開頭 import 相關(guān)的 polyfill,你只需使用汉额,transform-runtime 會幫你引入曹仗。

對于開發(fā)應用來說,直接使用上述的按需 polyfill 方案是比較方便的蠕搜,但如果是開發(fā)工具怎茫、庫的話,這種方案未必適合(babel-polyfill 是通過向全局對象和內(nèi)置對象的 prototype 上添加方法實現(xiàn)的妓灌,會造成全局變量污染)轨蛤。Babel 提供了另外一種方案 transform-runtime,它在編譯過程中只是將需要 polyfill 的代碼引入了一個指向 core-js 中對應模塊的鏈接(alias)虫埂。關(guān)于這兩個方案的具體差異和選擇祥山,可以自行搜索相關(guān)教程,這里不再展開掉伏,下面提供一個 transform-runtime 的參考配置方案缝呕。

  • 首先安裝 runtime 相關(guān)依賴
npm i @babel/plugin-transform-runtime -D
npm i @babel/runtime -S

修改 .babelrc

{
  //...
  "plugins": ["@babel/plugin-transform-runtime"]
}

打包前清理源目錄文件 clean-webpack-plugin

每次打包,都會生成項目的靜態(tài)資源斧散,隨著某些文件的增刪供常,我們的 dist 目錄下可能產(chǎn)生一些不再使用的靜態(tài)資源,webpack 并不會自動判斷哪些是需要的資源鸡捐,為了不讓這些舊文件也部署到生產(chǎn)環(huán)境上占用空間栈暇,所以在 webpack 打包前最好能清理 dist 目錄。

npm install clean-webpack-plugin -D

修改 webpack.config.js 文件

const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
  plugins: [new CleanWebpackPlugin(['dist'])]
}

提取公用代碼

假如你 a.jsb.js 都 import 了 c.js 文件箍镜,這段代碼就冗雜了源祈。為什么要提取公共代碼,簡單來說鹿寨,就是減少代碼冗余新博,提高加載速度。

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          // 抽離自己寫的公共代碼
          chunks: 'initial',
          name: 'common', // 打包后的文件名脚草,任意命名
          minChunks: 2, //最小引用2次
          minSize: 0 // 只要超出0字節(jié)就生成一個新包
        },
        styles: {
          name: 'styles', // 抽離公用樣式
          test: /\.css$/,
          chunks: 'all',
          minChunks: 2,
          enforce: true
        },
        vendor: {
          // 抽離第三方插件
          test: /node_modules/, // 指定是node_modules下的第三方包
          chunks: 'initial',
          name: 'vendor', // 打包后的文件名赫悄,任意命名
          // 設(shè)置優(yōu)先級,防止和自定義的公共代碼提取時被覆蓋,不進行打包
          priority: 10
        }
      }
    }
  }
}

hash

hash 是干嘛用的埂淮?
我們每次打包出來的結(jié)果可能都是同一個文件姑隅,那我上線的時候是不是要替換掉上線的 js,那我怎么知道哪是最新的呢倔撞,我們一般會清一下緩存讲仰。而 hash 就是為了解決這個問題而存在的

我們此時在改一些 webpack.config.js 的配置

module.exports = {
  //...
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash:8].js'
  },
  //...
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash:8].css',
      chunkFilename: '[id].[hash:8].css'
    })
  ]
}

減少 resolve 的解析,配置別名

如果我們可以精簡 resolve 配置痪蝇,讓 webpack 在查詢模塊路徑時盡可能快速地定位到需要的模塊鄙陡,不做額外的查詢工作,那么 webpack 的構(gòu)建速度也會快一些

module.exports = {
  resolve: {
    /**
     * alias: 別名的配置
     *
     * extensions: 自動解析確定的擴展,
     *    比如 import 'xxx/theme.css' 可以在extensions 中添加 '.css'躏啰, 引入方式則為 import 'xxx/theme'
     *    @default ['.wasm', '.mjs', '.js', '.json']
     *
     * modules 告訴 webpack 解析模塊時應該搜索的目錄
     *   如果你想要添加一個目錄到模塊搜索目錄趁矾,此目錄優(yōu)先于 node_modules/ 搜索
     *   這樣配置在某種程度上可以簡化模塊的查找,提升構(gòu)建速度 @default node_modules 優(yōu)先
     */
    alias: {
      '@': path.resolve(__dirname, 'src'),
      tool$: path.resolve(__dirname, 'src/utils/tool.js') // 給定對象的鍵后的末尾添加 $给僵,以表示精準匹配
    },
    extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx'],
    modules: [path.resolve(__dirname, 'src'), 'node_modules']
  }
}

webpack-dev-serve

上面講到了都是如何打包文件毫捣,但是開發(fā)中我們需要一個本地服務(wù),這時我們可以使用 webpack-dev-server 在本地開啟一個簡單的靜態(tài)服務(wù)來進行開發(fā)帝际。

webpack-dev-server 是 webpack 官方提供的一個工具蔓同,可以基于當前的 webpack 構(gòu)建配置快速啟動一個靜態(tài)服務(wù)。當 modedevelopment 時蹲诀,會具備 hot reload 的功能斑粱,即當源碼文件變化時,會即時更新當前頁面侧甫,以便你看到最新的效果珊佣。...

npm install webpack-dev-server -D

package.json 中 scripts 中添加

"start": "webpack-dev-server --mode development"

默認開啟一個本地服務(wù)的窗口 http://localhost:8080/ 便于開發(fā)

配置開發(fā)服務(wù)器

我們可以對 webpack-dev-server 做針對性的配置

module.exports = {
  // 配置開發(fā)服務(wù)器
  devServer: {
    port: 1234,
    open: true, // 自動打開瀏覽器
    compress: true // 服務(wù)器壓縮
    //... proxy、hot
  }
}
  • contentBase: 服務(wù)器訪問的根目錄(可用于訪問靜態(tài)資源)
  • port: 端口
  • open: 自動打開瀏覽器

模塊熱替換(hot module replacement)

模塊熱替換(HMR - Hot Module Replacement)功能會在應用程序運行過程中替換披粟、添加或刪除模塊咒锻,而無需重新加載整個頁面。主要是通過以下幾種方式守屉,來顯著加快開發(fā)速度:

  • 保留在完全重新加載頁面時丟失的應用程序狀態(tài)惑艇。
  • 只更新變更內(nèi)容,以節(jié)省寶貴的開發(fā)時間拇泛。
  • 調(diào)整樣式更加快速 - 幾乎相當于在瀏覽器調(diào)試器中更改樣式滨巴。

上面我們 npm start 后修改一次文件,頁面就會刷新一次俺叭。這樣就存在很大問題了恭取,比如我們使用 redux, vuex 等插件,頁面一刷新那么存放在 redux, vuex 中的東西就會丟失熄守,非常不利于我們的開發(fā)蜈垮。

HMR 配合 webpack-dev-server 耗跛,首先我們配置下 webpack.config.js

const webpack = require('webpack')

module.exports = {
  devServer: {
    //...
    hot: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
    //...
  ]
}

配置后還不行,因為 webpack 還不知道你要更新哪里, 修改 src/index.js 文件, 添加

if (module.hot) {
  module.hot.accept()
}

重啟服務(wù)攒发,npm start 之后调塌,修改引入 index.js 文件后,頁面就不會重新刷新了惠猿,這便實現(xiàn)了 HMR

但是但是有個問題是羔砾,你修改 css/less 等樣式文件并未發(fā)生改變, what ?

HMR 修改樣式表 需要借助于 style-loader偶妖, 而我們之前用的是 MiniCssExtractPlugin.loader姜凄, 這也好辦,修改其中一個 rules 就可以了餐屎,我們可以試試改

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          // MiniCssExtractPlugin.loader,
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')] // 添加css中的瀏覽器前綴
            }
          },
          'less-loader'
        ]
      }
    ]
  }
}

這樣我們修改 less 文件就會發(fā)現(xiàn) HMR 已經(jīng)實現(xiàn)了檀葛。

其實,我們可以發(fā)現(xiàn)腹缩,dev 下配置的 loader 為 style-loader , 而生產(chǎn)環(huán)境下則是需要 MiniCssExtractPlugin.loader

這就涉及到了不同環(huán)境之間的配置】赵可以通過 process.env.NODE_ENV 獲取當前是開發(fā)環(huán)境或者是生產(chǎn)環(huán)境藏鹊,然后配置不同的 loader,這里就不做展開了转锈。下一篇文章打算在做一個 react-cli 或者 vue-cli 的配置盘寡,將開發(fā)環(huán)境的配置與生產(chǎn)環(huán)境的配置分開為不同的文件。

結(jié)語

前面講到的知識都是 webpack 的一些基礎(chǔ)的知識撮慨,更多的資料可以查詢webpack 中文官網(wǎng)竿痰,官網(wǎng)講的比較詳細,我這里也是講最常的配置砌溺,也是一篇入門系列的文章影涉,文中涉及的知識點還有很多地方還需要完善,譬如 優(yōu)化 webpack 的構(gòu)建速度规伐, 減小打包的體積等等蟹倾。

學習 webpack 4.0 還需要多實踐,多瞎搞猖闪,筆者也是剛剛學習 webpack 的配置鲜棠,不對之處請各位指出。

下一篇文章打算從零配置一個腳手架培慌,以加深自己對 webpack 的理解豁陆。

本文產(chǎn)生的代碼:webpack-dev

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吵护,隨后出現(xiàn)的幾起案子盒音,更是在濱河造成了極大的恐慌表鳍,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件里逆,死亡現(xiàn)場離奇詭異进胯,居然都是意外死亡,警方通過查閱死者的電腦和手機原押,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門胁镐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诸衔,你說我怎么就攤上這事盯漂。” “怎么了笨农?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵就缆,是天一觀的道長。 經(jīng)常有香客問我谒亦,道長竭宰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任份招,我火速辦了婚禮切揭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锁摔。我一直安慰自己廓旬,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布谐腰。 她就那樣靜靜地躺著孕豹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪十气。 梳的紋絲不亂的頭發(fā)上励背,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音桦踊,去河邊找鬼椅野。 笑死,一個胖子當著我的面吹牛籍胯,可吹牛的內(nèi)容都是我干的竟闪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼杖狼,長吁一口氣:“原來是場噩夢啊……” “哼炼蛤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝶涩,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤理朋,失蹤者是張志新(化名)和其女友劉穎絮识,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗽上,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡次舌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了兽愤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片彼念。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖浅萧,靈堂內(nèi)的尸體忽然破棺而出逐沙,到底是詐尸還是另有隱情,我是刑警寧澤洼畅,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布吩案,位于F島的核電站,受9級特大地震影響帝簇,放射性物質(zhì)發(fā)生泄漏徘郭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一丧肴、第九天 我趴在偏房一處隱蔽的房頂上張望崎岂。 院中可真熱鬧,春花似錦闪湾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至濒憋,卻和暖如春何暇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凛驮。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工裆站, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人黔夭。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓宏胯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親本姥。 傳聞我的和親對象是個殘疾皇子肩袍,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 寫在前面的話 閱讀本文之前,先看下面這個webpack的配置文件,如果每一項你都懂岭粤,那本文能帶給你的收獲也許就比較...
    不忘初心_9a16閱讀 3,232評論 0 17
  • 版權(quán)聲明:本文為博主原創(chuàng)文章顶伞,未經(jīng)博主允許不得轉(zhuǎn)載廉油。 webpack介紹和使用 一牲芋、webpack介紹 1撩笆、由來 ...
    it筱竹閱讀 11,055評論 0 21
  • GitChat技術(shù)雜談 前言 本文較長,為了節(jié)省你的閱讀時間街图,在文前列寫作思路如下: 什么是 webpack浇衬,它要...
    蕭玄辭閱讀 12,679評論 7 110
  • 前言 本文主要從webpack4.x入手,會對平時常用的Webpack配置一一講解餐济,各個功能點都有對應的詳細例子耘擂,...
    BetterChen閱讀 1,944評論 0 3
  • 怎么委婉的表達出我喜歡你醉冤?今天小木給大家盤點了一些可以用來表白的詩句 [先秦] 1、山有木兮木有枝篙悯,心悅君兮君不知...
    木有枝t閱讀 3,045評論 0 0