从vuecli3学习webpack记录(四)vue是怎么进行默认配置的

栏目: IT技术 · 发布时间: 4年前

内容简介:在我们讲到vue cli3中在commands文件夹里面的是调用api.registerCommand方法,在config文件夹里面的(teserOptions.js和html除外)是调用api.chainWebpack方法,该方法会将传得的参数(该参数是一个方法)push到this.service.webpackChainFns数组。今天就展开看看里面具体是什么。

在我们讲到 从vuecli3学习webpack记录(一)vue-cli-serve机制

vue cli3中在commands文件夹里面的是调用api.registerCommand方法,在config文件夹里面的(teserOptions.js和html除外)是调用api.chainWebpack方法,该方法会将传得的参数(该参数是一个方法)push到this.service.webpackChainFns数组。

今天就展开看看里面具体是什么。

1.this.service其实就是cli3里面的Service(node_modules/@vue/cli-service/lib/Service.js)的实例,通过api.registerCommand方法将对应的serve(就是npm run serve那个serve)等command加入到this.commands这个对象属性里面,通过api.chainWebpack方法将app、base等webpack配置加入到this.webpackChainFns这个数组属性里面。

2.上面的api其实是PluginApi(node_modules/@vue/cli-service/lib/PluginApi.js)的实例,

部分代码如下

// node_modules/@vue/cli-service/lib/PluginApi.js
constructor (id, service) {
    this.id = id
    this.service = service
  }

registerCommand (name, opts, fn) {
    if (typeof opts === 'function') {
      fn = opts
      opts = null
    }
    this.service.commands[name] = { fn, opts: opts || {}}
  }

  chainWebpack (fn) {
    this.service.webpackChainFns.push(fn)
  }

cli3帮我们配置的默认配置是怎么进去的呢?

在此之前,我们先看看这些配置长什么样吧,以node_modules/@vue/cli-service/lib/config/base.js为例

我们一般在webpack里面是这样配置它

module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      }
    ]
}

而在cli3里面这样配置

module.exports = (api, options) => {
  api.chainWebpack(webpackConfig => {
        webpackConfig.module
              .rule('vue')
                .test(/\.vue$/)
                .use('cache-loader')
                  .loader('cache-loader')
                  .options(vueLoaderCacheConfig)
                  .end()
                .use('vue-loader')
                  .loader('vue-loader')
                  .options(Object.assign({
                    compilerOptions: {
                      preserveWhitespace: false
                    }
                  }, vueLoaderCacheConfig))

        webpackConfig
              .plugin('vue-loader')
              .use(require('vue-loader/lib/plugin'))

        webpackConfig.module
              .rule('images')
                .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
                .use('url-loader')
                  .loader('url-loader')
                  .options(genUrlLoaderOptions('img'))
     })
}

可以看出webpack的配置可以以链式调用的方式添加,这样就可以以更加灵活的函数式添加配置了。

webpackConfig 是什么鬼,这就要再次回到Service.js了,看它是怎执行 webpackChainFns 数组里面的函数了

const Config = require('webpack-chain')

resolveChainableWebpackConfig () {
    const chainableConfig = new Config()
    // apply chains
    this.webpackChainFns.forEach(fn => fn(chainableConfig))
    return chainableConfig
}

再看看 webpack-chain

const ChainedMap = require('./ChainedMap');
const ChainedSet = require('./ChainedSet');
const Resolve = require('./Resolve');
const ResolveLoader = require('./ResolveLoader');
const Output = require('./Output');
const DevServer = require('./DevServer');
const Plugin = require('./Plugin');
const Module = require('./Module');
const Optimization = require('./Optimization');
const Performance = require('./Performance');

module.exports = class extends ChainedMap {
  constructor() {
    super();
    this.devServer = new DevServer(this);
    this.entryPoints = new ChainedMap(this);
    this.module = new Module(this);
    this.node = new ChainedMap(this);
    this.optimization = new Optimization(this);
    this.output = new Output(this);
    this.performance = new Performance(this);
    this.plugins = new ChainedMap(this);
    this.resolve = new Resolve(this);
    this.resolveLoader = new ResolveLoader(this);
    this.extend([
      'amd',
      'bail',
      'cache',
      'context',
      'devtool',
      'externals',
      'loader',
      'mode',
      'parallelism',
      'profile',
      'recordsInputPath',
      'recordsPath',
      'recordsOutputPath',
      'stats',
      'target',
      'watch',
      'watchOptions',
    ]);
  }

  toConfig() {
    const entryPoints = this.entryPoints.entries() || {};

    return this.clean(
      Object.assign(this.entries() || {}, {
        node: this.node.entries(),
        output: this.output.entries(),
        resolve: this.resolve.toConfig(),
        resolveLoader: this.resolveLoader.toConfig(),
        devServer: this.devServer.toConfig(),
        module: this.module.toConfig(),
        optimization: this.optimization.entries(),
        plugins: this.plugins.values().map(plugin => plugin.toConfig()),
        performance: this.performance.entries(),
        entry: Object.keys(entryPoints).reduce(
          (acc, key) =>
            Object.assign(acc, { [key]: entryPoints[key].values() }),
          {}
        ),
      })
    );
  }
}

原来它针对webpack的配置里面的每一个大项都设置了不同的属性,并且分配以不同的方式实现。我们还可以看到里面有个 toConfig 方法,它会将最终的配置返回为我们熟悉的对象形式 的wepback配置,毕竟webpack只认这种配置。

下面就以 this.module 为例吧,因为看到它的链式调用里面有个 end 方法,会让链式调用调回去,方便执行后续的 use('vue-loader')

// node_modules/webpack-chain/src/Module.js
module.exports = class extends ChainedMap {
  constructor(parent) {
    super(parent);
    this.rules = new ChainedMap(this);
    this.defaultRules = new ChainedMap(this);
    this.extend(['noParse']);
  }
}

Module 继承 ChainMap ,而 ChainMap 又继承自 Chainable ,我们要看的 end 方法就是在这里

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({
          google_ad_client: "ca-pub-3013839362871866",
          enable_page_level_ads: true
     });
</script>
// node_modules/webpack-chain/src/Chainable.js
module.exports = class {
  constructor(parent) {
    this.parent = parent;
  }

  batch(handler) {
    handler(this);
    return this;
  }

  end() {
    return this.parent;
  }
};

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript高级程序设计(第3版)

JavaScript高级程序设计(第3版)

[美] Nicholas C. Zakas / 李松峰、曹力 / 人民邮电出版社 / 2012-3-29 / 99.00元

本书是JavaScript 超级畅销书的最新版。ECMAScript 5 和HTML5 在标准之争中双双胜出,使大量专有实现和客户端扩展正式进入规范,同时也为JavaScript 增添了很多适应未来发展的新特性。本书这一版除增加5 章全新内容外,其他章节也有较大幅度的增补和修订,新内容篇幅约占三分之一。全书从JavaScript 语言实现的各个组成部分——语言核心、DOM、BOM、事件模型讲起,深......一起来看看 《JavaScript高级程序设计(第3版)》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具