Webpack學習記錄

// 一個常見的`webpack`配置文件
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
        entry: __dirname + "/app/main.js", //已多次提及的唯一入口文件
        output: {
            path: __dirname + "/build",  //打包后的文件存放的地方
            filename: "bundle-[hash].js"  //打包后輸出文件的文件名
        },
        devtool: 'none',
        devServer: {
            contentBase: "./public", //本地服務(wù)器所加載的頁面所在的目錄
            historyApiFallback: true, //不跳轉(zhuǎn)
            inline: true, //構(gòu)建變化后自動刷新網(wǎng)頁實現(xiàn)實時預(yù)覽
            hot: true
        },
        module: {
            rules: [{
                    test: /(\.jsx|\.js)$/,
                    use: {
                        loader: "babel-loader"
                    },
                    exclude: /node_modules/
                }, {
                    test: /\.css$/,
                    use: ExtractTextPlugin.extract({
                        fallback: "style-loader",
                        use: [{
                            loader: "css-loader",
                            options: {
                                modules: true,
                                localIdentName: '[name]__[local]--[hash:base64:5]'
                            }
                        }, {
                            loader: "postcss-loader"
                        }],
                    })
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('123'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new 一個這個插件的實例,并傳入相關(guān)的參數(shù)
        }),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("style.css")
    ]
};

注:“_dirname”是node.js的一個全局變量,指向當前執(zhí)行腳本所在的目錄。

幾個核心概念。

  • Entry: 入口,webpack執(zhí)行構(gòu)建的第一步將從Entry開始,可抽象成輸入
  • Module: 模塊,在Webpack里一切皆模塊,一個模塊對應(yīng)一個文件。Webpack會從配置的Entry開始遞歸找出所有依賴的模塊。
  • Chunk: 代碼塊,一個Chunk由多個模塊組合而成,用于代碼合并與分割。
  • Loader: 模塊轉(zhuǎn)換器,用于將模塊的原內(nèi)容按照需求轉(zhuǎn)換成新內(nèi)容。項目中需要的每個Loader都需要安裝。
  • Plugin: 擴展插件,在Webpack構(gòu)建流程中的特定時機注入擴展邏輯,來改變構(gòu)建結(jié)果或做我們想要的事情。
  • Output: 輸出結(jié)果,在Webpack經(jīng)過一系列處理并得出最終想要的代碼后輸出結(jié)果。

Webpack在啟動后會從Entry里面配置的Module開始,遞歸解析Entry依賴的所有Module。每找到一個Module,就會根據(jù)配置的Lodaer去找出對應(yīng)的轉(zhuǎn)換規(guī)則,對Module進行轉(zhuǎn)換后,再解析出當前Module依賴的Module。這些模塊會以Entry為單位進行分組,一個Entry及其所有依賴的Module被分到一個組也就是一個Chunk。最后,Webpack會將所有Chunk轉(zhuǎn)換成文件輸出。在整個流程中,Webpack會在恰當?shù)臅r機執(zhí)行Plugin里定義的邏輯。

DevServer

使用DevServer,DevServer會啟動一個HTTP服務(wù)器用于服務(wù)網(wǎng)頁請求,同時會幫助啟動Webpack,并接收Webpack發(fā)出的文件變更信號,通過WebSocket協(xié)議自動刷新網(wǎng)頁做到實時預(yù)覽。

執(zhí)行打包任務(wù)

可以在package.json里對scripts對象進行設(shè)置即可。

 {
  "scripts": {
    "start": "webpack-dev-server --open --hot --progress --colors --host localhost",
    "build": "rm -rf ./dist && webpack --progress --colors"
  },
 }

npm的start命令是一個特殊的腳本名稱,其特殊性表現(xiàn)在,在命令行中使用npm start就可以執(zhí)行其對于的命令,如果對應(yīng)的此腳本名稱不是start,想要在命令行中運行時,需要這樣用npm run {script name}npm run build

--open --host localhost
//執(zhí)行npm start后自動打開瀏覽器

resolve.alias && ProvidePlugin

有時候我們在項目中會需要頻繁引入同一個路徑的文件,如果需要引入的次數(shù)特別多,我們就得在每一次引入都要寫一長串的地址,那么我們有沒有什么方法可以偷點懶呢,我們可以通過調(diào)整webpack里的配置達到“偷一點小懶”的目的。

   resolve.alias這個配置項相當于為文件目錄配置一個別名

使用resolve.alias配置的用法如下

module.exports = {
  entry: 
  {
    main:'./main.js',
  },
  output: {
    path:__dirname+'/dist',
    filename: '[name].js'
  },
  resolve:{
    //配置別名,在項目中可縮減引用路徑
    alias: {
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      '&': resolve('src/components'),
      'api': resolve('src/api'),
      'assets': resolve('src/assets')
    }
  },
  plugins: [
   
  ]
};

這樣配置后在使用的時候就可以直接

import http from '@/utils/http'

代替

import http from 'src/utils/http'
reslove.alias可以讓我們不用重復(fù)的去寫一長串的路徑,但是在使用的時候還是得引入,如果我們連引入都懶得引入呢?webpack為我們提供了ProvidePlugin這個幫我們解決問題的插件

那么ProvidePlugin要怎么使用呢?
webpack.config.js

const webpack = require('webpack')
module.exports = {
  entry: 
  {
    main:'./main.js',
  },
  output: {
    path:__dirname+'/dist',
    filename: '[name].js'
  },
  resolve:{
    //配置別名,在項目中可縮減引用路徑
    alias: {
      
    }
  },
  plugins: [
    //提供全局的變量,在模塊中使用無需用require引入
    new webpack.ProvidePlugin({
      $config: [resolve(`src/data/config/${process.env.CONFIG_ENV}.env.js`), 'default'],
    }),
  ]
};

