【问题标题】:Webpack : How to convert variables on buildWebpack:如何在构建时转换变量
【发布时间】:2017-11-29 06:25:15
【问题描述】:

关于使用 Vue (vue-loader) + WebpackChromatism

示例:(在开发/源上)

let textColor = chromatism.contrastRatio('#ffea00').cssrgb // => rgb(0,0,0)

是否可以告诉 Webpack 在构建版本上转换rgb(0,0,0)

所以在 build version 上应该转换为:(for performance)

let textColor = 'rgb(0,0,0)'

【问题讨论】:

  • 我相信没有人写过 AOT 插件来处理这个问题。您可能必须自己进行自定义构建步骤,或者编写一个插件来执行此操作
  • 这叫 AOT 对吧? @JoeyCiechanowicz

标签: javascript performance variables webpack vue.js


【解决方案1】:

正如之前的答案和 cmets 已经提到的,没有现成的 AOT 编译器来处理这种情况(我的意思是这是一个非常特殊的情况,没有通用工具能够处理它),有没有什么能阻止您推出自己的加载器/插件来处理此任务!
您可以使用自定义 Webpack LoaderNode's VM Module 在构建时执行代码,获取其输出并将其替换为源文件中的函数调用。
这个想法的一个示例实现看起来像下面的 sn-p:

// file: chromatismOptimizer.js

// node's vm module https://nodejs.org/api/vm.html
const vm = require('vm')

const chromatism = require('chromatism')

// a basic and largley incomplete regex to extract lines where chromatism is called
let regex = /^(.*)(chromatism\S*)(.*)$/

// create a Sandbox 
//https://nodejs.org/api/vm.html#vm_what_does_it_mean_to_contextify_an_object
// this is roughly equivalent to the global the context the script will execute in
let sandbox = {
  chromatism: chromatism
}

// now create an execution context for the script
let context = new vm.createContext(sandbox)

// export a webpack sync loader function
module.exports = function chromatismOptimizer(source){
  let compiled = source.split('\n').reduce((agg, line) => {
    let parsed = line.replace(regex, (ig, x, source, z) => {
      // parse and execute the script inside the context
      // return value is the result of execution
      // https://nodejs.org/api/vm.html#vm_script_runincontext_contextifiedsandbox_options
      let res = (new (vm.Script)(source)).runInContext(context)
      return `${x}'${res}'${z? z : ''}`
    })
    agg.push(parsed)
    return agg;
  }, []).join('\n');

  return compiled;
}

然后在您的 production.webpack.js(或类似的文件)中取自 this issue:

// Webpack config
resolveLoader: {
  alias: {
    'chromatism-optimizer': path.join(__dirname, './scripts/chromatism-optimizer'),
  },
}
// In module.rules
{
  test: /\.js$/,
  use: ['chromatism-optimizer'],
}

注意:这只是一个参考实现,基本上是不完整的。此处使用的正则表达式非常基础,可能无法涵盖许多其他用例,因此请确保更新正则表达式。此外,这一切都可以使用 webpack 插件来实现(只是我没有足够的知识来创建一个)。对于快速入门refer to this wiki 了解如何创建自定义插件。

基本思想很简单。

  1. 首先创建一个沙盒环境,
    let sandbox = { chromatism:chromatism, ...}

  2. 然后创建一个执行上下文,
    let context = new vm.createContext(sandbox)

  3. 然后对于每个有效的源,在上下文中执行源语句并得到结果。
    let result = (new (vm.Source)(source)).runInContext(context)

  4. 然后可能用结果替换原来的源语句。

【讨论】:

  • 感谢您对文章的精彩回答!我还没有测试。但似乎这是正确的做法。加油!
【解决方案2】:

尝试使用call-back loader 来处理你所有的 JavaScript。为这种特定情况甚至更一般的情况定义一个回调函数,例如: evalDuringCompile: function(code) { return JSON.stringify(eval(code)); }

【讨论】:

    【解决方案3】:

    State of Art 优化器无法处理任意表达式。在这种情况下,最可靠的解决方案是像这样在代码中使用硬代码常量。

    let textColor = process.env.NODE_ENV === 'production' ? 'rgb(0,0,0)' :  chromatism.contrastRatio('#ffea00').cssrgb;
    

    一些未来的优化器确实可以处理这样的情况。 prepack 将在编译时评估代码并输出计算值。但是,它通常不被认为是生产就绪的。

    【讨论】:

    • +1 感谢 Prepack 参考。但是你的例子不是我想要的对不起。我无法设置 if else 未知变量的简写
    • 如果您的代码包含非常量变量。我想知道 prepack 或任何优化器是否会有所帮助。
    猜你喜欢
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 2018-12-23
    • 2022-07-28
    • 2016-12-29
    • 1970-01-01
    • 2018-12-28
    • 2018-03-13
    相关资源
    最近更新 更多