>  기사  >  웹 프론트엔드  >  webpack을 사용하여 js 라이브러리 구축

webpack을 사용하여 js 라이브러리 구축

hzc
hzc앞으로
2020-07-04 09:54:082678검색

머리말

이전 기사에서 이 시리즈의 독자는 현대 프론트엔드 시스템에서 비즈니스 코드를 능숙하게 작성하는 학생들이라고 말씀드렸습니다. 따라서 이 기사에서는 웹팩 구성을 소개할 때 독특한 점만 언급합니다. 라이브러리 구축 및 나머지 구성은 공식 웹팩 문서를 참조하세요.

출력 제품

라이브러리 구축과 일반 애플리케이션 구축의 가장 큰 차이점은 빌드가 완료된 후 제품 출력에 있습니다.

일반 애플리케이션이 빌드된 후 다음이 출력됩니다.

  • html 파일
  • js 항목 청크, 여러 하위 청크
  • 일부 CSS 파일
  • 그림, 글꼴 파일 등과 같은 여러 기타 리소스

출력 리소스는 많지만 사실 모든 종속성 및 로딩 관계는 html 파일부터 시작하여 레이어별로 결정되었습니다. 즉, 이 html 파일은 실제로 전체 애플리케이션의 입구입니다.

라이브러리가 빌드되면 다음이 출력됩니다.

  • CommonJS 형식의 js 파일
  • UMD 형식의 압축되지 않은 js 파일
  • UMD 형식의 압축된 js 파일
  • 여러 CSS 파일이 포함될 수 있음
  • 포함될 수 있음 여러 다른 리소스 파일

라이브러리 입구는 위에 나열된 js 파일입니다. 어떻게 라이브러리에 3개의 항목 파일이 있을 수 있나요? 조급해하지 말고 내 말을 들어보세요.

CommonJS

CommonJS는 Node.js에서 추진하는 모듈식 사양입니다. 주요 구문에는 module.exports, require() 등이 포함됩니다. webpack이 npm 패키지를 도입하면 실제로는 Node.js 환경에 있는 것을 알 수 있습니다. CommonJS 형식의 이 항목 js 파일(<library name>.common.js)은 다음과 같습니다. 다른 애플리케이션 Node.js 환경에 npm 패키지를 도입하여 사용됩니다. npm 패키지를 참조할 때 npm 패키지의 크기는 일반적으로 크게 고려되지 않으며(자신의 애플리케이션을 빌드할 때 필요한 경우 직접 압축할 수 있음) 디버깅의 편의를 위해 js 항목 파일은 압축되지 않습니다. module.exportsrequire()等;而我们在使用 webpack 引入 npm 包时,实际上是处于 Node.js 环境,由此可知,这个 CommonJS 格式的入口 js 文件(<库名称>.common.js)是供其它应用在 Node.js 环境下引入 npm 包使用的。由于在引用 npm 包时一般不会过多考虑 npm 包的体积(在构建自己的应用时如有需要可自行压缩),且为了方便调试,因此该 js 入口文件是没有经过压缩的。

UMD

UMD 是一个模块化规范大杂烩,除了兼容 CommonJS 外,它还兼容 AMD 模块化规范,以及最传统的全局变量模式。

这边稍微介绍一下 AMD 规范, AMD 全称 Asyncchronous Module Definition ,一般应用在浏览器端(这是与 CommonJS规范最大的不同点),最著名的 AMD 加载器是 RequireJS 。目前由于 webpack 的流行, AMD 这一模块化方案已逐渐退出市场。

全局变量模式就很好理解了,就是把库的入口挂载在一个全局变量(如window.xxx)上,页面上的任何位置都能随时取用,属于最传统的 js 插件加载方案。

由上可知, UMD 格式的入口 js 文件,既可以用于引用 npm 包的场景(未压缩的版本,即<库名称>.umd.js),也可以直接用于浏览器端(已压缩的版本,即<库名称>.umd.min.js)。

如何构建不同模块化规范的库文件

目前, webpack 不支持同时生成多份入口 js 文件,因此需要分多次来进行构建。

关键的 webpack 配置是:

  • CommonJS:output.libraryTarget: "commonjs2"
  • UMD:output.libraryTarget: "umd"

对于 UMD ,我们还需要设置全局变量名称,即output.library: "LibraryName"

为了压缩构建出来的文件,最简单的方法是在 CLI 中调用 webpack 命令时带上 mode 参数,如webpack --mode=production;这是因为当 mode 的值为productionUMD

UMD

는 CommonJS와 호환될 뿐만 아니라

AMD

모듈 사양 및 가장 전통적인 전역 변수 패턴과도 호환됩니다.

