webpack

作者: 9吧和9说9话 | 来源:发表于2020-02-07 13:27 被阅读0次

    webpack是啥?

    静态模块打包工具。

    会从入口文件开始,递归的分析模块以及依赖模块,然后进行模块路径解析,loader处理,plugin处理等等,最终产出静态资源:js css images fonts 等等。

    配置文件概述

    一切从webpack.config.js 配置文件开始。
    webpack早期的版本,模糊不清的文档被大家所诟病,好在目前webpack4的文档已经非常清晰,而且社区生态也是非常的活跃和强大。

    module.exports = {
        mode: xxx,
        // 入口
        entry:xxx,
        output: xxx,
        module: {
          rules: []
        },
        plugins: [],
        resolve: {
            modules: [],
            extensions: [],
            alias: [],
        },
        devtool: xxx,
        devServer: {},
        ....
      
    }
    
    

    特点

    1. 配置型
    2. 所有的静态资源都可以视为模块
    3. 支持HMR
    4. 扩展性良好: 可以通过自定义loaderplugins实现特定的业务需求。
    5. 目前为止,社区活跃、强大,很多前端技术栈体系都是依靠webpack来组织和构建,比如流行的 reactvue等。

    注意点

    1. webpack 已经内置支持了各种的模块记载机制(es2015、AMD、commonjs等),其内部实现 会将代码进行transpile,实现了旧版本浏览器也可以执行。

    常用的点

    1. 一般使用webpack-dev-server来搭建开发环境,默认提供了livereload功能。
    2. webpack-dev-server内部实现依赖的webpack-dev-middleware
    3. webpack-dev-server 可以通过配置hot配置项来开启HMR特性, 但是具体的实现需要自己来,好在强大的社区已经为我们实现了相关资源模块的热更新替换, 比如css-loader就为我们提供了css样式的HMR功能。

    webpack编译过程

    webpack编译过程

    1. 收集配置项
    2. 实例化Compiler对象,调用run 或者是 watch开始编译
    3. Compiler继承自Tabable类,Tabable类实现了订阅发布模式。
    4. 各个hooks就是事件列表,tap tapPromise tapAsync 是添加事件,call promise callAsync 就是执行事件列表。
      hooks
    5. webpack内部不同的hooks部署到webpack编译的各个阶段。
    6. 所以我们实现自己插件的时候,定义了一个类,有一个apply方法,在apply方法中对编译的不同阶段 添加处理流程。

    插件

    webpack 自己也是基于plugin的机制进行实现。

    1. plugin 的作用
    2. 实现自己的plugin

    loader

    1. loader的作用

    2. 实现自己的loader

    所谓 loader 只是一个导出为函数的 JavaScript 模块。内部 webpack会调用它。

    const {getOptions} = require('loader-utils');
    const schemaUtils = require('schema-utils');
    module.exports = function (source) {
        const options = getOptions(this);
        console.log(options, "options");
        console.log('-----------');
        console.log(source);
        
        schemaUtils(schema, options, 'Example Loader');
    
        // Apply some transformations to the source...
        return source;
    }
    

    学习代码的一种最好的方式就是学习开源的优秀lib,所以我clonefile-loader css-loader style-loader我们常用的几个loader来学习。

    先看下file-loader:

    import path from 'path';
    
    // 引入常用的loader辅助工具
    import loaderUtils from 'loader-utils';
    // 引入loader 配置项校验工具
    import validateOptions from 'schema-utils';
    
    // 配置项的校验格式要求
    import schema from './options.json';
    // 暴露一个函数 给webpack使用
    export default function loader(content) {
      // 获取到配置loader的配置项
      const options = loaderUtils.getOptions(this) || {};
      // 校验配置项
      validateOptions(schema, options, {
        name: 'File Loader',
        baseDataPath: 'options',
      });
    
      const context = options.context || this.rootContext;
      // 调用了loader-utils的辅助方法
      const url = loaderUtils.interpolateName(
        this,
        options.name || '[contenthash].[ext]',
        {
          context,
          content,
          regExp: options.regExp,
        }
      );
    
      let outputPath = url;
    
      if (options.outputPath) {
        if (typeof options.outputPath === 'function') {
          outputPath = options.outputPath(url, this.resourcePath, context);
        } else {
          outputPath = path.posix.join(options.outputPath, url);
        }
      }
    
      let publicPath = `__webpack_public_path__ + ${JSON.stringify(outputPath)}`;
    
      if (options.publicPath) {
        if (typeof options.publicPath === 'function') {
          publicPath = options.publicPath(url, this.resourcePath, context);
        } else {
          publicPath = `${
            options.publicPath.endsWith('/')
              ? options.publicPath
              : `${options.publicPath}/`
          }${url}`;
        }
    
        publicPath = JSON.stringify(publicPath);
      }
    
      if (options.postTransformPublicPath) {
        publicPath = options.postTransformPublicPath(publicPath);
      }
      // 产出文件
      if (typeof options.emitFile === 'undefined' || options.emitFile) {
        this.emitFile(outputPath, content);
      }
    
      const esModule =
        typeof options.esModule !== 'undefined' ? options.esModule : true;
      // 返回路径
      return `${esModule ? 'export default' : 'module.exports ='} ${publicPath};`;
    }
    
    export const raw = true;
    
    

    相关文章

      网友评论

          本文标题:webpack

          本文链接:https://www.haomeiwen.com/subject/pmclzctx.html