如何使用Vue CLI3将代码分成几个捆绑

时间:2019-07-19 10:55:53

标签: javascript typescript vue.js webpack

我有一个使用TypeScript并由Vue-CLI3构建的Vue项目。

我要实现的目标是让Webpack为我的工作人员构建单独的捆绑软件。我已经在vue.config.js中阅读过Webpack Code SplittingconfigureWebpack的内容,但到目前为止,将它们组合在一起并没有运气。

项目设置是标准的vue create类型。我有一个./src/main.ts作为主要入口点,还有一堆TypeScript模块,我想作为带有各自的依赖树的单独捆绑包(如果无法避免,我可以进行代码重复)。

我想得到

./dist/js/all main stuff
./dist/js/workers/worker1.6e3ebec8.js
./dist/js/workers/worker2.712f2df5.js
./dist/js/workers/worker3.83041b4b.js

所以我可以在主代码中进行new Worker(worker1.6e3ebec8.js)

我可以通过生成javascript代码,将其放入blob并从中进行实例化来从主程序包中启动工作程序,但是看起来很尴尬。此外,我的工作程序代码会导入其他模块,因此无论如何似乎不是一个选择。

我对所有这一切都很陌生,所以也许我甚至没有朝着正确的方向前进。

在此堆栈上执行此操作的常规方法是什么?

4 个答案:

答案 0 :(得分:0)

您可以使用import(),它将返回一个Promise并将解析您的模块。 在使用Vue-CLI 3时,Webpack已准备就绪,它将自动拆分捆绑包。

const moduleName = 'coolModuleName'
import (
  /* webpackChunkName: "[moduleName]" */
  `@/my/module/path/${moduleName}.js`
).then(moduleCode => {
  // use your module
})


// load them in parallel
const getModuleDynamically(path, moduleName) => import(
  /* webpackChunkName: "[moduleName]" */
  `@/${path}/${moduleName}.js`
)

Promise.all([
  getModuleDynamically(path, moduleName1),
  getModuleDynamically(path, moduleName2),
  getModuleDynamically(path, moduleName3)
])

答案 1 :(得分:0)

最后我到了那里。正确设置所有红润的配置非常痛苦。

我仍然不太确定这是应该这样做的方式,因此,我欢迎更多评论和答案。我已经修改了Vue的默认设置,以便为诸如src/mainsrc/sharedsrc/workers之类的主要内容提供单独的代码区域。

重点是,由于全局命名空间中的类型不同(但有重叠),因此您必须分别编译工作程序和主程序,并且您需要具有不同的标头集lib的{​​{1}}的{​​{1}}中。但是,您显然希望将整个事情用一个简单的compilerOptions进行编译,并让VSCode识别您在这里所做的事情。因此,您需要为工作人员分别调用webpack和一组单独的配置文件。

文件夹结构如下(省略无关的内容):

tsconfig

yarn buildsrc/ src/main/ src/main/tsconfig.json -- extends ../../tsconfig.base.json src/shared/ src/workers/ src/workers/tsconfig.json -- extends ../../tsconfig.base.json package.json -- contains another call to webpack before build or serve tsconfig.base.json -- specifically renamed vue.config.js -- modified with both configureWebpack and chainWebpack webpack.config.workers.js -- this one deals with the workers part 都包含src/workers/tsconfig,因此名称为src/main/tsconfig

最令人沮丧的是,webpack和VSCode都尊重类型和引用。而且Vue部分似乎不尊重"../shared/**/*.ts"中的shared快捷方式。

请记住,path并不尊重您在TypeScript配置中拥有的tsconfig.base.json快捷方式。就像.vue

答案 2 :(得分:0)

到达那里! @aquilesb的答案确实有帮助,尽管经过大量实验,我仍然无法从答案中获得getModuleDynamically()

更新:看起来像这种解决方案,我无法使用npm模块的导入。我已经尝试过使用worker-loader进行实验,但到目前为止还没有取得任何进展。

以下是一些要点:

  1. 为包装工人创建一个单独的webpack配置。 target: 'webworker' 必须在那里。用webpack --config ./webpack.config.workers.js来称呼它,因为Vue对此一无所知。
  2. 为工作人员TypeScript创建单独的tsconfig.json。工人的lib设置必须在其中:"lib": ["esnext","webworker","scripthost"]以及正确的include:[...] / exclude:[...]设置。
  3. 可能需要告诉Vue使用自己的主tsconfig.json"lib":["esnext","dom","dom.iterable","scripthost"] / include的主exclude。这是在vue.config.js中完成的,您可能需要创建它。我使用Vue config的chainWebpack配置选项。
  4. 让Webpack通过使用import()(即不是变量)名称调用static来动态加载。我还没有在配置文件中找到这样做的方法,但这没关系:您无法在某个地方对名称进行硬编码,Webpack怎么会知道它必须捆绑和拆分代码?
  5. 以某种方式获得所生成文件的名称,因为在运行时必须至少拥有其中一个文件才能执行new Worker(filename)。为此,我使用了Webpack CLI的--json选项。

可以通过多种方式实现所有这些目标。这就是我的项目中最终的样子:

  • 文件夹结构:

    webpack.config.workers.js
    vue.config.js
    tsconfig.base.json
    
    src/main/
    src/main/tsconfig.json -- extends tsconfig.base.json
    
    src/shared/ -- this code may be duplicated by the Vue app bundles and by workers bundle
    
    src/workers/
    src/workers/tsconfig.json -- extends tsconfig.base.json
    
  • webpack.config.workers.js:包含一个条目-主工作程序文件,用于加载其他内容。

    entry: {
        worker: './src/workers/worker.ts'
    } 
    
  • build.workers.sh:该脚本调用Webpack CLI并生成带有产生的工作人员名称的JSON文件(省略了对文件夹的琐碎操作)。我唯一需要的一个叫做“工人”。其余的将由它动态加载。

    #!/bin/bash
    
    # Map entry name -> bundle file name
    # "assetsByChunkName":{"entryN":"entryN.[hash].js", ...}
    json=$(webpack --config ./webpack.config.workers.js --json $@|tr -d "\n\r\t "|grep -Eo '"assetsByChunkName":.+?}')
    
    # Remove "assetsByChunkName"
    json=$(echo "${json:20}")
    
    echo $json
    echo $json > "$target/$folder/workers.json"
    
  • 在运行时加载workers.json。另一个选择是在编译时使用const VUE_APP_MAIN_WORKER = require("path to/workers.json").worker并使用此env常量为Vue config使用它。

  • 现在我们有了主工作程序文件的名称,可以执行new Worker("main worker file path we've got from webpack")

  • 主工作文件包含静态引用其他模块并动态加载它们的功能。这样,Webpack知道要捆绑什么以及如何拆分代码。

    enum WorkerName {
        sodium = "sodium",
        socket = "socket"
    }
    
    function importModule(name: WorkerName): Promise<any> {
        switch (name) {
            case WorkerName.sodium:
                return import(
                    /* webpackChunkName: "sodium" */
                    "workers/sodium"
                );
            case WorkerName.socket:
                return import(
                    /* webpackChunkName: "socket" */
                    "workers/socket"
                );
        }
    }
    
  • 使用postMessage / message event API告诉您的主要工作程序代码要加载什么。

    const messageHandler = (e: MessageEvent) => {
    
        // here goes app-specific implementation of events
        // that gets you the moduleName in the end
    
        importModule(moduleName).then((work) => {
            // do smth
        });
    };
    

答案 3 :(得分:0)

现在,给出正确答案。

要实现以下目标:

  • 使用网络工作者
  • 在Webworker代码中同时使用动态导入和普通导入
  • 网络工作者与主应用之间的共享代码

我必须在vue.config.js中为worker-loader添加一个单独的规则,还必须添加babel-loader。我花了一些时间来找到正确的解决方案,但最后还是放弃了上一个解决方案。对于主要人员和网络工作人员,我仍然分别使用tsconfig.js

我仍然不满意的是,那个vue-cli或fork-ts-checker插件似乎不知道我的worker类中特定于Webworker的类型(所以我不能使用{例如{1}}。