关于webpack:回顾webpack在vueconfigjs中写loader和plugin

50次阅读

共计 17486 个字符,预计需要花费 44 分钟才能阅读完成。

前言

咱们先思考一个问题:如果不应用 webpack,前端可能开发我的项目吗?

先别着急说出答案,咱们持续往下看 …

工作中,咱们都是应用框架的脚手架进行开发,支流的趋势 …

vue-cli & create-react-app 和 webpack 的关系

咱们晓得,无论是 Vue 的 vue-cli 还是 React 的 create-react-app 这样的脚手架,实际上都是给 webpack 做了一层封装,包了一层壳子,并预设了一些默认罕用的配置项(当然还有别的货色),以便晋升开发效率。

所以它们的关系是:脚手架只是给 webpack 穿上了一个马甲 …

不过有时候脚手架提供的默认配置项不够用了,就须要咱们手动去写一些 plugin 或者 loader 从而实现咱们想要的性能。

学习本文的播种

  • 通俗易懂地回顾 webpack 知识点
  • 学习在 vue-cli 脚手架中写 webpack 的 plugin 的知识点
  • 学习在 vue-cli 脚手架中写 webpack 的 loader 的知识点

webpack

平时咱们写代码都是 模块化、组件化(工程化)进行开发,导致代码会进行拆分、细化、公共局部提取、援用等 …

为何要 模块化、组件化(工程化)进行开发呢?因为:这是软件开发的支流和趋势 …

什么是 webpack & 谈谈你对 webpack 的了解

  • 平时咱们写代码都是 模块化、组件化(工程化)进行开发,导致代码会进行拆分、细化、公共局部提取、援用等 …
  • 比方:咱们会写很多.vue 文件(当然还有别的文件如.less 等)。然而咱们写的代码是最终要被浏览器拜访解析执行的,而浏览器不意识.vue 文件,也不意识.less 文件!
  • 浏览器不意识就不能解析,不能用。
  • 浏览器倒是意识 js、css、html,能够解析出相应内容,并渲染展现。
  • 又因为 .vue 文件和.less 文件实际上也只是 html、css、js化妆之后 的款式。
  • 那这样,搞一个工具,可能让.vue 文件和.less 文件 卸妆 成 html、css、js 就行了。
  • 而 webpack 恰好可能做到这一点(编译转化打包)

所以,webpack 就是:一个转化编译打包工具,将一些浏览器不意识的花里胡哨的文件转化为浏览器意识的 html、css、js 文件。

还记得咱们最终打包好的 dist 文件夹目录吗?外面就只有:html、css、js 等 一些资源 …

这样形容,不是非常谨严。精确来说,webpack 是一个动态模块资源打包工具,官网:https://webpack.docschina.org/concepts/

回到最开始的那个问题~

如果不应用 webpack,前端可能开发我的项目吗?

  • 问:如果不应用 webpack,前端可能开发我的项目吗?
  • 答:如果一个我的项目炒鸡小,只是用来展现一点点货色,齐全能够应用原生的 html、css、js 去写,这样的话,就用不到

咱们要晓得 webpack 的作用就是,去转化编译打包脚手架、工程化的大我的项目。如果是一个小我的项目,齐全不须要去用工程化的形式开发,间接写,写完了丢到服务器上,间接用

前端工程化 == 模块化 + 组件化 + 自动化 + …

webpack 的几个重要概念

  • 打包入口(entry)
  • 打包输入(output)
  • 加载器(loader)
  • 插件(plugin)
  • 模式(mode)
  • nodejs 环境(environment)

webpack 打包入口 -entry

  • 咱们晓得,咱们开发我的项目有很多文件,比方 a、b、c 等。a 援用了 b 中的货色,而 b 又援用了 c 中的货色。那么打包翻译的话,就须要指定从哪个文件开始打包,打包的过程中如果遇到了有别的援用,就顺藤摸瓜 …
  • webpack 中默认打包的入口文件是 ./src/index.js 文件,这个文件中援用了好多别的文件,所以 webpack 持续顺藤摸瓜寻找、编译、转化、打包。
  • 而 vue-cli 脚手架中的入口文件是 src 目录下的 main.js 文件(vue-cli 改写了 webpack 默认的入口文件地位罢了)
  • 这里咱们能够去 vue-cli 仓库代码中去找到相干的代码,能看到指定的打包入口