AMD 사양에 대한 간략한 소개입니다. AMD의 전체 이름은 Asyncchronous Module Definition입니다. 일반적으로 브라우저 측에 적용됩니다(CommonJS 사양과 가장 큰 차이점). AMD 로더는

RequireJS

입니다. 현재 웹팩의 인기로 인해 AMD의 모듈형 솔루션은 시장에서 점차 철수하고 있습니다.

🎜전역 변수 모드🎜는 이해하기 쉽습니다. 이는 라이브러리 입구가 언제 어디서나 액세스할 수 있는 전역 변수(예: window.xxx)에 마운트된다는 의미입니다. 가장 전통적인 js 플러그인 로딩 솔루션입니다. 🎜🎜위에서 볼 수 있듯이 UMD 형식의 항목 js 파일을 사용하여 npm 패키지(압축되지 않은 버전, 즉 <라이브러리 이름>.umd.js)를 참조할 수 있습니다. 또는 브라우저 측에서 직접 사용됩니다(압축 버전, 예: <라이브러리 이름>.umd.min.js). 🎜🎜다른 모듈 사양으로 라이브러리 파일을 빌드하는 방법🎜🎜현재 webpack은 여러 항목 js 파일을 동시에 생성하는 것을 지원하지 않으므로 여러 번 빌드해야 합니다. 🎜🎜핵심 웹팩 구성은 다음과 같습니다: 🎜🎜🎜CommonJS: output.libraryTarget: "commonjs2" 🎜🎜UMD: output.libraryTarget: "umd"🎜🎜🎜UMD의 경우 , 전역 변수 이름, 즉 output.library: "LibraryName"도 설정해야 합니다. 🎜🎜빌드된 파일을 압축하려면 가장 간단한 방법은 webpack --mode=production와 같이 CLI에서 webpack 명령을 호출할 때 🎜mode🎜 매개변수를 가져오는 것입니다. 모드 값이 production인 경우 webpack은 자동으로 🎜UglifyJsPlugin🎜을 활성화하여 소스 코드를 압축합니다. 🎜🎜출력 버전 정보🎜🎜제가 회사에 근무할 때 회사에서는 타사 종속성에 대해 매우 엄격했습니다. 프로젝트에 사용되는 모든 타사 종속성을 사용하려면 먼저 신청하고 승인해야 합니다. 정확해야 합니다. 특정 버전의 경우, 적용되지 않은 소프트웨어 버전은 사용할 수 없습니다. 일부 타사 종속성은 파일 내용이나 파일 이름에 버전 번호를 반영하지 않으므로 이러한 타사 종속성을 식별하는 데 장애가 됩니다. 이는 자체 라이브러리를 개발할 때 취해야 할 경고입니다. . 🎜🎜라이브러리를 구축할 때 webpack을 사용하여 라이브러리 정보를 파일 콘텐츠로 직접 출력할 수 있습니다. 이 "신원 정보"를 통해 사용자는 사용 시 더욱 편안함을 느낄 수 있습니다. 🎜🎜라이브러리 버전 정보를 출력하는 방법은 webpack.BannerPlugin을 사용하는 것입니다. 가장 간단한 방법은 다음과 같습니다. 🎜
const pgk = require('./package.json');
const banner = `
${pkg.name}
${pkg.description}\n
@version v${pkg.version}
@homepage ${pkg.homepage}
@repository ${pkg.repository.url}\n
(c) 2019 Array-Huang
Released under the MIT License.
hash: [hash]
`;

/* webpack 配置 */
{
    // ...其它配置
    plugins: [
        // ...其它 plugin 配置
        new webpack.BannerPlugin(banner);
    ]
}
🎜최종 생성 효과는 다음과 같습니다. 🎜
/*!
 * 
 * vue-directive-window
 * Vue.js directive that enhance your Modal Window, support drag, resize and maximize.
 * 
 * @version v0.7.5
 * @homepage https://github.com/Array-Huang/vue-directive-window
 * @repository git+https://github.com/Array-Huang/vue-directive-window.git
 * 
 * (c) 2019 Array-Huang
 * Released under the MIT License.
 * hash: dc6c11a1e50821f4444a
 * 
 */

source map

如果库的用户是直接通过在浏览器里加载你的库来使用的话,那么提供一份 source map 文件是非常有必要的;这是因为你的库在经过 webpack 构建,甚至压缩后,与源代码已经大相径庭了,用户将难以在浏览器中进行调试;但如果你能为自己的库附上一份 source map ,浏览器开发者工具会调用 source map 来帮助解析,用户的调试体验会更接近于调试库的源码。

相应的 webpack 配置为:

// webpack 配置
{
    // ...其它配置
    devtool: 'cheap-module-source-map'
}

