乐趣区

关于前端:前端工程化7自定义实现Webpack中的Loader和Plugin

loader 比照 plugin

  • loader:用于资源加载并解决各种语言的转换 / 编译(例如将不同语言转换为 javascript);
  • plugin:用于资源加载以外的其余打包 / 压缩 / 文件解决等性能;

loader 原理,loader 的自定义实现

loader 用处

loader 用于资源加载并解决各种语言的转换 / 编译(例如将不同语言转换为 javascript);

loader 实现原理,自定义实现

  1. loader 函数:loader 必须导出一个函数;它对资源文件进行解决后输入内容;它相似于管道,能够串联多个 loader,将返回值交给下一个 loader 持续解决;
  2. loader 输出:function 接管一个参数作为输出,该参数的内容为文件内容
  3. loader 输入:return 一个返回值作为输入,该返回值为模块导出的字符串;loader 须要将返回值作为一个模块导出,能力更好的在 webpack 打包文件中应用,有三种导出形式;
  • (1)依照 ES Modules 形式导出
  • (2)依照 CommonJS 形式导出
  • (3)loader 解决相似于管道,能够串联多个 loader,能够间接将返回值交给下一个 loader 持续解决;
// 自定义 loader:// 性能:导入 markdown 文件,将 markdown 转换成 html 导出


// 插件:marked 实现将 markdown 内容转换成 html 的性能
const marked = require('marked')

// loader 须要返回一段 js 代码:因为在 webpack 加载时会将这段代码拼接到打包代码中~
// 输出:function 的参数作为输出值:这里是原有的 markdown 内容,source
// 输入:return 一个返回值作为输入:这里是转换成 html 的内容,html(// 输入留神:1、须要将返回值作为一个模块导出,能力更好的在 webpack 打包文件中应用
// 输入留神:2、module.exports = source => {const html = marked(source)

    // webpack 将 loader 加载后会将代码放到打包文件 boundle.js 中,一个 loader 对应一个 (function(){}) 模块;所以在 loader 中须要导出
    // webpack 的打包文件 boundle.js 中,反对 CommonJS 的形式、ES Modules 的形式导出

    // loader 的
    // 1、CommonJS 的形式:输入的模块转换为字符串的模式 return
    // return `module.exports = ${JSON.stringify(html)}`//JSON.stringify 转换 html 的换行符和空格

    // 2、ES Modules:webpack 外部会主动转换 export default 导出的代码
    // return `export default ${JSON.stringify(html)}`


    // 3、间接返回 html,再将后果交给 html-loader 解决(loader 是管道的模式解决,能够串联)return html
}
  1. 应用自定义 loader
  module: {
    rules: [
        {// 自定义 loader,markdown-loader
            test: /.md$/,
            use: [                    // 串联多个 loader,执行程序从下到上
              'html-loader',          // 装置 html-loader:npm install html-loader --save-dev
              './markdown-loader.js'  // 自定义实现的 loader
            ]
        },
    ]
  },

plugin 原理,plugin 的自定义实现

plugin 用处

用于资源加载以外的其余打包 / 压缩 / 文件解决等性能;

plugin 插件机制(Hook 钩子机制)

  • 须要理解 taple 钩子:https://gitee.com/ymcdhr/e-demo/tree/master/webpack-source-code
  • webpack 钩子:https://webpack.docschina.org/api/compiler-hooks/#hooks

plugin 实现原理,自定义实现:

  1. plugin 是依据 webpack 生命周期的钩子机制进行开发的,plugin 通过在钩子中挂载函数实现扩大;webpack 钩子参考文档:https://webpack.docschina.org/api/compiler-hooks/#hooks
  2. plugin 必须是一个函数,或者蕴含 apply 办法的对象
  • apply 办法有一个参数 compiler;
  • 通过 compiler 能够给 webpack 编译打包过程中增加钩子;
  • 通过钩子的回调函数 callback 拿到打包后果对象 compilation(通过 compilation.assets 获取资源文件信息);
  • 而后对打包后果对象 compilation 进行批改;
// 自定义 plugin:// 性能:将 js 文件中的正文删除调

// 自定义插件
// 自定义插件必须是一个函数,或者蕴含 apply 办法的对象
// plugin 依据 webpack 生命周期钩子函数开发的:https://webpack.docschina.org/api/compiler-hooks/#hooks
// compiler.hooks 能够拜访钩子
// 性能:革除打包过程中的正文
class MyPlugin {apply (compiler){console.log('MyPlugin 启动')
  
      // emit 钩子的执行机会是:输入打包好的资源文件 asset 到 output 目录之前执行。compiler.hooks.emit.tap('MyPlugin', compilation => {
        // compilation => 能够了解为此次打包的后果
        // compilation.assets => 获取 dist 目录的所有生成的资源文件信息,例如:bundle.js
        for (const name in compilation.assets) {// console.log(name)
  
          // 获取到资源的内容,例如:bundle.js 外面的内容
          console.log(compilation.assets[name].source())
  
          // 判断文件是否为 js 文件
          if (name.endsWith('.js')) {
            // 替换掉 js 文件中的正文
            const contents = compilation.assets[name].source()
            const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
  
            // 笼罩原有内容
            compilation.assets[name] = {source: () => withoutComments, // 新的内容
              size: () => withoutComments.length // 内容的大小,webpack 必须的办法}
          }
        }
      })
    }
}


module.exports = MyPlugin
  1. 在 webpack.config.js 配置中引入插件
const MyPlugin = require('./comment-plugin.js')

module.exports = {
  // ...
  plugins: [new MyPlugin() // 自定义插件
  ]
}

特地鸣谢:拉勾教育前端高薪训练营

退出移动版