Loading...
墨滴

许彦峰

2021/12/12  阅读:50  主题:橙心

vue-cli-service源码分析解读

入口

bin/vue-cli-service.js

const services=new Service(process.cwd());
services.run(cmd)

service的构造函数中会加载内置的几个plugins

services.run会调用一个核心函数init

init(){

  // 处理.env(.mode?)(.local?)等环境变量,使用了dotenv模块,最终会挂在process.env变量上
  this.loadEnv(mode);
  this.loadEnv();

  // 处理并加载vue.config.js
this.loadUserOptions();

// 处理内置插件,registerCommand,
// 内置插件
// built-in:commands/serve
// built-in:commands/build
// built-in:commands/inspect
// built-in:commands/help
// built-in:config/base
// built-in:config/css
// built-in:config/prod
// built-in:config/app

// 执行插件
this.plugins.forEach((id,apply)=>{
  // apply来自loadModule的返回值
  apply(new PluginAPI(id,this),this.projectOptions);
});

const {fn} = this.commands;
fn();
}

当执行build命令时,最终的fn会回调到built-in:command/build

vue-cli-service build

cli-service/lib/commands/build/index.js

api.registerCommand(
  'build',
  {
    // ...一些build命令的参数
  },
  async (args, rawArgs){
    // 中间有许多校验逻辑,最终会调用具体的build
    await build(...);
  }
)

查看下build的具体实现


async function build(args, api, options){

  let webpackConfig
  // 根据不同搞的target获取默认的webpackConfig
  if(target === 'lib'){
  
  }else if(target ==='wc'||target==='wc-async'){
  
  }else{
    webpackConfig=require('./resolveAppConfig');
  }
  // 校验webpack的配置参数
  validateWebpackConfig(webpackConfig);
  // 最终还是回到webpack,来生成最终的文件
  return new Promise((resolve,reject)=>{
    webpack(webpackConfig,(error,stats)=>{
      // ...
      console.log('Build complete')
    })
  })

}

重点看下resolveAppConfig.js

module.exports=(api:PluginAPI,args,options){
  //本质是: new ()();
  const config = api.resolveChainableWebpackConfig();
  api.resolveWebpackConfig(config);
}

最终又来到service.js

resolveChainableWebpackConfig(){
  const wenpackChain=require('webpack-chain');
  let chainableConfig = new wenpackChain();
  // 将所有的chain重组,定义了非常多的chains规则,这里集中进行了处理
  this.webpackChainFns.forEach(fn => fn(chainableConfig))
  return chainableConfig;
}

resolveWebpackConfig(chainConfig){
  // ...
  let config = chainConfig.toConfig(); // 转换为webpack的配置
  // ...
  return config;
}

重点就来到了对webpack-chain的配置操作

vue的插件

resolvePlugins(){
     const idToPlugin = id => ({
      id: id.replace(/^.\//'built-in:'),
      applyrequire(id)
    })
// 这部分会检索到devDependencies,换而言之,插件只需要在devDependencies声明后就会生效
         const projectPlugins = Object.keys(this.pkg.devDependencies || {})
        .concat(Object.keys(this.pkg.dependencies || {}))
        .filter(isPlugin)
        .map(id => {
          if (
            this.pkg.optionalDependencies &&
            id in this.pkg.optionalDependencies
          ) {
            let apply = () => {}
            try {
              apply = require(id)
            } catch (e) {
              warn(`Optional dependency ${id} is not installed.`)
            }

            return { id, apply }
          } else {
            return idToPlugin(id)
          }
        })
      plugins = builtInPlugins.concat(projectPlugins)
}

所以插件一般的格式为

module.exports=(api:PluginAPI, options){
  // ...
  
  // 以下是2个比较重要的函数,可以修改webpack的配置
  api.chainWebpack((webpackConfig)=>{
  
  });
  api.configureWebpack((webpackConfig)=>{
  
  });
}

再回头看下PluginAPI,就一目了然,对整体越来越理解了

总结

简单来说,就是对webpack包装了一层cli,使用起来无须关注过多的webpack相关的配置,同时也可以充分利用webpack的生态。

收获

ora一个终端旋转器

许彦峰

2021/12/12  阅读:50  主题:橙心

作者介绍

许彦峰