【webpack 系列】基礎篇

Webpack 基礎篇

基本概念

Webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖,其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundlecss

四個核心概念

  1. 入口(Entry): 構建 Webpack 內部依賴圖的入口模塊
  2. 輸出(Output): 輸出 Webpack 打包好的 Bundles
  3. Loader: 加載器,Webpack 原生只能解析 JavaScript 文件,Loaderwebpack 擁有了加載和解析非 JavaScript 文件的能力。
  4. 插件(Plugins): 擴展 Webpack 的功能,讓 Webpack 具備更多的靈活性。在 Webpack 運行的生命週期中會廣播出許多事件,Plugin 能夠監聽這些事件,在合適的時機經過 Webpack 提供的 API 改變輸出結果。

Webpack 基礎配置

初始化項目

新建一個文件夾 webpack-demo,在該目錄中使用 npm init -y 進行項目初始化。html

mkdir webpack-demo && cd webpack-demo
npm init -y

運行如下命令安裝最新版本或特定版本node

npm i -D webpack
npm i -D webpack@<version>

若是你使用 webpack 4+ 版本,你還須要安裝 CLIwebpack

npm i -D webpack-cli
  • npm i -Dnpm install --save-dev 的縮寫,安裝一個用於開發環境的安裝包
  • npm i -Snpm install --save 的縮寫,安裝一個要打包到生產環境的安裝包

如今安裝的 webpack 版本號是:git

├── webpack@4.42.1
└── webpack-cli@3.3.11

新建 src/index.js 文件:es6

// src/index.js

class HelloComponent {
  constructor (content = '') {
    this.content = content;
    this.render();
  }
  render () {
    const element = document.createElement('div');
    element.innerHTML = this.content;
    document.body.appendChild(element);
  }
}

new HelloComponent('hello webpack');

如今能夠直接執行 npx webpack,默認是 production 模式。
也能夠在 package.json 中的 scripts 裏配置一個 build 命令,模式指定爲 production
webpack 默認會將 ./src/index.js 做爲入口文件,默認打包到 dist/main.jsgithub

// ...
"scripts": {
  "build": "webpack --mode=production"
}
// ...

經過 npm run build 能夠執行咱們定義的命令,這是能夠多了 dist/main.js 文件,這就是打包以後的 js 代碼。web

webpack 配置文件

上面例子中使用的是 webpack 的默認配置,下面咱們來定義更加豐富的自定義配置。npm

根目錄下新建 webpack.config.js 文件json

const path = require('path');

module.exports = {
  mode: 'development', // 模式
  entry: path.resolve(__dirname, 'src/index.js'), // 入口文件
  output: {
    path: path.resolve(__dirname, 'dist'), // 輸出目錄
    filename: 'bundle.js' // 輸出文件名
  }
}

更改咱們的 build 命令,指定 webpack 按照咱們的配置文件來打包文件

"scripts": {
  "build": "webpack --config webpack.config.js"
}

執行 npm run build 能夠看到,dist 目錄下新增了 bundle.js 文件。而且 bundle.js 是在開發模式下打包的,能夠看到更多的信息。

html-webpack-plugin 插件

如今咱們已經有了打包好的 js 文件了,須要添加個 html 文件來引入這個 js 文件在瀏覽器查看效果了。

在實際開發中,爲了不每次修改打包的 js 文件被瀏覽器緩存而看不到最新的代碼,咱們會給打包文件加上 hash,至關於這個文件的版本號。這樣每次修改後打包的 js 文件名都會不一樣,若是人工去修改 html 中的 js 文件名就太麻煩了,咱們能夠藉助 html-webpack-plugin 插件來自動完成這些事情。

安裝 html-webpack-plugin

npm i -D html-webpack-plugin

新建 public/index.html 文件,修改咱們的 webpack.config.js

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'public/index.html'), // 指定模板文件,不指定會生成默認的 index.html 文件
      filename: 'index.html' // 打包後的文件名
    })
  ]
}

執行 npm run build 能夠看到 dist 目錄下新增了 index.html 文件,而且自動將打包好的 bundle.js 文件經過 script 標籤引入了。

webpack-dev-server 開發工具

如今能夠經過瀏覽器直接打開 dist/index.html 查看了,可是這樣每次改完代碼咱們都須要手動 npm run build 一下,這樣太麻煩了。

咱們能夠藉助 webpack-dev-server 來解決這個問題。webpack-dev-server 會提供了一個簡單的 web 服務器,而且可以實時從新加載。

安裝 webpack-dev-server