vue-cli 仓库地址:https://github.com/vuejs/vue-cli

大家把代码下载下来,Code –> Download ZIP,而后在 vscode 中关上代码,在左上角第二个放大镜中搜寻关键字:src/main.js

有很多的关键词,其中有一个 get entryFile 办法,代码如下:

/**
* Get the entry file taking into account typescript.
*
* @readonly
*/
get entryFile () {if (this._entryFile) return this._entryFile
    return (this._entryFile = fs.existsSync(this.resolve('src/main.ts')) ? 'src/main.ts' : 'src/main.js')
}

对应截图如下:

其实 vue-cli 中有很多的中央的代码,都告知了咱们 vue-cli 是将 main.js 作为 webpack 打包的入口的,大家多看看 …

好了,至此咱们见证了 webpack 的打包入口 (entry) 在 vue-cli 脚手架中的具体利用展示模式。大家也能够在 create-react-app 中去看一下 webpack 的打包入口文件,一个意思

vue-cliwebpack 的关系,换句话说,也像 苹果手机 富士康 的关系 …

webpack 打包输入 -output

咱们晓得,平时我的项目写完,公布上线,打包输入的个别都是一个 dist 文件夹(也能够改)

原始的 webpack 是这样写:

const path = require('path');

module.exports = {
  entry: './src/index.js', // 从以后同级目录下的 index.js 作为入口文件,顺藤摸瓜开始打包
  output: {path: path.resolve(__dirname, 'dist'), // 这里的 path 值要是一个绝对路径,如:E:\echarts\code\dist,所以要应用 path 模块来操作
    filename: 'myDemo.js',
  },
};

vue-cli 中叫做 outputDir 并指定了默认值为 dist(实际上就是 webpack 中的 output,又是套壳子),咱们通过在 vue.config.js 文件中更改 outputDir 的值,即可批改打包换名字了

vue-cli 中的代码如下:

exports.defaults = () => ({
  // project deployment base
  publicPath: '/',

  // where to output built files
  outputDir: 'dist', // 即为 webpack 中的 output

  // where to put static assets (js/css/img/font/...)
  assetsDir: '',

  // filename for index.html (relative to outputDir)
  indexPath: 'index.html',

  // ......

  devServer: {
    /*
    open: process.platform === 'darwin',
    host: '0.0.0.0',
    port: 8080,
    https: false,
    hotOnly: false,
    proxy: null, // string | Object
    before: app => {}
  */
  }
})

留神看,上述的参数,就是 vue.config.js 须要咱们设定的一些参数

vue-cli 中的 webpack 工作流程

  1. 咱们在 vue.config.js 中写的合乎 vue-cli 语法的代码,会被传递到 vue-cli 代码中
  2. vue-cli 接管到当前,会再转化一下,转化成为合乎 webpack 语法的配置
  3. 并通过 webpack-merge 这个插件,传递给 webpack 中。
  4. webpack 拿到对应配置项当前,再执行相应的打包策略形式

create-react-app 这个脚手架也是相似,大抵都是套壳子,定规定,拿参数(解决),丢给 webpack 去打包

模式(mode)

  • 开发模式(development)
  • 生产模式(production)

nodejs 环境(environment)

咱们晓得 webpack 是用 js 语言写的,在 nodejs 创立的环境中运行,咱们能够通过我的项目中的 node_modules/webpack/bin/webpack.js 文件看到 如下图,看一下:

child_process 为 node 的子过程

高深莫测 …


webpack 工作流程

在 nodejs 环境下,从入口递归寻找各个模块(组件)依赖关系,去打包,遇到不能间接辨认的比方.vue 文件、.less 文件,就应用对应的 loader 去解析它。另外如果还能够在 webpack 的生命周期钩子的某一个工夫节点,去操作打包的内容,从而管制打包的后果。

