完結!手把手教你使用webpack打包前端組件(三)

手把手教你使用webpack打包前端組件(三)

這是我參與更文挑戰的第9天,活動詳情查看: 更文挑戰javascript

回顧前面

回顧前兩篇文章中,咱們從一個現成的webpack-template中,逐步逐步地修改構建出了一個組件調試的頁面,當組件調試沒問題以後,咱們就要對組件進行一個打包操做讓其餘用戶可使用。css

若是尚未閱讀第一,二篇的小夥伴們, 請點擊閱讀: 手把手教你使用webpack打包前端組件(一)html

手把手教你使用webpack打包前端組件(二)前端

打包組件

執行npm run build命令進行項目打包 ~ ~vue

9.png

打包後分別有htmljs文件,咱們使用編輯器打開Drag.html,發現html中已經幫咱們引入了Drag.js了,其實在這裏邊它已經引入better-draggable-ball了,再使用瀏覽器打開後發現拖拽球是能夠被正常顯示出來的。java

當咱們從新建立一個HTML文件,引入better-draggable-ball時,再按原來ts中的寫法會發現:node

Drag is not definedwebpack

難道咱們只能引入已經配置好配置項的Drag麼???es6

強大的webpack也給咱們提供了output.library選項,webpack打包時能夠將你的項目做爲一個庫來導出web

微信截圖_20210624190019.png

關於 webpack library選項配置文檔地址

咱們修改webpack.config.ts配置文件,將咱們的項目中的better-draggable-ball做爲一個庫來導出

web

entry: {
    'better-draggable-ball': './src/components/better-draggable-ball/index.ts'
  },
複製代碼

output屬性中添加library屬性。

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    clean: true,
    library:'betterDraggableBall',
  },
複製代碼

plugins屬性中的HtmlWebpackPlugin進行刪除,由於咱們已經不須要導出HTML文件了,只須要導出js文件讓其用戶去引用就能夠了。

plugins: [
    new ESLintPlugin({
      extensions: ['js', 'ts'],
      exclude: '/node_modules/',
    }),
  ],
複製代碼

附上完整的webpack.config.ts配置文件代碼:

import * as path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import * as webpack from 'webpack';

const config: webpack.Configuration = {
  mode: 'production',
  entry: {
    'better-draggable-ball': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    clean: true,
    library: 'betterDraggableBall'
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          // 將 JS 字符串生成爲 style 節點
          'style-loader',
          // 將 CSS 轉化成 CommonJS 模塊
          'css-loader',
          // 將 Sass 編譯成 CSS
          'sass-loader',
        ],
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new ESLintPlugin({
      extensions: ['js', 'ts'],
      exclude: '/node_modules/',
    }),

  ],
};

export default config;
複製代碼

接下來咱們再打包一下,能夠看到此次dist文件夾中只輸出了better-draggable-ball文件。

微信截圖_20210624195410.png

接下來,咱們在dist文件夾中建立一個test.html文件,利用script標籤引入一下,而後使用console.log來打印下betterDraggableBall看看裏邊是什麼?

微信截圖_20210624200736.png

很明顯,打印出來的是個Object,裏邊只有一個default的函數,咱們打印下試試。

微信截圖_20210624215507.png

是一個函數,咱們仔細一看,誒?這不是咱們的Drag麼?

咱們試試看能不能new一下試試 。

!!! 注意:打包後 庫的位置是在.default中 !!!

<script src="../dist/better-draggable-ball.js"></script>
<script> window.onload = () => { let DragDom = document.getElementById('drag') Drag = new betterDraggableBall.default(DragDom) console.log(Drag); } </script>
複製代碼

微信截圖_20210624222304.png

webpack.config.ts中配置下library,讓default中的數據做爲默認導出對象,type屬性是配置庫的暴露方式,以後再打包一下

library: {
      name: 'betterDraggableBall',
      type: 'umd',
      export: 'default',
    },
複製代碼

打印下betterDraggableBall對象,此次咱們能夠看到沒有default這個屬性了,而是將default裏的內容放到了betterDraggableBall對象根部了,也就是說如今能夠直接直接new一個betterDraggableBall類了

微信截圖_20210625143444.png

咱們如今只達到了能夠經過script標籤來引入組件了

支持更多的引入方式

  • 定個小目標
    • 咱們須要輸出的文件是(分別爲壓縮和未壓縮版本):
      • 一個 CommonJS 格式的 js 文件
      • 一個 UMD 格式的 js 文件
      • ESM格式的js文件

這裏給你們簡單的講下這些格式

CommonJS

CommonJS是服務器端模塊的規範,Node.js採用了這個規範。,主要語法:好比加載模塊使用的是require方法,導出模塊使用的是exportCommonJS 加載模塊是同步的,因此只有加載完成才能執行後面的操做。

AMD

AMD 全稱 Asyncchronous Module Definition,通常應用在瀏覽器端(這是與 CommonJS規範最大的不一樣點),最著名的 AMD 加載器是 RequireJS 。目前因爲 webpack 的流行, AMD 這一模塊化方案已逐漸退出市場。

UMD

UMDAMDCommonJS的糅合,以及最傳統的全局變量模式。全局變量模式便是把庫的入口掛載在一個全局變量(window.xxx)上,頁面上的任何位置都能隨時取用,屬於最傳統的 js 插件加載方案,它的出現也是解決跨平臺的問題。UMD先判斷是否支持Node.js的模塊(exports)是否存在,存在則使用Node.js模塊模式。在判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。

ESM

esm 即 es6 模塊,在以前經常使用的是 CommonJS 和基於 AMD 的其餘模塊系統,ES Modules 的關鍵字是 importexport,也是目前最流行的一種導入方式。

咱們須要修改webpack的配置文件,以前咱們打包項目都是使用單獨的一種配置方式,可是咱們如今須要導出多種類型文件,這時webpack給咱們提供了導出多種配置方式的寫法(webpack 3.1.0 起支持),把webpack.config.ts修改以下:

import * as path from 'path';
import { Configuration as webpackConfiguration } from 'webpack';
import ESLintPlugin from 'eslint-webpack-plugin';

const outputConfig: webpackConfiguration[] = [
  {
    output: {
      path: path.resolve(__dirname, 'dist/commonjs'),
      filename: '[name].js',
      clean: true,
      library: {
        name: 'betterDraggableBall',
        type: 'commonjs',
        export: 'default',
      },
    },
  },
  {
    output: {
      path: path.resolve(__dirname, 'dist/umd'),
      filename: '[name].js',
      clean: true,
      library: {
        name: 'betterDraggableBall',
        type: 'umd',
        export: 'default',
      },
    },
  },
  {
    output: {
      path: path.resolve(__dirname, 'dist/module'),
      filename: '[name].js',
      clean: true,
      module: true,
      library: {
        type: 'module',
      },
    },
    experiments: {
      outputModule: true,
    },
  },
];

const baseConfig: webpackConfiguration = {
  mode: 'development',
  entry: {
    'better-draggable-ball': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // 將 JS 字符串生成爲 style 節點
          'style-loader',
          // 將 CSS 轉化成 CommonJS 模塊
          'css-loader',
          // 將 Sass 編譯成 CSS
          'sass-loader',
        ],
      },

      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  plugins: [
    new ESLintPlugin({
      extensions: ['js', 'ts'],
      exclude: '/node_modules/',
    }),

  ],
};
const config:webpackConfiguration[]|[] = [];
for (let i: number = 0; i < outputConfig.length; i += 1) {
  config[i] = Object.assign(outputConfig[i], baseConfig);
}

export default config;
複製代碼