webpack 支持多种类型的 source map ,不同类型的 source map 在生成速度、支持功能(如 babel )、调试位置偏移等问题上均有不同表现,我这边只做推荐:

  • 开发环境:cheap-module-eval-source-map
  • 生产环境:cheap-module-source-map

关于其它类型的 source map ,请查看 webpack 官方文档的 devtool 章节。

排除第三方依赖

与一般应用不一样,在开发库的时候,我们应尽量避免引入第三方库(构建过程中使用的工具链除外),因为这些第三方库会让我们写的库的大小猛增;很可能会出现这样的情况:我们自己写的小功能只有几百行代码的逻辑,构建出来的库却有几百k,那这样的库意义就不大了。

但我们的确也很难避免使用第三方库,那该咋办呢?

// webpack 配置
{
    // ...其它配置
    externals: {
        lodash: {
            commonjs: 'lodash',
            commonjs2: 'lodash',
            amd: 'lodash',
            root: '_'
        }
    }
}

使用上述配置后,我们构建出来的库中就不会包含配置中指定的第三方库(例子中为lodash)了,下面来一一详解:

  • commonjscommonjs2项都是指明用户在 node.js 环境下使用当前库时,以 CommonJS 的方式来加载名为lodash的 npm 包。
  • amd项表示在浏览器中加载运行本库时,本库会试图以 AMD 的方式来加载名为lodash的 AMD 模块。
  • root项表示在浏览器中加载运行本库时,本库会试图取全局变量window._(通过<script>标签加载lodash.js时, lodash 会把自己注入到全局变量window._中)。

与一般应用不一样的 externals 配置

在一般应用中,你或许会看到这样的 externals 配置:

// webpack 配置
{
    // ...其它配置
    externals: {
        lodash: '_'
    }
}

这样的 externals 配置方式意味着:无论在什么环境,都要取_这个全局变量;如果当前是在一般应用且确定已经使用<script>来加载指定的第三方库(比如 jQueryVue 等核心库,的确很常以这种方式来加载),当然大可直接这样用;但我们作为库的作者,应提供更宽松更灵活的使用方式。

完整的 webpack 配置示例

由于构建不同模块化规范的库需要不同的 webpack 配置(其实也只是稍有不同)来进行多次构建,因此本文只针对构建 UMD 格式且已压缩这一场景来展示最简单的 webpack 配置示例;如果想知道如何更有效率地拼接 webpack 配置,请看 micro-schema-validator 项目的 webpack 配置文件。

// webpack.config.js
const webpack = require('webpack');
const pkg = require('./package.json'); // 把 package.json 作为信息源
const banner = `
${pkg.name}
${pkg.description}\n
@version v${pkg.version}
@homepage ${pkg.homepage}
@repository ${pkg.repository.url}\n
(c) 2019 Array-Huang
Released under the MIT License.
hash: [hash]
`;

module.exports = {
  entry: `${__dirname}/index.js`,
  devtool: 'cheap-module-source-map',
  output: {
    path: `${__dirname}/dist`, // 定义输出的目录
    filename: 'micro-schema-validator.min.js', // 定义输出文件名
    library: 'MicroSchemaValidator', // 定义暴露到浏览器环境的全局变量名称
    libraryTarget: 'umd', // 指定遵循的模块化规范
  },
  /* 排除第三方依赖 */
  externals: {
    lodash: {
      commonjs: 'lodash',
      commonjs2: 'lodash',
      amd: 'lodash',
      root: '_'
    }
  },
  module: {
    rules: [
      {
        test: /(\.jsx|\.js)$/,
        loader: 'babel-loader',
        exclude: /(node_modules|bower_components)/
      },
      {
        test: /(\.jsx|\.js)$/,
        loader: 'eslint-loader',
        exclude: /(node_modules|bower_components)/
      }
    ]
  },
  plugins: [
    new webpack.BannerPlugin(banner) // 输出项目信息
  ]
};

利用 vue-cli 定制并管理 webpack 配置

对于 Vue 生态的库,如 Vue 组件、Vue 自定义指令等,可以使用 vue-cli (本文特指 vue-cli 3.0 后的版本)根据你的需求来定制 webpack 配置,可定制内容包括:

  • 是否启用 Babel
  • 是否接入 TypeScript 语法
  • 是否支持 PWA
  • 是否使用 Vue-Router 和 Vuex
  • 是否使用 CSS 预处理器,并可选择具体的 CSS 预处理器,包括 Sass / Less / Stylus
  • 是否使用 ESLint 和 Prettier
  • 是否接入单元测试和端对端测试(E2E)