npm i -D webpack-dev-server

修改 package.json 文件

// package.json
"scripts": {
  "dev": "webpack-dev-server --config webpack.config.js",
  "build": "webpack --config webpack.config.js"
}

npm run dev 以後,默認會在 localhost:8080 下創建服務,經過訪問這個地址能夠訪問到 dist 目錄下的文件。

能夠在 webpack.config.jsdevServer 進行配置

// webpack.config.js

module.exports = {
  // ...
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    port: '9000', // 指定端口,默認是8080
    compress: true // 是否啓用 gzip 壓縮
  }
  //...
}

關於 webpack-dev-server 更多的配置能夠點擊查看

mode

咱們在 package.json 定義了兩條命令,可是 mode 都爲 development。咱們能夠經過設置 process.env.NODE_ENV 的值來區分開發仍是生產環境。

咱們須要安裝一下 cross-env, 來實現跨平臺設置 NODE_ENV

npm i -D cross-env
// package.json
"scripts": {
  "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js",
  "build": "cross-env NODE_ENV=production webpack --config webpack.config.js"
}

修改 webpack.config.js

// webpack.config.js

const isProduction = process.env.NODE_ENV == 'production';

module.exports = {
  mode: isProduction ? 'production' : 'development', // 模式
  // ...
}

設置 mode 的不一樣值能夠啓用相應模式下的 webpack 內置的優化

選項 描述
development 會將 process.env.NODE_ENV 的值設爲 development。啓用 NamedChunksPluginNamedModulesPlugin
production 會將 process.env.NODE_ENV 的值設爲 production。啓用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin.

用 babel 向後兼容 js 語法

如今咱們的代碼雖然已經完成了打包,可是並無被轉義爲低版本的代碼。咱們須要經過 Babel 來將 ECMAScript 2015+ 版本的代碼轉換爲向後兼容的 JavaScript 語法,以便可以運行在當前和舊版本的瀏覽器或其餘環境中。

安裝 babel-loader

npm i -D babel-loader

此外咱們還須要安裝如下依賴

npm i -D @babel/core @babel/preset-env @babel/plugin-transform-runtime
npm i -S @babel/runtime @babel/runtime-corejs3

webpack.config.js 配置 babel-loader

// webpack.config.js 
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: ['babel-loader'],
        exclude: /node_modules/ // 排除 node_modules 目錄
      }
    ]
  }
  // ...
}

建議給 loader 指定 include 或是 exclude,排除一些不須要編譯的目錄能夠提升編譯效率,好比 node_modules 目錄。

有兩種方式配置 babel

  1. 經過 .babelrc 文件配置

根目錄下新建一個 .babelrc 文件,配置以下:

// .babelrc

{
  "presets": ["@babel/preset-env"],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": 3
      }
    ]
  ]
}
  1. webpack 中配置 babel
// webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ["@babel/preset-env"],
            plugins: [
              [
                "@babel/plugin-transform-runtime",
                {
                  "corejs": 3
                }
              ]
            ]
          }
        },
        exclude: /node_modules/
      }
    ]
  }
}

經過執行 npm run dev, 咱們查看 http://localhost:9000/bundle.js 發現已是轉義以後的低版本代碼了。

使用 source map

webpack 打包源代碼時,會很難追蹤到錯誤和警告在源代碼中的原始位置。爲了更容易地追蹤錯誤和警告,JavaScript 提供了 source map 功能,將編譯後的代碼映射回原始源代碼。

在開發環境中,能夠設置 devtool 值爲 inline-source-map,生產環境設置爲 none 或者 source-map

// webpack.config.js
const isProduction = process.env.NODE_ENV == 'production';

module.exports = {
  // ...
  devtool: isProduction ? 'source-map' : 'inline-source-map',
}

使用 source-map 最終會單獨打包出一個 .map 文件,咱們能夠根據報錯信息和 map 文件定位到源代碼。

可是通常不會直接將 .map 文件部署到 CDN,而是將 .map 文件傳到錯誤監控系統,以便咱們能夠解析到出錯的源碼位置。

處理樣式文件

webpack 只能處理 js 文件,若是要處理 css 須要藉助 loader

若是是 .css,咱們須要的 loader 有: style-loadercss-loader,考慮到兼容性問題,還須要 postcss-loaderautoprefixer

若是是 .less, 還須要 less-loaderless

若是是 .sass 的話,還須要 sass-loadernode-sass

安裝相應的依賴

npm i -D style-loader css-loader postcss-loader autoprefixer less-loader less sass-loader node-sass