這裏邊,我定義了2個數組,一個是baseConfig,它用來存放webpackConfig的基本配置,另一個是outputConfig,它存放了三種導出方式,分別爲commonjsumdmodule,最後我使用了循環和對象合併方法把基本配置對象和不一樣的output屬性進行一個合併生成導出一個新的webpackConfig模塊。

// 合併的語句
const config:webpackConfiguration[]|[] = [];
for (let i: number = 0; i < outputConfig.length; i += 1) {
  config[i] = Object.assign(outputConfig[i], baseConfig);
}
複製代碼

咱們打包試一下,看看是否是生成了多種導入方式的文件:

2.png

nice!接下來咱們建立一個普通的HTML文件使用script標籤引用試一下(umd)。

<script src="./dist/umd/better-draggable-ball.js"></script>
<script> console.log(betterDraggableBall); </script>
複製代碼

3.png

接下來,再試試ESM版本的,這裏我新建了一個vue vite項目,在項目中的組件中引入它。

// 忽略一些代碼 只列出主要代碼
  import Drag from './better-draggable-ball'
 
  setup: () => {
    const DragDom=ref<HTMLElement|null>(null)
    // 拖拽組件 初始化
    onMounted(()=>{
      new Drag(DragDom.value, {
        defaultPosition: { x: 10, y: 10 },
        autoAdsorbent: true,
      });
    })
    return{
      DragDom
    }
  }
複製代碼

77.gif

壓縮環節

爲何要進行壓縮處理

一般,開源的插件、庫代碼都會提供兩種版本:

  1. 可讀版,通常爲開發人員準備的
  2. 壓縮版,通常爲生產環境中提供使用的

壓縮版的好處:

  1. 減小了文件的體積
  2. 減小了網絡傳輸時使用的帶寬佔用
  3. 減小了服務器的壓力

咱們使用的是webpack5版本以上的,無需terser-webpack-plugin插件,直接使用就能夠了。

注意:webpack4版本須要安裝!!

npm install terser-webpack-plugin --save-dev
複製代碼

但咱們還須要執行下如下命令,安裝相關聲明文件。

npm i --save-dev @types/terser-webpack-plugin
複製代碼

baseConfig的入口屬性中,添加一個better-draggable-ball.min,做爲壓縮版的文件。

entry: {
    'better-draggable-ball': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件
    'better-draggable-ball.min': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件(壓縮版本)
  },
// ... ...
複製代碼

baseConfig中添加optimization對象,將含有min的文件進行壓縮處理。

optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: 4,
        include: /\.min\.js$/,
        terserOptions: {
          format: {
            comments: false,
          },
        },
        test: /\.js(\?.*)?$/i,
        extractComments: false,
      }),
    ],
  },
複製代碼

baseConfig中添加devtool屬性,是選擇一種 source map 格式來加強調試過程。不一樣的值會明顯影響到構建(build)和從新構建(rebuild)的速度 ( 官方解釋 )詳細配置請閱讀 Devtool 配置項

devtool:'cheap-module-source-map',
複製代碼

配置完以後,執行npm run build將項目進行打包 ~ ~

6.png

拿打包後的commonjs版本的插件對比一下,壓縮版本(min.js)比未壓縮版本減小了約50%的體積,這大大提高了瀏覽器加載該插件的速度。

關於生成後的map文件

Source map就是一個信息文件,裏面儲存着位置信息。也就是說,轉換後的代碼的每個位置,所對應的轉換前的位置。有了它,瀏覽器開發者工具會調用 source map 來幫助解析,在出錯的時候,除錯工具將直接顯示原始代碼,而不是轉換後的代碼。這無疑在調試過程當中帶來了很大方便。

這是由於上面的配置文件設置了devtool

devtool: 'cheap-module-source-map'
複製代碼

最後

本系列的教程也到此結束了,很感謝你們的觀看,但願這三篇文章對你們有所幫助!

若是你對文章有什麼建議能夠留言在評論區哦

😀😀 關注我,不迷路! 😀😀

相關文章
相關標籤/搜索