vue.config 配置 webpack 插件的办法,对象写法或函数写法

实际上,学习 webpack 学的就是,别的开发者或者公司去开发的 loader 或者 plugin,学的是 webpack 的生态。

webpack 加载器 -loader

什么是 loader

loader 顾名思义,就是加载的意思,加载什么呢?加载 webpack 不能间接意识的文件,加载好当前,以供 webpack 去打包。

webpack 间接意识的只有 js 和 json 文件内容

有哪些常见的 loader

  • vue-loader 去加载.vue 文件
  • react-loader 用于加载 react 组件的
  • style-loader 将 css 款式挂到 style 标签下
  • css-loader 编译 css 款式文件
  • less-loader 去加载.less 款式文件
  • postcss-loader 给款式加上浏览器前缀
  • file-loader 和 url-loader 能够压缩图片资源(后者可压成 base64)
  • babel-loader、ts-loader、eslint-loader 等

loader 执行程序

从下到上,从右到左。

简略的 loader 之去除 console.log

第一步,src 目录下新建文件夹 myLoader,内创立 js 文件 removeConsole.js 文件

一个 loader 就是一个模块化的 js 文件

第二步,裸露一个函数,loader 实质上是一个函数,在函数体外部,能够去对代码(字符串)进行加工

plugin 也是相似,也能够对代码字符串进行加工,不过性能更加弱小

第三步,写 loader 函数逻辑内容

const reg = /(console.log\()(.*)(\))/g;
module.exports = function (source) {console.log('source', source);
    source = source.replace(reg, "")
    return source;
}

loader 就是一个加工函数,回想起 js 中的经典的一句话,万物皆可函数

第四步,在 vue.config.js 中的 configureWebpack 中增加应用本人写的 loader

/**
* 增加本人写的模块 loader
* */
module: {
    rules: [
      /**
       * 对.vue 和.js 文件失效,不蕴含 node_modules 大文件夹,加载器的地位在
       * 当前目录下的./src/myLoader/removeConsole.js
       * */
      // {
      //   test: /\.vue$/,
      //   exclude: /node_modules/,
      //   loader: path.resolve(__dirname, "./src/myLoader/removeConsole.js")
      // },
      // {
      //   test: /\.js$/,
      //   exclude: /node_modules/,
      //   loader: path.resolve(__dirname, "./src/myLoader/removeConsole.js")
      // }
    ],
}

如果想要给 loader 传参,接参,能够在 loader 函数外部应用 this.query 接管,或者 npm i -D loader-utils 工具包去进一步操作。

残缺代码示例,见 GitHub 仓库:https://github.com/shuirongshuifu/elementSrcCodeStudy

更多开发 loader 细节,见官网文档:

webpack 插件 -plugin

什么是 plugin

  • loader 解决不了的,去应用 plugin 去解决
  • webpack 在打包资源代码文件时,也会有先后执行步骤,换句话说即为 webpack 的生命周期
  • 所以咱们能够在对应生命周期的钩子函数中,去编写一些代码从而影响最终的打包后果
  • 这些编写的代码,即为 webpack 的插件(代码)

webpack 的打包也会有很多生命周期,plugin 就是在适合的机会,通过 webpack 提供的 api,去扭转输入后果。留神,loader 是一个转换器,运行在打包之前,而 plugin 在整个编译周期都起作用。

plugin 构造

  • plugin 是一个 class 类(构造函数)
  • 类中的 constructor 函数用来接参
  • apply 函数的 compiler 对象自带很多的 api 能够供咱们调用
  • 通过这些 api 的应用最终影响打包后果

如下代码:

class myPlugin {constructor(options) {console.log("接参 -->", options);
    }
    apply(compiler) {console.log('下面有十分多 api,可参见 compiler 打印后果', compiler)
    }
}

module.exports = myPlugin

打印的 compiler 对象

通过下方的打印后果,咱们确实能够看到 compiler.hooks.xxx 有很多暴露出的 api

