简体   繁体   English

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

[英]How to split code into several bundles with Vue CLI3

I have a Vue project using TypeScript and built by Vue-CLI3. 我有一个使用TypeScript并由Vue-CLI3构建的Vue项目。

What I'm trying to achieve is to get Webpack to build separate bundles for my workers. 我想要实现的目标是让Webpack为我的工作人员构建单独的捆绑软件。 I've read about Webpack Code Splitting and about configureWebpack in vue.config.js , but so far had no luck in putting them together. 我已经在vue.config.js中阅读了有关Webpack代码拆分configureWebpackvue.config.js ,但到目前为止,将它们组合在一起并没有运气。

The project setup is the standard vue create type. 项目设置是标准的vue create类型。 I have a ./src/main.ts as the main entry point and a bunch of TypeScript modules, I want as separate bundles with their own dependency trees (I'm fine with code duplication if it can't be avoided). 我有一个./src/main.ts作为主要入口点,还有一堆TypeScript模块,我想作为具有各自依赖树的单独捆绑包(如果无法避免,我可以进行代码复制)。

I'd like to get 我想得到

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

So I could do new Worker(worker1.6e3ebec8.js) in the main code. 因此,我可以在主代码中new Worker(worker1.6e3ebec8.js)

I could launch workers from the main package by generating javascript code, putting it into a blob and instantiating from that, but it looks rather awkward. 我可以通过生成javascript代码,将其放入blob并从中进行实例化来从主程序包中启动工作程序,但是它看起来很尴尬。 Besides, my worker code import other modules, so it doesn't seem to be an option anyway. 此外,我的工作程序代码导入了其他模块,因此无论如何似乎都不是一个选择。

I'm quite new to all of this, so maybe I'm not even heading in the right direction. 我对所有这些都还很陌生,所以也许我什至没有朝着正确的方向前进。

What is the usual way of doing that on this stack? 在此堆栈上执行此操作的通常方法是什么?

You can use import() , it will return a Promise and will resolve your module. 您可以使用import() ,它将返回一个Promise并将解析您的模块。 As you are using Vue-CLI 3, webpack is ready and it should split your bundle automatically. 在使用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) ]) 

Got there! 到了那里! @aquilesb's answer did help, although I've failed to get getModuleDynamically() from the answer working after plenty of experimenting. @aquilesb的答案确实有所帮助,尽管经过大量实验后我未能从答案中获得getModuleDynamically()

Update: Looks like with this solution I'm not able to use imports of npm modules. 更新:看起来与此解决方案,我无法使用npm模块的导入。 I've tried experimenting with worker-loader but haven't got anywhere so far. 我已经尝试过使用工人装载机进行试验,但到目前为止还没有任何进展。

Here are a few takeaways: 以下是一些要点:

  1. Create a separate webpack config for packing workers. 为打包人员创建一个单独的webpack配置。 The target: 'webworker' must be there. target: 'webworker' 必须存在。 Call it with webpack --config ./webpack.config.workers.js , as Vue wouldn't know about that. webpack --config ./webpack.config.workers.js调用它,因为Vue对此一无所知。
  2. Create a separate tsconfig.json for workers TypeScript. 为工人TypeScript创建一个单独的tsconfig.json The lib setting for workers must be there: "lib": ["esnext","webworker","scripthost"] as well as the proper include:[...] / exclude:[...] settings. 工作者的lib设置必须存在: "lib": ["esnext","webworker","scripthost"]以及适当的include:[...] / exclude:[...]设置。
  3. You may need to tell Vue to use the main tsconfig.json that has it's own "lib":["esnext","dom","dom.iterable","scripthost"] and include / exclude . 可能需要告诉Vue公司使用的主要tsconfig.json有它自己的"lib":["esnext","dom","dom.iterable","scripthost"]include / exclude This is done in vue.config.js , you will probably need to create it. 这是在vue.config.js完成的,您可能需要创建它。 I use chainWebpack configuration option of Vue config. 我使用Vue配置的chainWebpack配置选项。
  4. Let Webpack know you have dynamic loading by making calls to import() with static (ie not variable) names. 通过使用static (即非可变)名称调用import() ,使Webpack知道您具有动态加载。 I haven't found a way to do so in config file, but it doesn't matter: you can't help hardcoding the names somewhere, how else Webpack would know it has to bundle and split the code? 我还没有在配置文件中找到这样做的方法,但这没关系:您无法在某个地方对名称进行硬编码,Webpack怎么会知道它必须捆绑和拆分代码?
  5. Somehow get the name(s) of generated files, as you must have at least one of them at runtime to do new Worker(filename) . 以某种方式获取生成文件的名称,因为在运行时必须至少拥有其中一个才能执行new Worker(filename) I used the --json option of Webpack CLI for that. --json使用了--json CLI的--json选项。

There are many ways all of this can be achieved. 所有这些都可以通过多种方式实现。 This is what this ended up looking like in my project: 这就是我的项目最终的样子:

  • Folder structure: 资料夹结构:

     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 : contains a single entry – the main worker file, that loads the other stuff. webpack.config.workers.js :包含一个条目–主工作程序文件,该文件加载其他内容。

     entry: { worker: './src/workers/worker.ts' } 
  • build.workers.sh : the script calls Webpack CLI and produces a JSON file with the resulting workers names (trivial actions on folders are omitted). build.workers.sh :该脚本调用Webpack CLI并生成带有产生的工作人员名称的JSON文件(省略了对文件夹的琐碎操作)。 The only one I need is called "worker". 我唯一需要的一个叫做“工人”。 The rest is to be dynamically loaded by it. 其余的将由它动态加载。

     #!/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" 
  • Load workers.json at runtime. 在运行时加载workers.json The other option would be to use it at compile time by providing Vue config with const VUE_APP_MAIN_WORKER = require("path to/workers.json").worker and using this env constant. 另一个选择是在编译时使用const VUE_APP_MAIN_WORKER = require("path to/workers.json").worker并使用此env常量在Vue配置中使用它。

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

  • The main worker file contains the function that statically references other modules and dynamically loads them. 主工作文件包含静态引用其他模块并动态加载它们的功能。 This way Webpack knows what to bundle and how to split the code. 这样,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" ); } } 
  • Use the postMessage / message event API to tell your main worker code what to load. 使用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 }); }; 

Now, to the correct answer. 现在,正确的答案。

To achieve the following: 要实现以下目的:

  • Using webworkers 使用网络工作者
  • Using both dynamic imports and normal imports in webworker code 在Webworker代码中同时使用动态导入和普通导入
  • Sharing code between webworkers and main app 在网络工作者和主应用之间共享代码

I had to add a separate rule for worker-loader in vue.config.js and also to add babel-loader. 我必须在vue.config.jsworker-loader添加一个单独的规则,还必须添加babel-loader。 It took me some time to find the correct solution, but I dropped the previous one (in my other answer) in the end. 我花了一些时间来找到正确的解决方案,但最后还是放弃了上一个解决方案。 I still use separate tsconfig.js for main and for webworkers. 我仍然可以使用单独的tsconfig.js主和webworkers。

What I'm still not happy with, is that vue-cli–or rather fork-ts-checker plugin–doesn't seem to know the webworker-specific types in my worker classes (so I can't use DedicatedWorkerScope , for instance). 我仍然不满意的是,vue-cli或fork-ts-checker插件似乎不了解我的工作人员类中特定于Webworker的类型(例如,我不能使用DedicatedWorkerScope )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM