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

    正文概述 掘金(爱笑阿)   2021-03-29   472

    webpack

    一句话总结,webpack是用来编译打包代码的.

    在当下ES6语法在项目中屡见不鲜的情况下,一些浏览器其实对ES6还不是很友好,这时候就需要有个中间介质来做翻译.那webpack就是市面上众多'翻译'中的一员.

    在日常开发中,我们除了一些样式/图片元素还会使用很多框架,类库...来提升我们的输出效率.让我们可以更有效率的完成开发工作.比如: vue.js、Eslint、Less/Sass、Es6、image...但是就会出现一个问题,这些东西,或者说模块浏览器不认识,这就需要使用webpack来让浏览器认识这些代码.

    loader

    loader用于对模块源代码进行转换.loader可以将不同语言转换为JavaScript,可以将内联图像转换为data URL,他可以让开发者直接在JavaScript模块中使用import();

    loader就是一个导出的function.当要对资源进行转换时,会调用这个函数.

    loader是怎么在项目中使用的

    可以直接使用path到一个loader.js

    const path = require('path');
    
    module.exports = {
      //...
      module: {
        rules: [
          {
            test: /\.js$/,
            use: [
              {
                loader: path.resolve('path/to/loader.js'),
                options: {
                  /* ... */
                },
              },
            ],
          },
        ],
      },
    };
    

    要测试多个loader,使用resolveLoader.modules来配置webpack在什么地方去查找:

    const path = require('path');
    
    module.exports = {
      //...
      resolveLoader: {
        modules: ['node_modules', path.resolve(__dirname, 'loaders')],
      },
    };
    

    如果是通过npm之类的包管理工具安装的loader:

    module.exports = {
      //...
      module: {
        rules: [
          {
            test: /\.js/,
            use: ['bar-loader', 'foo-loader'],
          },
        ],
      },
    };
    

    如何编写一个loader

    一个loader首先需要导出一个函数, 这个函数会拿到需要编译处理的内容,然后对这个内容进行一些列的处理,最后返回处理后的内容.

    module.exports = function(source) {
        // ...
        return source;
    }
    

    下面我们来实现一个简单的编译markdown的loader来落地上面的想法:

    • 新建文件夹loader,npm init 初始化package.json然后安装webpack-cli webpack-dev-server webpack

    npm init

    npm i -D webpack webpack-cli webpack-dev-server

    • 创建webpack.config.js
    var path = require('path')
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.md$/,
            // html是用来处理md转换之后生成的html的
            use: ['html-loader', './src/loader/md-loader'], 
          },
        ],
      },
      devServer: {
        contentBase: './dist',
        overlay: {
          warnings: true,
          errors: true,
        },
        open: true,
      },
    }
    
    • 创建index.js 使用 index.md模块
    import md from './index.md'
    
    var content = document.createElement('div')
    content.innerHTML = md
    document.body.appendChild(content)
    
    • 新建loader文件 添加md-loader.js
    var marked = require('marked')
    
    module.exports = function (source) {
      var html = marked(source)
      return html
    }
    

    然后run 就可以看到页面上展示出我们markdown中的内容了. 源码入口

    上面我们实现的是一个简单的loader,实质上loader有很多options可供配置选择.loader-utils提供了很多有用的工具.更多loader配置可以移步.

    常用loader示例

    • babel-loader
    • vue-loader
    • html-loader
    • style-loader
    • css-loader
    • sass-loader
    • file-loader
    • url-loader ...

    plugin

    plugin比loader更强大,当loader满足不了你的需求时就需要plugin了.plugin向开发者提供了webpack引擎中完整能力.用官方的话说就是创建plugin比创建loader更高级!

    plugin是怎么在项目中使用的

    webpack.config.js

    const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
    const webpack = require('webpack'); // 访问内置的插件
    const path = require('path');
    
    module.exports = {
      entry: './path/to/my/entry/file.js',
      output: {
        filename: 'my-first-webpack.bundle.js',
        path: path.resolve(__dirname, 'dist'),
      },
      module: {
        rules: [
          {
            test: /\.(js|jsx)$/,
            use: 'babel-loader',
          },
        ],
      },
      plugins: [
        new webpack.ProgressPlugin(), // 用于自定义编译过程中的进度报告
        // 将生成一个 HTML 文件,并在其中使用 script 引入一个名为 my-first-webpack.bundle.js 的 JS 文件, 这样我们就不用像上文那样在index.html中引入打包之后的bundle.js文件了.
        new HtmlWebpackPlugin({ template: './src/index.html' }),
      ],
    };
    

    如何编写一个plugin

    一个plugin的构成部分分为以下几点:

    • 一个具名的JavaScript函数
    • 函数的prototype上要有一个apply方法
    • 指定一个触及到webpack本身的钩子(hooks) complier hooks
      • complier 代表了整个webpack从启动到关闭的生命周期
    • 操作webpack内部的实例特定数据 compilation hooks
      • compilation 只代表一次单独的编译
    • 实现功能后调用callback
    // 一个 JavaScript class
    class MyExampleWebpackPlugin {
      // 将 `apply` 定义为其原型方法,此方法以 compiler 作为参数
      apply(compiler) {
        // 指定要附加到的事件钩子函数
        compiler.hooks.emit.tapAsync(
          'MyExampleWebpackPlugin',
          (compilation, callback) => {
            // 钩子第二个参数以compilation 为参数
    
            // 使用 webpack 提供的 plugin API 操作构建结果
            compilation.addModule(/* ... */)
    
            callback()
          }
        )
      }
    }
    module.exports =  MyExampleWebpackPlugin
    

    下面我们实现一个简单的代码来实现html-webpack-plugin(它的源码还是比较复杂的,这边只是实现简单功能,不做过多参数配置).

    • 首先,npm init -y 并安装webpack以及 webpack-cli.我这边使用了webpack-dev-server(手动执行webpack太麻烦,起服务方便)
    {
      ...
      "dependencies": {
        "webpack": "^4.46.0",
        "webpack-dev-server": "^3.11.2"
      },
      "devDependencies": {
        "webpack-cli": "^3.3.12"
      }
    }
    
    • 创建webpack.config.js
    var path = require('path')
    var MyExampleWebpackPlugin = require('./src/plugins/index')
    module.exports = {
      mode: 'development',
      devServer: {
        contentBase: './dist',
        overlay: {
          warnings: true,
          errors: true,
        },
        open: true,
      },
      entry: '/src/app.js',
      output: {
        path: path.resolve(__dirname, './dist'),
        filename: 'bundle.js',
      },
      plugins: [new MyExampleWebpackPlugin()],
    }
    
    • 编写plugin
    class MyExampleWebpackPlugin {
      apply(compiler) {
        compiler.hooks.emit.tapAsync(
          'MyExampleWebpackPlugin',
          (compilation, callback) => {
            let html = `
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>Document</title>
            </head>
            <body>
                <div id="app"></div>
            </body>
            <script src="./bundle.js"></script>
            </html>
          `
            compilation.assets['index.html'] = {
              source() {
                return html
              },
              size() {
                return html.length
              },
            }
            callback()
          }
        )
      }
    }
    
    • 执行npm run dev就ok了

    谈: webpack的loader与plugin

    对了,这里可能会碰到一个问题就是执行webpack-dev-server会起一个服务,然后执行配置中的内容, 但是它不会生成打包后的文件.根本原因是webpack与webpack-dev-server是两个工具,后者不做打包的事情,就是起个服务.

    打包的话执行./node_modules/.bin/webpack 源码入口.

    常用的plugin示例

    • HtmlWebpackPlugin
    • CleanWebpackPlugin
    • CopyWebpackPlugin
    • BannerPlugin
    • TerserWebpackPlugin
    • UglifyjsWebpackPlugin
    • DLLPlugin与DllReferencePlugin
    • HotModuleReplacementPlugin

    总结

    webpacktapable有这密不可分的关系,上文中的compilercompilation都是tapable实例化出来的.上文中也提到了它们各自有很多hooks,可以分别用在编译或者打包不同进行时间做处理.

    在现在的开发工作中, webpack与我们息息相关.对于它海量的文档API,其实不用望而却步,我们需要理解它的目的,以及它做的事情,这样用起来肯定游刃有余.至于API,我认为常用的比如loader/plugin稍加了解即可,在实际业务场景中使用到的话,去做深入学习即可.


    起源地下载网 » 谈: webpack的loader与plugin

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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