還學不會webpack?看這篇!

摘要: webpack入門教程。javascript

Fundebug經受權轉載,版權歸原做者全部。css

Webpack已經流行很久了,但不少同窗使用webpack時仍是一頭霧水,一下看到那麼多文檔、各類配置、各類loader、plugin立馬就暈頭轉向了。我也不例外,以致於很長一段時間對webpack都是隻知其一;不知其二的狀態。可是想要繼續作好前端,webpack是必須得跨過的一道坎,其實掌握webpack並不難,只是咱們沒有找到正確的方法。本文就是我本身在學習webpack時的一點心得體會,供你們參考。html

什麼是webpack?

一句話歸納:webpack是一個模塊打包工具(module bundler)。重點在於兩個關鍵詞「模塊」和「打包」。什麼是模塊呢?咱們回顧一下曾經的前端開發方式,js文件經過script標籤靜態引入,js文件之間因爲沒有強依賴關係,若是文件1要用到文件2的某些方法或變量,則必須將文件1放到文件2後面加載。隨着項目的增大,js文件之間的依賴關係愈加錯綜複雜,維護難度也愈來愈高。這樣的困境驅使着前端工程師們不斷探索新的開發模式,從後端、app的開發模式中咱們得到靈感,爲何不能引入「模塊」的概念讓js文件之間能夠相互引用呢?模塊1要使用模塊2的功能,只須要在該模塊1中明確引用模塊2就好了,而不用擔憂它們的排列順序。基於這種理念,CommonJSAMD規範被創造了出來,而後有了require.js、system.js這樣的前端模塊加載工具和node的模塊系統,直到如今流行的es6 module前端

模塊的引入解決了文件之間依賴引用的問題,而打包則解決了文件過多的問題。當項目規模增大,模塊的數量數以千計,瀏覽器若是要加載如此多的文件,頁面加載的速度勢必會受影響,而bundler能夠把多個關聯的文件打包到一塊兒從而大量減小文件的數量提升網頁加載性能。提供模塊化的開發方式和編譯打包功能就是webpack的核心,其餘不少功能都圍繞它們展開。java

核心概念

Module(模塊)

對於webpack,模塊不只僅是javascript模塊,它包括了任何類型的源文件,不論是圖片、字體、json文件都是一個個模塊。Webpack支持如下的方式引用模塊:node

Dependency Graph(依賴關係圖)

所謂的依賴關係圖是webpack根據每一個模塊之間的依賴關係遞歸生成的一張內部邏輯圖,有了這張依賴關係圖,webpack就能按圖索驥把全部須要模塊打包成一個bundle文件了。react

Entry(入口)

繪製依賴關係圖的起始文件被稱爲entry。默認的entry爲 ./src/index.js,或者咱們能夠在配置文件中配置。entry能夠爲一個也能夠爲多個。webpack

單個entry:git

module.exports = {
  entry: './src/index.js'
}

或者es6

module.exports = {
  entry: {
    main: './src/index.js'
  }
};

多個entry,一個chunk

咱們也能夠指定多個獨立的文件爲entry,但將它們打包到一個chunk中,此種方法被稱爲 multi-main entry,咱們須要傳入文件路徑的數組:

module.exports = {
  entry: ['./src/index.js', './src/index2.js', './src/index3.js']
}

可是改種方法的靈活性和擴展性有限,所以並不推薦使用。

多個entry,多個chunk

若是有多個entry,而且每一個entry生成對應的chunk,咱們須要傳入object:

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js'
  }
};

這種寫法有最好的靈活性和擴展性,支持和其餘的局部配置(partial configuration)進行合併。好比將開發環境和生產的配置分離,並抽離出公共的配置,在不一樣的環境下運行時再將環境配置和公共配置進行合併。

Output(出口)

有了入口,對應的就有出口。顧名思義,出口就是webpack打包完成的輸出,output定義了輸出的路徑和文件名稱。Webpack的默認的輸出路徑爲 ./dist/main.js。一樣,咱們能夠在配置文件中配置output:

module.exports = {
  entry: './src/index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js'
  }
};

多個entry的狀況

當有多個entry的時候,一個entry應該對應一個output,此時輸出的文件名須要使用替換符(substitutions)聲明以確保文件名的惟一性,例如使用入口模塊的名稱:

module.exports = {
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}

最終在 ./dist 路徑下面會生成 app.jssearch.js兩個bundle文件。

Loader

Webpack自身只支持加載js和json模塊,而webpack的理念是讓全部的文件都能被引用和加載並生成依賴關係圖,因此loader出場了。Loader能讓webpack可以去處理其餘類型的文件(好比圖片、字體文件、xml)。咱們能夠在配置文件中這樣定義一個loader:

