最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • [ webpack ] webpack 的 loader 和 plugin 开发的方法

    正文概述 掘金(GavinUI)   2021-06-12   466

    Loader 和 Plugins 的区别

    loader 主要的是处理静态资源,而 plugins 是可以贯穿在整个 webpack 构建的周期中,他能做到 loader 做不到的事情。但是,loader 他可以用独立的运行环境,可以在本地使用一些库进行本地发发调制,而 plugins 不行,他必须编写好这个 plugin 之后在 webpack 构建中将 plugin 放在 plugins 的数组中执行。

    [ webpack ] webpack 的 loader 和 plugin 开发的方法

    loader 开发的常用的开发方法

    webpack 文档 DEMO 结构分析

    import { getOptions } from 'loader-utils';
    import { validate } from 'schema-utils';
    const schema = {
      type: 'object',
      properties: {
        test: {
          type: 'string',
        },
      },
    };
    export default function (source) {
      const options = getOptions(this);
      validate(schema, options, {
        name: 'Example Loader',
        baseDataPath: 'options',
      });
      // Apply some transformations to the source...
      return `export default ${JSON.stringify(source)}`;
    }
    

    loader 实际上就是一个 js 模块,提供一个方法对原文件进行逻辑操作,处理完毕之后返回回去的一个过程。顺带提一点就是,loader 的链式调用是从后往前。

    同步 loader 参数获取

    参数获取可以使用一个 叫 loader-utils 的 loader,使用其中的 getOptions 的方法就可以拿到传递的参数。 在 runLoaders 配置中 loaders 参照文档修改为带 options 的配置,举例加上一个对象:

    runLoaders({
        loaders: [
            // path.join(__dirname, './loaders/raw-loader.js'),
            {
                loader: path.join(__dirname, './loaders/raw-loader.js'),
                options:{
                    env: 'development',
                    version: '1.0.0'
                },
            }
        ],
    ...})
    

    之后使用 loader-utils 将传递的参数带出。注意,这里的 module.exports 不能使用箭头函数,否则,this 是指向了当前的作用域,就拿不到 runLoaders 里面的属性了。

    // npm install loader-utils -save-dev
    const loaderUtils = require('loader-utils');
    
    module.exports = function (source) {
        console.log(this);
        const { env, version } = loaderUtils.getOptions(this);
        console.log(env);
        console.log(version);
        ...
    };
    
    // npmjs -> https://www.npmjs.com/package/loader-utils 
    

    同步 loader 异常处理

    同步执行的情况下,处理异常错误打印的方式有两种:

    第一种:是直接使用 Error 输出错误,可以在信息内填写错误编号

    
    module.exports = function (source) {
     	  ...
        return new Error('error:10001');
    };
    

    第二种:是直接使用 this.callback ,根据参数的不同,再执行下一步或者是输出报错信息。

    module.exports = function (source) {
    		...
        return this.callback(new Error('error:10001'), source);
    };
    

    this.callback 的第一个参数是 Error 时,表示异常直接报错,如果第一个参数是 null ,那就说明函数正常执行下一步返回数据, 同时也支持多个参数进行传递,代码如下:

    module.exports = function (source) {
    		...
    		const params = { key: 1 }
        return this.callback(null, source, params);
    };
    

    异步 loader 处理

    使用异步获取结果需要使用 this.async() 这个方法,作为一个 callback 使用,第一个参数是判断是否错误,第二个直接传递参数。

    module.exports = function (source) {
    		...
        const callback = this.async();
        fs.readFile(path.join(__dirname, '../src/number.txt'), 'utf-8', (err, data) => {
            if(err){
                callback(err,'error')
            }
            callback(null, data);
        });
    };
    

    loader 输出文件

    使用 emitFile 进行输出。

    const loaderUtils = require('loader-utils');
    module.exports = function (source) {
        const url = loaderUtils.interpolateName(this, '[name].[ext]', source);
        this.emitFile(url, source)
        return source;
    }
    

    开发适用于活动的 CSS Sprites loader

    首先,需要使用 spritesmith 这个依赖,将多张图片和合并到一起。

    第一步:读取图片 URL

    思路是先将 css 文件获取到,再使用正则匹配导出所有的图片地址

    const loaderUtils = require('loader-utils');
    module.exports = function (source) {
       const images = source.match(/url\((\S*)/g);
       const matchedImages = [];
       if (images && images.length > 0) {
    		for (let i = 0; i < images.length; i++) {
         const img = images[i].match(/url\(..(\S*)\'/)[1];
         matchedImages.push(path.join(__dirname, img));
        }
       }
    }
    

    再把文件的目录提取出来,转换成一个绝对地址 push 到一个数组里面,打印出来的 matchedImages 如下:

    [
      '/Users/../images/web-security-bg-1.jpeg',
      '/Users/../images/webpack-images-2.png'
    ]
    

    第二步:使用 spritesmith 合并图片和 css 地址替换

    Spritesmith.run({ src: matchedImages}, (err, result) => {
    	fs.writeFileSync(path.join(process.cwd(), 'dist/sprite.png'), result.image);
    	source = source.replace(/url\((\S*)/g, (match) =>{
    		return `url("dist/sprite.jpg")`;
      });
      fs.writeFileSync(path.join(process.cwd(), 'dist/index.css'), source);
         callback(null,source); })
    
    

    在 dist 的目录中,就会出现一个合并好的图片同时 dist 里面还有一个已替换了 sprite 图的 css 文件 ,当然这里只是说明了一个思路,如果要完全的实现图片和样式的替换还需要考虑到背景大小,定位或者是一些边界问题,这里就不再细说了。

    webpack 的 Plugin 的常用的开发方法

    webpack 文档 DEMO 结构分析

    // webpack writting a plugin -> https://webpack.js.org/contribute/writing-a-plugin/
    
    // A JavaScript class.
    class HelloWorldPlugin {
      apply(compiler) {
        compiler.hooks.done.tap('Hello World Plugin', (
          stats /* stats is passed as an argument when done hook is tapped.  */
        ) => {
          console.log('Hello World!');
        });
      }
    }
    module.exports = HelloWorldPlugin;
    

    plugin 实际上一个一个类,在 webpack 使用 plugin 的时候都会有 new XXplugin() 的操作,就是新建一个 plugin 的类。apply 是 plugin 在 webpack 是每一次构建的时候都会运行。

    hooks 是 compiler 对象的一个钩子,也可以说是可以监听在某个阶段做一些什么样的事情。会掉的最后就是这个 plugin 的逻辑代码。

    开发一个压缩构建资源为 zip 包的 plugin

    创建 zip 文件

    首先,还是先使用一个 jszip 它可以将文件压缩成一个 zip 包,使用 compiler 对象的 hooks 的 emit 钩子,生成一个文件。

    const JSZip = require('jszip');
    const zip = new JSZip();
    compiler.hooks.emit.tapAsync('ZipPlugin', (Compilation, callback) => {
        const folder = zip.folder(this.options.filename);
        for (let filename in Compilation.assets) {
            const source = Compilation.assets[filename].source();
            folder.file(filename, source)
        }
    })
    

    使用 zip.folder 先设置 zip 包的名称, 在触发到了emit 的 tapAsunc 异步钩子的时候,处理 compilation 的内容填充到 folder 里面去。 compilation.assist 是一个目录名,遍历出文件名之后使用 source 拿到 source 在放回 folder 中。

    第二步将文件输出为 zip

    zip.generateAsync({
      type:'nodebuffer'
      	}).then((content)=>{
      	const outputPath = path.join(Compilation.options.output.path 	,this.options.filename + '.zip');
      const outputRelativePath = path.relative(
        Compilation.options.output.path,
        outputPath
      )
      Compilation.assets[outputRelativePath] = new RawSource(content);
        callback()
        console.log(Compilation.options)
      })
    })
    

    使用 zip.generateAsync 返回的 content 是一个 buffer ,需要使用 RawSource 将这个 buffer 转换挂到 compilation 的 assist 中 ,最后执行 callback 。


    起源地下载网 » [ webpack ] webpack 的 loader 和 plugin 开发的方法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元