webpack.config.js 添加 csslesssass loader

// webpack.config.js

module.exports = {
  // ..
  module: {
    rules: [
      // ...
      {
        test: /\.(c|le)ss$/,
        use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'],
        exclude: /node_modules/ // 排除 node_modules 目錄
      },
      {
        test: /\.sass$/,
        use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
        exclude: /node_modules/ // 排除 node_modules 目錄
      }
    ]
  }
}

根目錄新建 postcss.config.js

// postcss.config.js
module.exports = {
  plugins: [
    // 兼容瀏覽器,添加前綴
    require('autoprefixer')({
      overrideBrowserslist: [
        "Android 4.1",
        "iOS 7.1",
        "Chrome > 31",
        "ff > 31",
        "ie >= 8"
        // 'last 10 versions', // 全部主流瀏覽器最近10版本用
      ],
      grid: true
    })
  ]
}

配置完成,新建幾個文件測試一下

/* src/index.css */
div {
  width: 200px;
  height: 100px;
  display: flex;
}
// src/index.less
@color: yellow;
body {
  background: @color;
  display: flex;
}
// src/index.sass
$text-color: orange;
div 
  color: $text-color;
  display: flex;

再在入口文件中引入三個文件

// src/index.css
import './index.css';
import './index.less';
import './index.sass';

咱們能夠看到樣式生效而且 flex 也自動加上瀏覽器前綴了。

須要注意的是 loader 的執行順序是從右向左執行的,執行順序爲:

less-loader/sass-loader => postcss-loader => css-loader => style-loader

  1. less-loader 處理編譯 .less 文件,將其轉爲 css
  2. sass-loader 處理編譯 .sass 文件,將其轉爲 css
  3. postcss-loaderautoprefixer,自動生成瀏覽器兼容性前綴
  4. css-loader 處理 css 中的 @importurl(...)等語句
  5. style-loader 動態建立 style 標籤,將 css 插入到 head

處理圖片、字體等媒體文件

咱們可使用 url-loader 或者 file-loader 來處理本地的資源文件。

file-loader 就是將文件在進行一些處理後(主要是處理文件名和路徑、解析文件 url),將文件移動到輸出的目錄中,同時在 require 文件的地方會返回文件的絕對路徑。

url-loader通常與 file-loader 搭配使用,功能與 file-loader 相似,若是文件小於限制的大小,則會返回 base64 編碼。

須要同時安裝 file-loaderurl-loader

npm i -D file-loader url-loader

配置 webpack.config.js

// webpack.config.js

module.exports = {
  // ..
  module: {
    rules: [
      // ...
      {
        test: /\.(jpe?g|png|gif|webp|svg|eot|ttf|woff|woff2)$/i,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10240, // 10K 資源大小小於 10K 時,將資源轉換爲 base64,超過 10K,將圖片拷貝到 dist 目錄
              name: '[name]_[hash:6].[ext]', // 設置文件名,默認狀況下,生成的文件的文件名就是文件內容的 MD5 哈希值並會保留所引用資源的原始擴展名
              outputPath: 'assets', // 輸出目錄
              esModule: false // 表示是否使用es6模塊的導出,默認是啓用的
            }
          }
        ],
        exclude: /node_modules/
      }
    ]
  }
}

咱們修改 src/index.sass 文件

// src/index.sass
$text-color: orange;
div 
  color: $text-color;
  display: flex;
  background: url('../images/author.jpg');

修改了配置文件,咱們從新 npm run dev 一下,能夠看到圖片地址已經被替換了

npm run build 能夠看到 dist/assets 有這個文件

注意此時若是須要在 html 文件中引用這個圖片須要這樣寫

<body>
  <img src="<%= require('../images/author.jpg') %>">
</body>

最終打包以後的路徑是

打包前清空 dist 目錄

咱們修改文件打包以後,生成的 hash 值和以前 dist 中的不同,會致使 dist 下的文件愈來愈多,因此咱們須要在打包前先清空 dist 目錄。

安裝 clean-webpack-plugin

npm i -D clean-webpack-plugin
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  //...
  plugins: [
    // ...
    new CleanWebpackPlugin() 
  ]
}

這樣每次打包前就會自動清除 dist 目錄下的文件了。

最後

經過上面的實踐,咱們對 webpack 的基礎配置有了一個初步的瞭解。本文全部代碼能夠查看github

後續將會繼續推出 webpack 系列的其餘內容哦~

喜歡本文的話點個贊吧~

更多精彩內容,歡迎關注微信公衆號~

相關文章
相關標籤/搜索