定制完成后, vue-cli 将生成一个种子项目,该项目可执行(包括本地开发和构建生产环境的包)但没有实际内容(实际内容不还得由你来写嘛哈哈)。与一般的脚手架工具相比, vue-cli 除了可以生成 webpack 配置外,还将持续对其进行管理和维护,如:

  • 提供一个统一的自定义配置的入口;过往,我们为了达到自定义配置的目的,往往会直接在脚手架工具生成出来的 webpack 配置上直接进行修改,这样会导致修改点非常分散,难以让自定义的 webpack 配置在其它项目复用;而使用 vue-cli 后,所有对 webpack 配置的修改点都被集中管理起来了,需要复用的话,直接把这自定义配置文件(vue.config.js)迁移到别的项目即可。
  • 提供持续更新 webpack 配置的机制;假如现在有一个开源库,我为了达到自己的目的,肆意在库源码上修改,那么当我需要升级该开源库的时候可就犯难了,因为这会把我之前做的修改都覆盖掉;同理可得,vue-cli 由于统一了自定义配置的入口,并且是在每次运行项目(运行项目也是通过执行 vue-cli 的命令而非 webpack)时动态渲染 webpack 配置的,因此项目的 webpack 配置可以随着 vue-cli 的升级而不断升级了。
  • 提供持续更新 webpack 工具链的机制;众所周知, webpack 工具链中包含了大量的第三方开源库,如 Babel 、ESLint 等,这些开源库也都是在不断更新当中,在这个过程中,必然会不断产生 Breaking Change ,所幸 vue-cli 通过自身升级——不断修改 webpack 配置来达到适配最新版第三方开源库的目的,而我们的项目也可以以极小的代价(升级 vue-cli 本身)来获取 webpack 工具链的不断更新。

vue-cli 自定义配置示例

摘自 vue-directive-window 项目的 vue.config.js 文件:

const webpack = require('webpack');
const pkg = require('./package.json');

const banner = `
${pkg.name}
${pkg.description}\n
@version v${pkg.version}
@homepage ${pkg.homepage}
@repository ${pkg.repository.url}\n
(c) 2019 Array-Huang
Released under the MIT License.
hash: [hash]
`;

module.exports = {
  chainWebpack: config => {
    config.output.libraryExport('default');
    config.plugin('banner').use(webpack.BannerPlugin, [
      {
        banner,
        entryOnly: true,
      },
    ]);
  },
};

看起来是不是比上文中最基础的 webpack 配置还要简洁呢?当项目的架构逐渐丰富起来后,这个差距将不断拉大。

实例项目代码介绍

在我的工作生涯中,我写的绝大部分库都是为公司的项目写的,很可惜无法带出来,但我会以我最近写的两个开源库:javascript-library-boilerplate 和  vue-directive-window 来作为实例项目代码来辅助介绍。

javascript-library-boilerplate

javascript-library-boilerplate 是一个现代前端生态下快速构建 javascript 库的脚手架(或称种子项目,或称示例代码,看你理解了),本库支持 GitHub 的 repository templates 功能,你可以直接在项目首页点击 Use this template 来直接套用本脚手架的代码来创建你自己的 javascript 库。

vue-directive-window

vue-directive-window 是一个可以快速让模态框(modal)支持类窗口操作的增强库;类窗口操作主要包括三大类:拖拽移动、拖拽调整窗口尺寸、窗口最大化; vue-directive-window 支持以 Vue 自定义指令或是一般 js 类的方式来调用。

vue-directive-window 相对于 javascript-library-boilerplate 来说,更贴近 Vue 生态圈,如果你最近想为 Vue 生态圈添砖加瓦,不妨参考一下本项目。

实例项目代码介绍

我会以我最近写的两个开源库:javascript-library-boilerplate 和  vue-directive-window 来作为实例项目代码来辅助介绍。

javascript-library-boilerplate

javascript-library-boilerplate 是一个现代前端生态下快速构建 javascript 库的脚手架(或称种子项目,或称示例代码,看你理解了),本库支持 GitHub 的 repository templates 功能,你可以直接在项目首页点击 Use this template 来直接套用本脚手架的代码来创建你自己的 javascript 库。

vue-directive-window

vue-directive-window 是一个可以快速让模态框(modal)支持类窗口操作的增强库;类窗口操作主要包括三大类:拖拽移动、拖拽调整窗口尺寸、窗口最大化; vue-directive-window 支持以 Vue 自定义指令或是一般 js 类的方式来调用。

vue-directive-window 相对于 javascript-library-boilerplate 来说,更贴近 Vue 生态圈,如果你最近想为 Vue 生态圈添砖加瓦,不妨参考一下本项目。

推荐教程:《JS教程

위 내용은 webpack을 사용하여 js 라이브러리 구축의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 jianshu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제