实际上去编写 webpack 中的 plugin 就是,去正当应用 Compiler 的相干 hooks

Compiler {
  _pluginCompat: SyncBailHook {_args: [ 'options'],
    taps: [[Object], [Object], [Object] ],  
    interceptors: [],
    call: [Function: lazyCompileHook],       
    promise: [Function: lazyCompileHook],    
    callAsync: [Function: lazyCompileHook],  
    _x: undefined
  },
  // 钩子函数,即为生命周期
  hooks: {
    shouldEmit: SyncBailHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],     
      promise: [Function: lazyCompileHook],  
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    done: AsyncSeriesHook {_args: [Array],
      taps: [Array],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],  
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    additionalPass: AsyncSeriesHook {_args: [],
      taps: [Array],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    beforeRun: AsyncSeriesHook {_args: [Array],
      taps: [Array],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    run: AsyncSeriesHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    emit: AsyncSeriesHook {_args: [Array],
      taps: [Array],
      interceptors: [Array],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    assetEmitted: AsyncSeriesHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    afterEmit: AsyncSeriesHook {_args: [Array],
      taps: [Array],
      interceptors: [Array],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    thisCompilation: SyncHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    compilation: SyncHook {_args: [Array],
      taps: [Array],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    normalModuleFactory: SyncHook {_args: [Array],
      taps: [Array],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    contextModuleFactory: SyncHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    beforeCompile: AsyncSeriesHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    compile: SyncHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    make: AsyncParallelHook {_args: [Array],
      taps: [Array],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    afterCompile: AsyncSeriesHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    watchRun: AsyncSeriesHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: undefined,
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    failed: SyncHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    invalid: SyncHook {_args: [Array],
      taps: [Array],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    watchClose: SyncHook {_args: [],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    infrastructureLog: SyncBailHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    environment: SyncHook {_args: [],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    afterEnvironment: SyncHook {_args: [],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    afterPlugins: SyncHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    afterResolvers: SyncHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    entryOption: SyncBailHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    infrastructurelog: SyncBailHook {_args: [Array],
      taps: [],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    }
  },
  name: undefined,
  parentCompilation: undefined,
  outputPath: '',
  outputFileSystem: NodeOutputFileSystem {mkdirp: [Function: mkdirP] {mkdirP: [Circular],
      mkdirp: [Circular],
      sync: [Function: sync]
    },
    mkdir: [Function: bound mkdir],
    rmdir: [Function: bound rmdir],
    unlink: [Function: bound unlink],
    writeFile: [Function: bound writeFile],
    join: [Function: bound join]
  },
  inputFileSystem: CachedInputFileSystem {fileSystem: NodeJsInputFileSystem {},
    _statStorage: Storage {
      duration: 60000,
      running: Map {},
      data: Map {},
      levels: [Array],
      count: 0,
      interval: null,
      needTickCheck: false,
      nextTick: null,
      passive: true,
      tick: [Function: bound tick]
    },
    _readdirStorage: Storage {
      duration: 60000,
      running: Map {},
      data: Map {},
      levels: [Array],
      count: 0,
      interval: null,
      needTickCheck: false,
      nextTick: null,
      passive: true,
      tick: [Function: bound tick]
    },
    _readFileStorage: Storage {
      duration: 60000,
      running: Map {},
      data: Map {},
      levels: [Array],
      count: 0,
      interval: null,
      needTickCheck: false,
      nextTick: null,
      passive: true,
      tick: [Function: bound tick]
    },
    _readJsonStorage: Storage {
      duration: 60000,
      running: Map {},
      data: Map {},
      levels: [Array],
      count: 0,
      interval: null,
      needTickCheck: false,
      nextTick: null,
      passive: true,
      tick: [Function: bound tick]
    },
    _readlinkStorage: Storage {
      duration: 60000,
      running: Map {},
      data: Map {},
      levels: [Array],
      count: 0,
      interval: null,
      needTickCheck: false,
      nextTick: null,
      passive: true,
      tick: [Function: bound tick]
    },
    _stat: [Function: bound bound],
    _statSync: [Function: bound bound],
    _readdir: [Function: bound readdir],
    _readdirSync: [Function: bound readdirSync],
    _readFile: [Function: bound bound readFile],
    _readFileSync: [Function: bound bound readFileSync],
    _readJson: [Function],
    _readJsonSync: [Function],
    _readlink: [Function: bound bound readlink],
    _readlinkSync: [Function: bound bound readlinkSync]
  },
  recordsInputPath: null,
  recordsOutputPath: null,
  records: {},
  removedFiles: Set {},
  fileTimestamps: Map {},
  contextTimestamps: Map {},
  resolverFactory: ResolverFactory {
    _pluginCompat: SyncBailHook {_args: [Array],
      taps: [Array],
      interceptors: [],
      call: [Function: lazyCompileHook],
      promise: [Function: lazyCompileHook],
      callAsync: [Function: lazyCompileHook],
      _x: undefined
    },
    hooks: {resolveOptions: [HookMap], resolver: [HookMap] },
    cache2: Map {}},
  infrastructureLogger: [Function: logger],
  resolvers: {normal: { plugins: [Function: deprecated], apply: [Function: deprecated] },
    loader: {plugins: [Function: deprecated], apply: [Function: deprecated] },
    context: {plugins: [Function: deprecated], apply: [Function: deprecated] }
  },
  options: {
    mode: 'development',
    context: 'E:\\echarts\\code',
    devtool: 'eval-cheap-module-source-map',
    node: {
      setImmediate: false,
      process: 'mock',
      dgram: 'empty',
      fs: 'empty',
      net: 'empty',
      tls: 'empty',
      child_process: 'empty',
      console: false,
      global: true,
      Buffer: true,
      __filename: 'mock',
      __dirname: 'mock'
    },
    output: {
      path: 'E:\\echarts\\code\\dist',
      filename: 'js/[name].js',
      publicPath: '/',
      chunkFilename: 'js/[name].js',
      globalObject: "(typeof self !=='undefined'? self : this)",
      webassemblyModuleFilename: '[modulehash].module.wasm',
      library: '',
      hotUpdateFunction: 'webpackHotUpdate',
      jsonpFunction: 'webpackJsonp',
      chunkCallbackName: 'webpackChunk',
      devtoolNamespace: '',
      libraryTarget: 'var',
      pathinfo: true,
      sourceMapFilename: '[file].map[query]',
      hotUpdateChunkFilename: '[id].[hash].hot-update.js',
      hotUpdateMainFilename: '[hash].hot-update.json',
      crossOriginLoading: false,
      jsonpScriptType: false,
      chunkLoadTimeout: 120000,
      hashFunction: 'md4',
      hashDigest: 'hex',
      hashDigestLength: 20,
      devtoolLineToLine: false,
      strictModuleExceptionHandling: false
    },
    resolve: {alias: [Object],
      extensions: [Array],
      modules: [Array],
      plugins: [Array],
      unsafeCache: true,
      mainFiles: [Array],
      aliasFields: [Array],
      mainFields: [Array],
      cacheWithContext: true,
      preferAbsolute: true,
      ignoreRootsErrors: true,
      roots: [Array]
    },
    resolveLoader: {modules: [Array],
      plugins: [Array],
      unsafeCache: true,
      mainFields: [Array],
      extensions: [Array],
      mainFiles: [Array],
      cacheWithContext: true
    },
    module: {noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/,
      rules: [Array],
      unknownContextRequest: '.',
      unknownContextRegExp: false,
      unknownContextRecursive: true,
      unknownContextCritical: true,
      exprContextRequest: '.',
      exprContextRegExp: false,
      exprContextRecursive: true,
      exprContextCritical: true,
      wrappedContextRegExp: /.*/,
      wrappedContextRecursive: true,
      wrappedContextCritical: false,
      strictExportPresence: false,
      strictThisContextOnImports: false,
      unsafeCache: true,
      defaultRules: [Array]
    },
    optimization: {splitChunks: [Object],
      minimizer: [Array],
      removeAvailableModules: false,
      removeEmptyChunks: true,
      mergeDuplicateChunks: true,
      flagIncludedChunks: false,
      occurrenceOrder: false,
      sideEffects: false,
      providedExports: true,
      usedExports: false,
      concatenateModules: false,
      runtimeChunk: undefined,
      noEmitOnErrors: false,
      checkWasmTypes: false,
      mangleWasmImports: false,
      namedModules: true,
      hashedModuleIds: false,
      namedChunks: true,
      portableRecords: false,
      minimize: false,
      nodeEnv: 'development'
    },
    plugins: [VueLoaderPlugin {},
      [DefinePlugin],
      [CaseSensitivePathsPlugin],
      [FriendlyErrorsWebpackPlugin],
      [HtmlWebpackPlugin],
      [PreloadPlugin],
      [PreloadPlugin],
      [CopyPlugin],
      [HotModuleReplacementPlugin],
      [ProgressPlugin],
      HelloPlugin {}],
    entry: {app: [Array] },
    cache: true,
    target: 'web',
    performance: false,
    infrastructureLogging: {level: 'info', debug: false}
  },
  context: 'E:\\echarts\\code',
  requestShortener: RequestShortener {currentDirectoryRegExp: /(^|!)E:\/echarts\/code/g,
    parentDirectoryRegExp: /(^|!)E:\/echarts\//g,
    buildinsAsModule: true,
    buildinsRegExp: /(^|!)E:\/echarts\/code\/node_modules\/_webpack@4\.46\.0@webpack/g,
    cache: Map {}},
  running: false,
  watchMode: false,
  _assetEmittingSourceCache: WeakMap {<items unknown>},
  _assetEmittingWrittenFiles: Map {},
  watchFileSystem: NodeWatchFileSystem {
    inputFileSystem: CachedInputFileSystem {fileSystem: NodeJsInputFileSystem {},
      _statStorage: [Storage],
      _readdirStorage: [Storage],
      _readFileStorage: [Storage],
      _readJsonStorage: [Storage],
      _readlinkStorage: [Storage],
      _stat: [Function: bound bound],
      _statSync: [Function: bound bound],
      _readdir: [Function: bound readdir],
      _readdirSync: [Function: bound readdirSync],
      _readFile: [Function: bound bound readFile],
      _readFileSync: [Function: bound bound readFileSync],
      _readJson: [Function],
      _readJsonSync: [Function],
      _readlink: [Function: bound bound readlink],
      _readlinkSync: [Function: bound bound readlinkSync]
    },
    watcherOptions: {aggregateTimeout: 200},
    watcher: EventEmitter {_events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      options: [Object],
      watcherOptions: [Object],
      fileWatchers: [],
      dirWatchers: [],
      mtimes: [Object: null prototype] {},
      paused: false,
      aggregatedChanges: [],
      aggregatedRemovals: [],
      aggregateTimeout: 0,
      _onTimeout: [Function: bound _onTimeout]
    }
  }
}

简略的 plugin 写一个生成的动态资源文件

插件代码

class myPlugin {constructor(options) {// constructor 构造函数接管 new myPlugin(params)时传递的参数 params
        console.log("我是 new 这个类时所传递的参数 -->", options);
    }
    apply(compiler) {// console.log('^_^', compiler) // 下面有十分多 api,可供使用(参见 compiler 打印后果)compiler.hooks.emit.tapAsync('lss',(compliation,cb)=>{console.log('compliation',compliation.assets);
            const content=`
                - 生存不易
                - 打工仔加油致力
                - 奥利给
                - 😄😄😄 
            `
            compliation.assets['FBI-WARNING.md'] = {size() {return content.length},
                source: function () {return content}
            }
            cb()})
    }
}

module.exports = myPlugin

vue.config.js 文件中应用插件

// 引入这个插件
const myPlugin = require('./src/plugin/myPlugin')

  configureWebpack: {
    // 在 plugins 数组中实例化对象,若须要传参,变传递参数
    plugins: [new myPlugin('我是参数')
    ]
  },

未完待续。明天就先写(水)到这里吧

正文完
 0