1.0.0 • Published 6 months ago

@render-ae86/ae86-webpack-builder v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
6 months ago

ae86-webpack-builder

基于webpack-chain和webpack的通用型脚手架,旨于实现webpack配置高度复用

特性

  • 完善灵活的插件(plugin)和预设(preset)能力,实现webpack配置复用。
  • 提供builder运行过程中的多个生命周期函数,实现能力定制。
  • 没有使用场景限制,只要是使用webpack进行编译构建,都可以使用ae86-webpack-builder。
  • 在日常开发中可以不断提炼单一功能的plugin和preset,助力于开发提效,非常适合多人团队使用。
  • 通过使用ae86-webpack-builder中提供的createBuilder模块,可以通过编程方式处理webpack配置,可根据业务场景自主扩展能力,例如结合ae86-webpack-builder开发自己的脚手架

能力介绍

ae86-webpack-builder只是按照一定规范下编写的plugin和preset的脚手架,本身不耦合任何webpack配置,开发者无需担心使用ae86-webpack-builder过程中带来的副作用。

其内部的核心实现正如上面特性中说到的createBuilder模块,ae86-webpack-builder只是在createBuilder封住了一些工具,开发者如果只使用ae86-webpack-builder来构建项目,则无须了解createBuilder到底作了什么,没有概念负担。

ae86-webpack-builder通过解析和运行配置文件中的plugin和preset,得到最终的webpack配置,实现项目的开发和构建。它很简单,极易上手。

Plugin

plugin是ae86-webpack-builder中的最小配置单元,其数据类型是一个类(class),负责webpack的配置编写。

下面是一个简单plugin的示例代码:

import { Complier, Json, Config, PluginClass } from 'ae86-webpack-builder';

export default class TestPlugin extends PluginClass {
    run(complier: Complier, config: Config, options: Json) {
        const {
            context,
            log,
            hooks,
            getAllWebpackConfigs,
            setBuilderValue,
            getBuilderValue
        } = complier;
        const { command, pkg, commandArgs, rootDir } = context;

        // TODO: 编辑你的webpack配置 
        return config
    }
}

为了享受ae86-webpack-builder带来的额外能力,我们规定plugin必须继承ae86-webpack-builder提供的PluginClass类,必须重新实现来自于PluginClass中的run函数,且最后要返回config对象。

run函数中的参数

run函数是插件的核心,其必须被实现,ae86-webpack-builder内部就是通过执行run函数获得plugin的配置,其接受三个参数,分别是compiler、config、option。

complier

ae86-webpack-builder提供的编译对象,使用它可以调用ae86-webpack-builder提供的内部能力。 目前compiler提供的能力如下: 1. context:包含当前编译的上下文信息。 - rootDir:ae86-webpack-builder运行的工作路径 - command:当前运行的命令名称 (start|build|test) - commandArgs:运行命令时候添加的参数 - buildConfig:ae86-webpack-builder配置文件中的内容 - pkg:当前项目的package.json中的内容 2. hooks:ae86-webpack-builder提供的生命周期函数钩子,开发者可以使用相关的生命周期,实现额外的逻辑,详细请参考生命周期。 3. log:ae86-webpack-builder提供的日志工具,使用方法参考npmlog 4. getAllWebpackConfigs:该函数可以获取当前所有plugin和preset中的配置 5. setBuilderValue:用于插件之前通信,该函数可以设置相关的值,提供给其他插件使用,详细介绍请参考插件通信 6. getBuilderValue:用于插件之前通信,该函数可以获取其他插件设置的值,详细介绍请参考插件通信

config

config是一个有ae86-webpack-builder提供的webpack-chain对象,run函数中通过操作config对象,来完成webpack的编译配置。

option

option是插件本身自己的配置,开发者可以在配置文件中给plugin进行配置,内部可以使用option来决定plugin的能力。

plugin中的getConfig函数

当plugin继承PluginClass后,会获得一个额外的静态方法:getConfig,该函数可以使得plugin中运行其他插件并获取对应插件最后的配置。详细介绍请参考plugin中使用其他插件

preset

preset是一些列插件的集合,其最终得到的配置是所有的插件共同运行的结果。

下面是一个简单preset的示例代码:

import Plugin1 from 'Plugin1';
import Plugin2 from 'Plugin2';
import Plugin3 from 'Plugin3';

export default {
        install() {
                return [
                        Plugin1,
                        Plugin2,
                        Plugin3
                ]
        }
}

preset结构就是导出一个对象,然后在install方法中返回plugin数组,同样的,preset也支持option配置,在ae86-webpack-builder中,插件的preset的option会下发到各个plugin中去。

配置文件

ae86-webpack-builder支持多种文件类型的配置文件:build.config.(js|ts|mjs|mts|cjs|cts|.json)。

配置文件的作用是配置各种plugin和preset,下面是一个简单的配置示例(build.config.ts):

export default {
    plugins: [
        'Plugin1',
        [
            'Plugin2',
            {
                // 这里是Plugin2的配置option
            }
        ]
    ],
    presets: [
        'Preset1',
        [
            'Preset2',
            {
                // 这里是Preset2的配置option
            }
        ]
    ]
}

配置文件中提供plugins和presets来配置相应的plugin和preset,如果plugin或者preset有配置option,那么配置格式为一个数组,数组第一项为plugin/preset的名称,数组第二项则plugin/preset配置option。

注意配置文件的位置在项目的根目录下。

生命周期

ae86-webpack-builder在运行过程中,提供非常多的生命周期函数钩子,ae86-webpack-builder运行过程中一些数据会通过生命周期函数进行透出,开发者可以利用这些数据进行开发。

