ci010 / electron-vue-next

A starter template for using vue-next with the electron.
https://ci010.github.io/electron-vue-next/
191 stars 27 forks source link

Rough cleaning #34

Closed cawa-93 closed 3 years ago

cawa-93 commented 3 years ago

This patch is not for merging, but only for discussion

I decided to do some research and find things that could be simplified.

I commented on almost the whole project and started with an empty rollup.config.js file. When I came across some problem, I restored some things that solved this problem.

So I came to the stage where all the basic functions at first glance work.

So far I have not encountered any serious problems in this configuration. But I don't know why most of the plugins provided are needed.

ci010 commented 3 years ago

TypeScript support. Used @rollup/plugin-typescript. I have not studied how well it works and what its shortcomings are. It may make sense to consider alternatives. For example, learn how Vite works with the vehicle and try to reproduce this behavior.

@rollup/plugin-typescript works fine. The current project use it only for typecheck and use esbuild to build the project.

Auto-updater supported. But without two-package-structure.

Actually, this is my first time use two-package-structure. I think it's not bad at the glance. User don't need to maintain it as we will generate the second package.json.

Alternatively, if we could solve the rollup bundle issue with circular dependencies, we don't need it. Webpack could solve it (webpack can bundle with circular dependencies), but I don't want to include two build eco-system in a single project.

Single tsconfig.json. I deleted all tsconfig.json files and left only root. It does not seem that this would lead to any problems.

I don't think we should have only one tsconfig. I think the ideal case is we have three tsconfig in three different environments, as different env has different scope of import.

e.g. shared should not be able to import main and renderer.

Currently, the root one is only for vetur. Vetur cannot load tsconfig in separated directory.

Single entrypoind in main. There are no more index.product.ts and index.dev.ts. There is single index.ts for any mode. Different behaviors for different environments can be implemented through a conditional expression like this or this

I feel mixed about this. As when we have two entries and all configs exposed to the workspace. There are no magic to end user. They can easily understand and modify it if they don't like it.

Once thing I can come up with is we can push back to the static and url injection to the compile time. I don't think runtime solution is better, as it give user more mind burden on phase of writing (window) controller code.

The main difference is how the environment starts. scripts are no longer used. The tools run directly. And the management of child processes is entrusted to a third-party library. It will also make it easier to embed anything into the workflow. for example, configure a rollup to compile preload.js in watch mode etc.

I agree with we should extract all the build logic in a clear way so they can be easily embed. But I don't really like the idea of writing a dedicate package for it. Again, user need to know the "magic", I don't want it to be harder to modify and test. (if original electron-vue wrap whole build script into seperate project, I think I will be harder to modify it and fit it in to my project)

I agree with the idea we should have a build process for preload.js. (Maybe its src should be a ts file)

cawa-93 commented 3 years ago

@rollup/plugin-typescript works fine. The current project use it only for typecheck and use esbuild to build the project. According to the ideology, type checking should be provided by a code editor or a separate team that is not part of the development process. Maybe it would be better to make type checking a separate process? Let's say npm run typecheck.

As such, it will simply implement separate workflows for the liner, type checks, tests, and so on. And run them independently in the cloud or during build.

Actually, this is my first time use two-package-structure. I think it's not bad at the glance. User don't need to maintain it as we will generate the second package.json.

Alternatively, if we could solve the rollup bundle issue with circular dependencies, we don't need it. Webpack could solve it (webpack can bundle with circular dependencies), but I don't want to include two build eco-system in a single project.

I created electronic applications back in the days when such an architecture was mandatory. This is a terrible pain. So when I hear the phrase "two-package-structure" I just panic :)

I did not deeply study what is packed in the asar. As I wrote, I started on the other side: I created an empty config and gradually supplemented it as needed. Auto-update was the first thing I added to main/index.js and I didn't encounter the problem that was described in #30 . Therefore, it is difficult for me to judge its origin and solutions.

Webpack could solve it (webpack can bundle with circular dependencies), but I don't want to include two build eco-system in a single project.

Rollup -- one love ❤️

I don't think we should have only one tsconfig. I think the ideal case is we have three tsconfig in three different environments, as different env has different scope of import.

e.g. shared should not be able to import main and renderer.

Currently, the root one is only for vetur. Vetur cannot load tsconfig in separated directory.

Maybe you're right. I thought the opposite: nested tsconfigs are needed for Vetur and root need for develop.

However then there are some problems which I felt as the user:

Maybe the shared doesn't need its own tsconfig at all? However, this is not an entry point, but only a set of files that are imported. I think, if you create several separate tsconfigs, then only for entry points such as the main, renderer, preload, worker, etc.

I feel mixed about this. As when we have two entries and all configs exposed to the workspace. There are no magic to end user. They can easily understand and modify it if they don't like it.

I do not agree. I, a stranger, had to try to understand how it works. Why there are several entry points, what, where and how it is imported ... It was very magical for me.

And this leads to things like the need to set global variables, and imports at the end of the file. Imports at the end of the file are especially confusing (I didn't see them right away, because I'm used to the fact that EU imports can only be on top). In addition, my editor transfers all imports up automatically during formatting, which leads to problems.

This approach has a right to life but in much more complex systems. In our case, you only need to expand the URL depending on the mode. Multiple entry points with a configuration of global variables is too much for such a simple task.

It looks simple, clear and familiar to everyone. In addition, the runtime code after compilation is simplified and the conditions are cut.

This

  mainWindow.loadURL(import.meta.env.PROD
    ? join(__dirname, './renderer/index.html')
    : 'http://localhost:3000/index.html'
  )

in prod mode will compiled to

mainWindow.loadURL( path.join(__dirname, './renderer/index.html') );

I agree with we should extract all the build logic in a clear way so they can be easily embed. But I don't really like the idea of writing a dedicate package for it. Again, user need to know the "magic", I don't want it to be harder to modify and test. (if original electron-vue wrap whole build script into seperate project, I think I will be harder to modify it and fit it in to my project)

In my opinion, there should have separate scripts to compile each entry point. And each script should work only with its own entry point and not communicate with others.

With this architecture, you can easily add other commands to build arbitrary entry points.

In my implementation it is build:main -- compile main entry point build:renderer -- compile renderer entry point

I could easily add another command to compile the webassembly, add a building of webworkers, or some static scripts, or something else.

All I have to do is run the processes I need for the specific task at hand. I can do this manually or with some layer - abstraction - of the running process manager.

Separately, for convenience (although I myself do not need it) a separate command is added to run several npm commands simultaneously. It is not mandatory and we are not attached to it. This licks the layer to manage running processes.

I agree with the idea we should have a build process for preload.js. (Maybe its src should be a ts file)

As for the preload entry point. I think this is a special case. In fact, the preload is part of the main process. We could add it to the existing rolup config as another input.

So we will not have a separate team to build a preload.

ci010 commented 3 years ago

@cawa-93 After I studied the rollup plugin API, most of features like, electron html url, are handled by rollup plugin. For example:

import createBaseWorker from './workers/index?worker' // this will be a Worker factorial function
import indexPreload from '/@preload/index' // preload index.ts file path
import indexHtmlUrl from '/@renderer/index.html' // renderer index.html file url
import logoPath from '/@static/logo.png' // static file path

and this finally overcome the issue you mentioned. I saw your template project with another approach, which uses vite for main process also. Perhaps this can help you (as vite is also backed by rollup).

cawa-93 commented 3 years ago

It seems very interesting. 🤔😉

cawa-93 commented 3 years ago

@ci010 I understand correctly that the plugin solves only resolving modules, but not their build?

ci010 commented 3 years ago

@ci010 I understand correctly that the plugin solves only resolving modules, but not their build?

In the example I mentioned,

import createBaseWorker from './workers/index?worker' // this will be a Worker factorial function
import indexPreload from '/@preload/index' // preload index.ts file path
import indexHtmlUrl from '/@renderer/index.html' // renderer index.html file url
import logoPath from '/@static/logo.png' // static file path

The worker handled by worker plugin will trigger rollup split file, which shared the same build config with main process.

The preload plugin is more interesting. Normally, the preload code should be handled by a separated rollup build as it has different tsconfig (different typescript compile config), but here I have a tricky setup. Since the actual js code is emitted by esbuild, and typecheck is performed by my typescript plugin, I can build them in the same rollup build.

In my typescript plugin, I put both preload and main tsconfig inside, so it can typecheck both projects correctly without use two rollup build.

For the html url, it's just a url mapping, as renderer build is handled by vite. The html will build whatever I import it in main or not.

For the static resource, I emit it as rollup assets so it will bundle in dist dir with correct path.

So to answer your question, import worker file will cause the worker file to build, and the preload is the same. No import, no build for them. So I should say preload and worker build are handled by plugins.

Overall, the whole build process is still two rollup working. One is my customized rollup build for main with preload. Another is the vite building the renderer html.