使用的時候就可以寄直接將 $config作為一個全局變量來使用

編寫一個plugin

plugin可以監(jiān)聽webpack處理過程中的關(guān)鍵事件,深度集成進webpack的編譯器,可以說plugin的執(zhí)行層面是整個構(gòu)建過程。Plugin系統(tǒng)是構(gòu)成webpack的主干,webpack自身也基于plugin系統(tǒng)搭建,webpack有豐富的內(nèi)置插件和外部插件,并且允許用戶自定義插件。

插件的組成部分

  • 一個javaScript命名函數(shù),并暴露出去
  • 在插件函數(shù)的prototype上定義一個apply方法,注入complier對象
  • 指定一個綁定到webpack自身的事件鉤子
  • 處理webpack內(nèi)部實例的特定數(shù)據(jù)
  • 功能完成后調(diào)用webpack提供的回調(diào)
function MyPlugin(options) {}
// 2.函數(shù)原型上的 apply 方法會注入 compiler 對象
MyPlugin.prototype.apply = function(compiler) {
  // 3.compiler 對象上掛載了相應(yīng)的 webpack 事件鉤子 4.事件鉤子的回調(diào)函數(shù)里能拿到編譯后的 compilation 對象
  compiler.plugin('emit', (compilation, callback) => {
    ...
  })
}
// 1.獨立的 JS 模塊,暴露相應(yīng)的函數(shù)
module.exports = MyPlugin

Compiler 和 Compilation

compiler對象和compilation對象是webpack插件開發(fā)中最重要的兩個資源,那他們分別是什么呢?

  • compiler 對象代表了完整的 webpack 環(huán)境配置。這個對象在啟動 webpack 時被一次性建立,并配置好所有可操作的設(shè)置,包括 options,loader 和 plugin。當在 webpack 環(huán)境中應(yīng)用一個插件時,插件將收到此 compiler 對象的引用??梢允褂盟鼇碓L問 webpack 的主環(huán)境。

  • compilation 對象代表了一次資源版本構(gòu)建。當運行 webpack 開發(fā)環(huán)境中間件時,每當檢測到一個文件變化,就會創(chuàng)建一個新的 compilation,從而生成一組新的編譯資源。一個 compilation 對象表現(xiàn)了當前的模塊資源、編譯生成資源、變化的文件、以及被跟蹤依賴的狀態(tài)信息。compilation 對象也提供了很多關(guān)鍵時機的回調(diào),以供插件做自定義處理時選擇使用。

compiler 對象

compiler 即 webpack 的編輯器對象,在調(diào)用 webpack 時,會自動初始化 compiler 對象,源碼如下:

// webpack/lib/webpack.js
const Compiler = require("./Compiler")

const webpack = (options, callback) => {
  ...
  options = new WebpackOptionsDefaulter().process(options) // 初始化 webpack 各配置參數(shù)
  let compiler = new Compiler(options.context)             // 初始化 compiler 對象,這里 options.context 為 process.cwd()
  compiler.options = options                               // 往 compiler 添加初始化參數(shù)
  new NodeEnvironmentPlugin().apply(compiler)              // 往 compiler 添加 Node 環(huán)境相關(guān)方法
  for (const plugin of options.plugins) {
    plugin.apply(compiler);
  }
  ...
}
compilation 對象

結(jié)合源碼來理解下上面這段話,首先 webpack 在每次執(zhí)行時會調(diào)用 compiler.run() (源碼位置),接著追蹤 onCompiled 函數(shù)傳入的 compilation 參數(shù),可以發(fā)現(xiàn) compilation 來自構(gòu)造函數(shù) Compilation。

// webpack/lib/Compiler.js
const Compilation = require("./Compilation");

newCompilation(params) {
  const compilation = new Compilation(this);
  ...
  return compilation;
}

path.join()與path.resolve()的區(qū)別

path 是 node.js內(nèi)置的package,用來處理路徑

  • path.join([path1],[path2][,...])

    用于連接路徑,對參數(shù)里的路徑片段就行拼接

  • path.resolve([from...][,to])

    將to解析成絕對路徑

path.resolve(_dirname, '/img')
    
console.log(_dirname) //當前文件所在文件夾的絕對路徑
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • webpack 核心 核心概述 entry 入口文件:js 代碼文件,可執(zhí)行的 node 模塊或打包的入口文件。 ...
    coolheadedY閱讀 3,610評論 1 6
  • webpack 構(gòu)建 流程 webpack 整體是一個插件的架構(gòu),所有的功能都是插件的方式集成在構(gòu)建流程中,通過發(fā)...
    Lyan_2ab3閱讀 1,006評論 0 1
  • 基本打包原理 Webpack Loader Webpack Plugin HMR原理 Webpack的性能優(yōu)化 構(gòu)...
    大白兔奶糖味閱讀 182評論 0 0
  • 工作原理概括 基本概念 Entry:入口,Webpack執(zhí)行構(gòu)建的第一步將從Entry開始,可抽象成輸入。 Mod...
    Upcccz閱讀 394評論 0 1
  • 寫在前面:本文是webpack的一個學習筆記,涉及webpack打包流程、plugin、loader的編寫、以及實...
    Bbang呀_閱讀 494評論 0 2

友情鏈接更多精彩內(nèi)容