webpack.config.js

module.exports = {
  module: {
    rules: [
      { 
        test: /\.txt$/, 
        use: 'raw-loader' 
      }
    ]
  }
};

其中test定義了須要被轉化的文件或者文件類型,use定義了對該文件進行轉化的loader的類型。該條配置至關於告訴webpack當遇到一個txt文件的引用時(使用require或者import進行引用),先用raw-loader轉換一下該文件再把它打包進bundle。

還有其餘各類類型的loader,好比加載css文件的css-loader,加載圖片和字體文件的file-loader,加載html文件的html-loader,將最新JS語法轉換成ES5的babel-loader等等。完整列表請參考 webpack loaders

Plugin(插件)

Plugin和loader是兩個比較混淆和模糊的概念。Loader是用來轉換和加載特定類型的文件,因此loader的執行層面是單個的源文件。而plugin能夠實現的功能更強大,plugin能夠監聽webpack處理過程當中的關鍵事件,深度集成進webpack的編譯器,能夠說plugin的執行層面是整個構建過程。Plugin系統是構成webpack的主幹,webpack自身也基於plugin系統搭建,webpack有豐富的內置插件和外部插件,而且容許用戶自定義插件。官方列出的插件有 這些

與loader不一樣,使用plugin咱們必須先引用該插件,例如:

const webpack = require('webpack'); // 用於引用webpack內置插件
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 外部插件

module.exports = {
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

推薦你們使用Fundebug,一款很好用的BUG監控工具~

實踐

瞭解webpack的基本概念以後,咱們經過實踐來加深理解。接下來,咱們使用webpack搭建一個簡易的react腳手架。

建立項目

首先建立react-webpack-starter項目並使用 npm init 初始化。

安裝依賴

安裝react

npm i react react-dom

安裝webpack相關

npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader

安裝webpack-cli後能夠在命令行中執行webpack命令;webpack-dev-server提供了簡易的web服務器,而且在修改文件以後自動執行webpack的編譯操做並自動刷新瀏覽器,省去了重複的手動操做;html-webpack-plugin用於自動生成index.html文件,而且在index.html中自動添加對bundle文件的引用;style-loadercss-loader用於加載css文件。

安裝babel相關

因爲react中使用了class, import這樣的es6的語法,爲了提升網站的瀏覽器兼容性,咱們須要用babel轉換一下。

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

其中@babel/core是babel的核心模塊,包含了babel的核心功能;@babel/preset-env支持轉換ES6以及更新的js語法,而且可根據須要兼容的瀏覽器類型選擇加載的plugin從而精簡生成的代碼;@babel/preset-react包含了babel轉換react所須要的plugin;babel-loader是webpack的babel加載器。

配置webpack

在項目根目錄下面新建webpack.config.js,內容以下:

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_module/,
        use: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'] // 注意排列順序,執行順序與排列順序相反
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
}

其中HtmlWebpackPlugin使用自定義的模版來生成html 文件,模版的內容以下:

./src/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>My React App</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

配置babel

在項目根目錄下面新建.babelrc文件,配置咱們安裝的兩個babel preset:

.babelrc

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

生成react應用根節點

./src/index

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

ReactDOM.render(<App />, document.getElementById('app'));

./src/component/App.js

import React, { Component } from 'react';
import './App.css';

export default class App extends Component {
  render() {
    return (
      <div>
        my react webpack starter
      </div>
    )
  }
}

./src/components/App.css

body{
  font-size: 60px;
  font-weight: bolder;
  color: red;
  text-transform: uppercase;
}

配置 package.json

最後,在package.json文件裏面加上兩個scripts,用來運行開發服務器和打包:

package.json

"scripts": {
  "start": "webpack-dev-server --mode development --open --hot",
  "build": "webpack --mode production"
}

注意,咱們啓用了webpack-dev-server的模塊熱更新功能(HMR),進一步提升咱們的開發效率。

到此一個最簡版本的react腳手架就搭建完成了,咱們運行一下看看效果:

是否是沒有想象中的那麼難呢?固然webpack還有不少其餘的功能和特性須要掌握,但願在參考本文以後你們進一步的學習更加順利 😊。

本文demo地址:https://github.com/MudOnTire/...

最後,推薦你們使用Fundebug,一款很好用的BUG監控工具~

關於Fundebug

Fundebug專一於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有陽光保險、核桃編程、荔枝FM、掌門1對一、微脈、青團社等衆多品牌企業。歡迎你們免費試用

相關文章
相關標籤/搜索