[英]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代码拆分和configureWebpack的
vue.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: 以下是一些要点:
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对此一无所知。 tsconfig.json
for workers TypeScript. tsconfig.json
。 The lib setting for workers must be there: "lib": ["esnext","webworker","scripthost"]
as well as the proper include:[...]
/ exclude:[...]
settings. "lib": ["esnext","webworker","scripthost"]
以及适当的include:[...]
/ exclude:[...]
设置。 tsconfig.json
that has it's own "lib":["esnext","dom","dom.iterable","scripthost"]
and include
/ exclude
. 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. chainWebpack
配置选项。 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? 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: 要实现以下目的:
I had to add a separate rule for worker-loader in vue.config.js
and also to add babel-loader. 我必须在
vue.config.js
为worker-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.