生命周期函数的执行环境实在run函数中,下面是所有生命周期函数的名称、意义、参数的介绍。

  1. beforload:ae86-webpack-builder开始加载加载配置(start/build 命令通用)
  2. failed:ae86-webpack-builder执行失败(start/build 命令通用)
  3. beforRun:ae86-webpack-builder开始执行(start/build 命令通用,在这里可以对webpack配置进行最后的修改)
  4. afterStartDevServer:webpackDevServer启动完成(start命令仅有)
  5. afterBuildCompile:ae86-webpack-builder执行完成(build命令仅有)
export default class TestPlugin extends PluginClass {
    run(complier: Complier, config: Config, options: Json) {

     const {hooks} = complier; 
     
     hooks.beforload.tap("beforload",({
        args, // 命令参数
        config // webpack配置
     })=>{
        
     });

     hooks.beforRun.tap("beforRun",({
        args, // 命令参数
        config // webpack配置
     })=>{
        
     });

     hooks.failed.tap("failed",({
        err // 错误对象
     })=>{

     });

     hooks.afterBuildCompile.tap("afterBuildCompile",(
        ...result // webpack中compiler.run方法,执行完成的结果(webpackStats)
     )=>{

     })

     hooks.afterStartDevServer.tap("afterStartDevServer",({
        url, // 项目构建成功后服务器地址
        urls, // 项目构建成功后服务器地址集合
        devServer,// webpackDevServer实例
        err,// webpackDevServer运行错误
     })=>{

     })


     return config;
    }
}

插件通信

特殊场景下,plugin需要协作完成一次复杂的构建配置,这个时候就需要插件之前能够相互通信。ae86-webpack-builder中提供setBuilderValue函数和getBuilderValue函数,来实现plugin之前的通信。

下面是插件通信的简单代码示例:

// 设置值
export default class TestPlugin1 extends PluginClass {
    run(complier: Complier, config: Config, options: Json) {

     const {setBuilderValue} = complier; 
     
     setBuilderValue('TestPlugin1','TestPlugin1设置的值')

     return config;
    }
}

// 获取值
export default class TestPlugin2 extends PluginClass {
    run(complier: Complier, config: Config, options: Json) {

        const { getBuilderValue } = complier;

        const value = getBuilderValue('TestPlugin1')

        return config;
    }
}

plugin中使用其他插件

ae86-webpack-builder中的plugin可以直接使用plugin的getConfig方法,实现现有插件的配置复用。(前提:plugin要继承自ae86-webpack-builder中提供的PluginClass类)。

下面是插件使用其他插件简单代码示例:

export default class TestPlugin1 extends PluginClass {
    run(complier: Complier, config: Config, options: Json) {
        
        TestPlugin2.getConfig(complier,config,{
            ...options2 // options2为TestPlugin2所需的选项配置
        });

        return config;
    }
}

使用方式非常简单,只需要把当前插件的compiler,config和其他插件的配置选项传入,即可获取其他插件的配置。其实ae86-webpack-builder中的preset也是基于此方式来实现多个插件的整合的。

ae86-webpack-builder的整体设计

ae86-webpack-builder的整体设计

如何使用

下面介绍下如何编写Plugin和如何使用ae86-webpack-builder构建项目。

编写插件

  1. 项目安装ae86-webpack-builder:npm i @render-ae86/ae86-webpack-builder -S
  2. 配置package.json中的入口文件地址
  3. 书写自己的插件代码
import { Complier, Json, Config, PluginClass } from '@render-ae86/ae86-webpack-builder';

export default class TestPlugin extends PluginClass {
    run(complier: Complier, config: Config, options: Json) {
        const {
            context,
            log,
            hooks,
            getAllWebpackConfigs,
            setBuilderValue,
            getBuilderValue
        } = complier;
        const { command, pkg, commandArgs, rootDir } = context;

        // TODO: 编辑你的webpack配置 
        return config
    }
}

ae86-webpack-builder中的plugin编写十分灵活,插件中如何设置webpack配置全部有开发者自己决定。

ae86-webpack-builder中提供了非常多的类型定义,开发者可以查看ae86-webpack-builder的类型文件并使用相关类型。

使用插件

  1. 项目安装ae86-webpack-builder:npm i @render-ae86/ae86-webpack-builder -S
  2. 项目安装plugins: npm i your_plugin_name -S
  3. 对package.json中的script配置
  4. 项目根目录下编写配置文件

script中最简单的配置为:

{
    // package.json中其他配置
    "scripts": {
        "start": "ae86-webpack-builder start",
        "build": "ae86-webpack-builder build",
    },
    // package.json中其他配置
}

使用ae86-webpack-builder构建后的库,你可以上传到npm上,供以后安装使用,这跟开发npm包没有什么区别

plugin具体的编写可以参考以下链接: 1. render-build-react-component-plugin的仓库地址 2. render-build-react-component-plugin的npm地址

render-build-react-component-plugin是基于ae86-webpack-builder编写的一个简单的构建react组件的plugin。

如何具体使用插件和ae86-webpack-builder构建项目,可以参考如下链接: 1. render-component-template的仓库地址 2. render-component-template的npm地址

render-component-template是一个使用render-build-react-component-plugin插件的简单的计数器react组件。

未来展望

  • 丰富preset的能力,开发者可以通过配置决定preset生成一份配置还是多份配置。
  • 暴露更多的API,开发者运可以通过用这些API,实现更加丰富的定制,满足各种场景。
  • 接入更多的构建工具,例如vite、rollup,不只是webpack。
  • 当使用第三方plugin和preset的时候,会遇到plugin和preset大部分配置满足当前场景,但是需要一些额外的修改,如果重新开发将会耗时耗力,基于此后面会提供配置函数能力,使得开发者可以在特定时期根据业务场景修改第三方plugin和preset中得到的配置,减少重复开发。