How to cascade Vite configuration files in a monorepo? - vite

I'm undergoing a to-monorepo-conversion. It will include multiple servers (node/express microservices) and multiple frontend applications (react) and a large number of library modules. I want them as orthogonal as possible, such as all frontends and related libraries use the same dependencies and tooling.
I started to use pnpm w. workspaces, typescript, vite.
I cascaded the tsconfig.json files as shown below:
/monorepo-root
package.json
tsconfig.base.json
/server # node/express
tsconfig.server.json
/lib # libraries for server code
tsconfig.lib.json
/validation
tsconfig.lib.json
/...
/gateway
tsconfig.json
/ms-xxx # microservices
tsconfig.json
/ms-yyy
tsconfig.json
/...
/web # react apps
tsconfig.web.json
/lib # libraries for frontend code
tsconfig.lib.json
/corelib
tsconfig.json
/uilib
tsconfig.json
/...
/webapp-1
tsconfig.json
/webapp-2
tsconfig.json
/...
My question is about the Vite configuration files. Is it possible/meaningful to cascade Vite related configurations similarly?
"pnpm create vite" commands create a lot of unnecessary files and I have to edit each of them (think of tens of library modules).
I currently created tsconfig.web.vite.json and tsconfig.lib.vite.json files under /web and pointed to them from tsconfig.json files from webapps/modules (using references": [{ "path": "../tsconfig.web.vite.json" }]). This seems to work, but the problem is with defineConfig.server.port or similar settings where I have to define different port for each webapp. Perhaps I might use .env for these, but I'm not convinced yet if I'm on the right track.
For tsconfig files it just overrides the upper-level setting, but how can I deal with sub seetings under export default defineConfig({...})?
Any insight on a correct setup is much appreciated.

Related

Azure App Service (Windows) - Nodejs ES Module Problems with SvelteKit app

really hoping someone can point me in the right direction with this one as i'm having no luck at all. I'm trying to host a simple nodejs sveltekit application on a Windows based azure app service, but cannot get the application to start / run.
I'm using the adapter-node adapter for sveltekit to generate the build output as a self contained node app. After sveltekit generates the build output I inject a simple package.json file to the root of the build folder to instruct node to use the ESM style imports which simply contains a single property of type="module".
package.json
{
"type": "module"
}
Lastly I also inject a web.config into the root of the build folder for use with IISNode. The web.config file used is the same as from the nodejs quickstart guide provided by MS. The web.config can be seen here.
The final folder structure of the build output is simply:
build
└───assets
│ └───_app
│ │ ...
└───prerendered
│ index.js
│ package.json
│ web.config
Locally I can take this build folder, place it anywhere on my machine and it runs perfectly by simply running:
node index.js
The Problem
Even though it works perfectly locally, when I deploy the application to the Azure app service the application will not start with the browser simply displaying "This page isn’t working right now".
When I check the logs I see the following error:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: D:\home\site\wwwroot\index.js
require() of ES modules is not supported.
require() of D:\home\site\wwwroot\index.js from D:\Program Files (x86)\iisnode\interceptor.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from D:\home\site\wwwroot\package.json.
The error tells me that MS's iisnode\interceptor.js is using the commonjs style require syntax and cannot import the ES module of my index.js.
I found someone having a similar problem and a suggested solution here. The suggested solution is to create a new file next to my index.js file and configuring it as the app service's (or more specifically iisnode's) entry point in the web.config. The new file would be named run.cjs and only contain the following:
import("./index.js");
I tried this option, adding the new run.cjs file and updating the web.config to set this as IISNodes entry point:
<add name="iisnode" path="run.cjs" verb="*" modules="iisnode"/>
When I try the site after doing this I get a new problem. The site now loads but instead of seeing the app, the js from index.js renders as raw text into the browser.
The azure app service WEBSITE_NODE_DEFAULT_VERSION is set to ~14 and I can see from Kudu that the version running is 14.16.0 - my local machine is 14.17.0 so the node version looks to be ok.
Can anyone help??
Thanks in advance
Please re-install/update the npm module on your project.
Make sure all these files are present in your project.
Do not import your index.js file in other files like run.cjs or run.mjs, after building your application in your local and publish it in azure app service.
{
"type": "module"
}
This above code is required in the package.json file.
Check your npm reference files, if anyone of them is not installed properly, then you'll get the raw data which is present in app,js file, as output

How to organise file structure of backend and frontend in MERN

I have backend based on express + mongoose. File structure is:
- /models
-- item.js
- /node.modules
-- ...
- server.js
- package-lock.json
- package.json
And regular create-react-app based folder for front-end:
- /src
-- /assets
--- index.css
-- /components
--- Somecomponent.js
-- /containers
--- App.js
-- /reducers
--- somereducers.js
- /node.modules
-- ...
-- index.js
-- registerServiceWorker.js
- .gitignore
- package-lock.json
- package.json
I want to use it in proper way together. I wanted to organise it this way:
- /client
-- /src
...
-- index.js
-- registerServiceWorker.js
- .gitignore
- package-lock.json
- package.json
- /server
- /models
-- item.js
- /node.modules
-- ...
- server.js
- package-lock.json
- package.json
At this stage I stuck. I can make it if client folder inside server folder or if server folder inside client.
1. But how to make it run when two folders are siblings?
2. What should be package.json and where node.modules should be (whether both server and client should have it's own package.json and modules?)
The most basic structure would be to have a root folder that contains frontend and backend folders. Since you're talking about the MERN stack, you would have a package.json inside of your NodeJS backend environment and a package.json for your React side of things. Backend server and the frontend client are two totally separate things, so yes, they both have their own node_modules folders. On the backend, you'll probably have installed something like Express for your Node runtime, Mongoose for a more convenient way to talk to your MongoDB, etc, and on your frontend, you'll have your React as your frontend framework, Redux for state management, etc. Additionally, depending on what you have already listed inside of your package.json files, when you run npm install separately it will be installed in those two folders. If you want to install additional packages, just run npm install + "the name of the package" (without the '+' and without the quotes) inside of that particular folder where you need it (backend or/ and frontend).
I hope this was helpful. Check out the pics, especially the 2nd one.
App structure
Folder structure
UPDATE:
In development, I suggest installing two additional things:
npm i -D nodemon
npm i -D concurrently
Note: The -D flag will install them as devDependencies.
nodemon is going to track every file change and restart the backend server for you. So, it's obvious that it should be installed inside of the "backend" folder. All you have to do is go inside of the package.json file (backend) and add a new script. Something like this:
"scripts": {
"start": "node app.js", // in production
"dev": "nodemon app.js", // in development
}
concurrently allows you to start both your frontend and backend at the same time. I suggest initializing a new Node project inside of the top-level root folder -[folder which contains both, your frontend and backend]. You would do that with the npm init command, and after that, install the concurrently package there.
Now, go open your newly created package.json file inside of your root folder and edit the start section, like this:
"scripts": {
"dev": "concurrently \"cd backend && npm run dev\" \"cd frontend && npm start\" "
}
What this will do is go inside of the backend folder and run the dev command (the same one we just configured), so that will start nodemon. Additionally, it will also go inside of the frontend folder and run the default start command -which is exactly what we want.
If you kept the folder structure, installed all the dependencies (including the additional two I mentioned above), changed the package.json file inside of your root folder, you'll be able to start them both with a simple command:
npm run dev // make sure you're inside of the root folder when doing so :)
Adding to the accepted answer, the folder structure division inside the frontend and backend is more useful if it is based on business logic rather than tech logic.
Dividing the whole stack into self-contained components that preferably don't share files among them is the best way to make your app more testable and easy to update. This in the smallest possible way is what commonly known as microservice architecture.
Bad Design : difficult to update and test:
Good Design : easy to update and test:
Use Structure as per your requirement, like based on the project scope or depth. But make sure to keep the endpoints and models separate, so initially have a setup like such
src/
controllers - for the endpoints
models - for the schema
server.js - or index.js

Vue.js Webpack Template in a Docker Container: How do I add Webpack-Dev-Server --watch-poll flag?

I am running the webpack / webpack-dev-server portion of the base Vue.js Webpack template (https://github.com/vuejs-templates/webpack/) inside of a docker container I created. The container also contains the vue CLI in order to create new projects (you can get my container here if you want: https://hub.docker.com/r/ncevl/webpack-vue/).
Hot-reload does not work after moving from the webpack-simple template to this one.
Everything was working using the Webpack-Simple template which you can clone / see over here: https://github.com/vuejs-templates/webpack-simple
I was able to get the simple template running (with hot-reload working as intended) with the following webpack-development-server launch command:
webpack-dev-server --hot --inline --progress --host 0.0.0.0 --watch-poll
That said the full (not simple) version of the webpack template does not appear to use a webpack-dev-server launch command and instead appears to use additional middleware as referenced in build/dev-server.js (https://github.com/vuejs-templates/webpack/blob/master/template/build/dev-server.js) and the webpack dev config.
Since the --watch-poll was the key to getting the WDS hot-reload functionality to work within a docker container in the last project, my thinking is that I need to do something similar with the webpack-hot-middleware but I dont see anything in their docs (over here: https://github.com/glenjamin/webpack-hot-middleware) that talks about changing to a polling based approach.
I am not 100% sure the polling flag will do the trick since I can see the container recompile my source when I make a change. I can also see the change in my browser if I refresh it manually.
Whats stranger still is if I inspect my page in browser within chrome dev tools, and then head over to network / XHR I can see that the browser actually does receive information from the webpack-dev-server, but visually it does not update.
Give the above I assume websockets (or socket.io which I think is used) are working and communicating between the browser and the WDS so maybe this is a browser caching issue of some sort?
I checked in my console and found this so it is looking like a header issue:
For reference the text error from that image (to make it easier for anyone having the same issue to find this post) is:
EventSource cannot load http://__webpack_hmr/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://0.0.0.0:8080' is therefore not allowed access.
Again the Hot-Reload / Hot Module Reload was working with this identical container setup when using the webpack-simple Vue.js template.
I am wondering if anyone has run into anything similar or has any ideas on how to add the polling option . I guess my alternative would be roll back to a more basic webpack config and rebuild that portion of things to use the traditional webpack-dev-server / webpack config but give the above I am not sure that is going to fix it.
I am adding this as a separate answer since it more specifically answers the question in the title, while my other answer more specifically explains what solved my actual problem.
The vue.js webpack template project (which can either be init'd from the Vue CLI or pulled from its repo over here: https://github.com/vuejs-templates/webpack) separates its config files into several different directories.
I am posting this answer so that anyone who runs into the need to add polling to their project will be able to understand how / where to do that.
The base project structure for a Vue.js webpack template project looks like this:
The files that you care about if you are messing with trying to get hot module reload working are related to creating your server primarily with webpack-dev-middleware. The most important files related to that are highlighted here:
Basically if you want to add the polling code to the webpack-dev-middleware server you need to be in the /build/dev-server.js file on lines 20 to 24 that look like this:
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: true
})
To add polling you would add it just before or after quiet: true. As a side note, if you are having trouble with HMR I would change "quiet:true" to queit false to get a more verbose read out of whats going on from webpack-dev-middleware. I have included verbose and polling modifications to the above code here:
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: false, //Changed to for additional verbosity
watchOptions: { //Add Polling
aggregateTimeout: 300,
poll: 1000
}
})
My other answer is in regards to what ended up solving my problem, not necessarily how to actually add polling (which might be necessary for someone else but did not end up being needed to make my dockerized setup work).
It should also be noted that sometimes when HMR (webpack hot module reload) is not detecting changes it is due to the fact that webpack-hot-middleware or webpack-dev-middleware is running into an issue whereby some invisible characters are / were added to the name of the base project directory (probably by someone building the base Vue project) and therefore webpack on certain OSes is not able to see the changes.
If that happens to you and you are on OSx or running webpack inside of a docker container and you can't get HMR to detect changes, try to rename your vue-webpack project directory and it should work.
Ok. So I can't really take credit for this one since it was actually answered by Discuss user Cristian Pallarés over here: http://webpack.github.io/docs/webpack-dev-server.html#combining-with-an-existing-server
Christian says:
I was just trying the same. I just use "php artisan serve" on localhost:8000, and Webpack Dev Server on localhost:3000. You should make this:
set your webpack config "output.publicPath" as "http://localhost:3000/static/" instead of "/static/"
make your php application load this:
The key is the output.publicPath being absolute. Now, you should run "php artisan serve" and launch your webpack dev server too (in my case I use gulp).
Basically I took that and dug through the Vue.js Webpack Template files to locate the config file where webpack was looking for the public path. the public path setting ended up being in the index.js file located in the /config directory of the template.
I changed my code to look like this:
assetsSubDirectory: 'http://localhost:8080/static/', //!!Changed from /static/
assetsPublicPath: 'http://localhost:8080/', //!!Changed from /
As opposed to the previous setting which DID NOT WORK and looked like this:
assetsSubDirectory: '/static/',
assetsPublicPath: '/',
After that I was able to see my changes hot reload while running the vue.js Webpack template from within my docker container.

Nodejs Micro service architecture share models in a common project

I have somewhat large node application and planing to change it to Micro Service Architecture as follows.
Service1
--controllers
--services
--package.json
Service2
--controllers
--services
--package.json
CommonService
--models
--helpers
Can I have all models and other common helpers in separate project and refer them rather than keeping them in all projects.
So to be clear. You can do this two ways.
First you can create in git micro service with all helpers/services that you need. Then just add it in package.json like this
"yourModuleName": "git+ssh://git#github.com:yourName/yourModuleName#Branch",
Second way looks similar. You can create npm module(https://www.npmjs.com) add in in package.json like this
"yourModuleName": "yourModuleNameFromNPM",
Then in your main core module just do
const yourModuleName = require('yourModuleName');
Dont forget to run npm install
And you're done.
Hope this helps.

is it possible to have multiple modules defined in tsconfig?

Ok, so I'm making a angular2 app with a node server. I've followed the 5min tutorial so I'm using "system" as the module system. However I am using a simple node express server instead of the way they have in the tutorial. I am writing this in typescript as well, but it is also compiled to "system" style of importing modules. And when running the server I get System is not defined.
How do I fix so System is defined when starting the server?
Is it not recommended to use "system" as the compiler option "module" in the tsconfig-file, when writing a node server?
Can I compile the server code with eg "commonjs" and the angular front end with "system"?
How do I do the configuration of module loading (the small script they have in the index.html) if I would not use "system" in the front end either?
I would recommend to split front-end and back-end applications into different projects and make them communicate through a REST service. I mean the server application will provide the service and the front application will consume it using AJAX.
This way you will be sure that there won't be conflict between the tools you use. For example the use or not of SystemJS. You'll be free to use SystemJS in the Angular2 application as described in the 5min tutorial of the angular.io website and commonjs for the Node / Express application.
The following article describes how to do that:
Angular2 TypeScript Gulp and ExpressJS - http://blog.edenmsg.com/angular2-typescript-gulp-and-expressjs/
As #Thierry Templier suggested, you need to split your code into /client and /server to be more maintainable and structured, if you didn't do that yet.
You can create two tsconfig.json files, put one into /server and other into /client folder.
/server
tsconfig.json ( with module: commonjs )
/client
tsconfig.json ( with module: systemjs )
When you are invoking tsc from shell, you use --project command:
tsc -p ./server <-- /server/tsconfig.json is loaded
tsc -p ./client <-- /client/tsconfig.json is loaded

Resources