Open pie6k opened 6 years ago
If you set up a git repo with an express server and some basic code, using your front end of choice, I'll look into integrating parcel with it so that you can serve files.
It seems like we can expose an express middleware pretty easily.
Express middleware would be awesome. Right now my API service and UI can be separate, so I have a workaround setup for hacking on both simultaneously:
Server (./server/index.js
):
const express = require('express')
const app = express()
const { spawn } = require('child_process')
const PORT0 = process.env.PORT0
const PORT1 = process.env.PORT1
app.get('/ping', (req, res) => {
res.status(200).send('Ok')
})
app.listen(PORT0, () => {
console.log(`Service running on ${PORT0}`)
// Run Parcel if we're in dev mode...
if (process.env.NODE_DEV) {
const opts = {
env: process.env,
cwd: process.cwd(),
stdio: ['inherit', process.stdout, process.stdout]
}
// Run parcel
spawn('parcel', [ './src/index.html', '-p', PORT1 ], opts)
}
})
Then in my package.json
I have a script that starts everything with Nodemon on the server:
"scripts": {
"dev": "PORT0=8888 PORT1=8889 NODE_DEV=true nodemon ./server/index.js"
}
You have to add this to package.json
as well to prevent a loop when parcel
builds:
"nodemonConfig": {
"ignore": ["src/*", "dist/*", ".cache/*"]
}
Kinda hacky but it at least allows me to spin-up a single command to work between my REST API and UI.
Parcel actually already has an express middleware. It's not well documented at the moment, but this is basically how it works:
const Bundler = require('parcel-bundler');
const express = require('express');
let bundler = new Bundler('path/to/index.html');
let app = express();
app.use(bundler.middleware());
app.listen(5000);
Do you have any documentation on this? I gave it a shot and am getting an error (on 1.3.1):
TypeError: Cannot read property 'type' of undefined
at sendIndex (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/parcel-bundler/src/Server.js:33:29)
at respond (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/parcel-bundler/src/Server.js:23:16)
at /home/fluidbyte/workspace/sandbox/react-parcel/node_modules/parcel-bundler/src/Server.js:15:7
at Layer.handle [as handle_request] (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/express/lib/router/index.js:317:13)
at /home/fluidbyte/workspace/sandbox/react-parcel/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/express/lib/router/index.js:335:12)
at next (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/express/lib/router/index.js:275:10)
at expressInit (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/express/lib/middleware/init.js:40:5)
at Layer.handle [as handle_request] (/home/fluidbyte/workspace/sandbox/react-parcel/node_modules/express/lib/router/layer.js:95:5)
My /server/index.js
:
const express = require('express')
const Bundler = require('parcel-bundler')
const path = require('path')
const bundler = new Bundler(path.resolve(__dirname, '../src/index.html'))
const app = express()
const PORT0 = process.env.PORT0
app.use(bundler.middleware())
app.get('/ping', (req, res) => {
res.status(200).send('Ok')
})
app.listen(PORT0, () => {
console.log(`Service running on ${PORT0}`)
})
@Fluidbyte I ran into the same issue. The middleware attempts to check the type
prop on bundler.mainAsset
, but bundler.mainAsset
will be undefined until the bundler bundles at least once. I worked around this problem by calling await bundler.bundle()
once on my sever:
if (Constants.ISLIVE) {
// Redirect http requests to https when live
app.use(httpsRedirect());
} else {
// Run Parcel bundler for client development
const bundler = new Bundler(path.resolve(__dirname, "../client/index.html"))
// Bugfix: parcel bundler must call bundle at least once using middleware
await bundler.bundle();
app.use(bundler.middleware());
}
Edit: filed a bug report #442
I'd like to re-open this issue for a few reasons:
bundler.mainAsset
is undefined until calling bundle.bundle()
). This is at odds with providing effective server-side support across language services.I've been studying IntelliJ's PSI architecture, and we could probably borrow ideas from their architecture. They've solved a lot of the same things we're running into: How can users extend the core behavior via plugins? What about services? When are things loaded, and in what order? How do I get notified when content changes? How do I create "virtual files" that aren't saved to disk? Etc.
Holy moly! I wanted to create server rendering topic but found it's already here. This is important topic, guys!
I really like how Parcel works for typical single page app. But looks like Parcel forces me to use *.html
file as an entrypoint. And then I wanna ask a question...
*.html
file?
*.js
file coz all babel things, imports, etc, all the configuration - everything breaks up*.html
file coz it should be generated by server - it's all the meaning of server rendering!Still, I love Parcel. Please, make some progress on this ;)
P.S. If you guys direct me, I could probably help
@JerryGreen Parcel can take a .js
file as an entrypoint. I'm exploring the same use case now. I'll post an update here if I get something nice working.
I found a relatively simple workaround for my setup that allows me to have hot reloading with parceljs and hot reloading of my express app. I have two repos that are separate, one for my Vue app (parcel runs here), and another for my express/node backend. I've symlinked the public
directory in my express app to the dist
directory that parcel outputs by default.
In the Vue/parcel directory, I run parcel watch --public-url "http://localhost:3000/" index.htm
and in my Express/node directory, I just run nodemon app.js
as usual. Everything seems to be working as you'd expect. Admittedly this is a simple setup for an app I'm just starting with.
I'd like to clarify, that when creating this issue, I've meant hot reloading server code. Meaning - is parcel suitable for hot-reloading back-end service like api that doesn't have even single html or css file.
@devongovett example looks really promising, but it seems to be browser/frontend related. Would that work for node.js only? eg my api responses to http://localhost:3000/hello
with World
and being able to 'hot-reload' it when file is changed without restarting the server.
Hi everyone! I've just got parcel bundler working for my node.js project with hot reloading. Had to write a custom bundler for it: https://gist.github.com/mvlabat/265b3f5a89417d30d891642cf93ad642
It will work out of the box if you place this file next to your index.js
, you can also customize it any way you want, adding specific build options etc.
I run it with the following yarn scripts, so it gets really convenient to use:
"scripts": {
"serve": "node bundler.js run",
"build": "NODE_ENV=production node bundler.js"
}
I think maybe that's something that Parcel should do out of the box, when serving js file as node.js target. Or at least such way of using Parcel bundler should be documented.
Update. I've just realized the main topic is about HMR. This solution doesn't make use of Hot Module Replacement, but just restarts the application on every rebuild. So it may be suitable for small projects, but not for large applications with heavy bootstrapping process.
Are you able to use parcel in HapiJS? @devongovett
@rodoabad This seems to be unrelated to this thread. Anyways you can probably register the middleware of parcel to onRequest using this: https://hapijs.com/api#-serverextevents you'll have to write some code to make it compatible but shouldn't be too hard
this issue can be closed, imho. parcel ships a dev server, middleware, and a hmr api. it's all documented on https://parceljs.org
It's an old issue, there's no guarantee the bug is still there
Devs are not actively looking into the issues. There's 612 of them already. May probably close, idk
@JerryGreen we do actively look into and fix issues. Most issues are just vague, non reproducible, already fixed or will be fixed in Parcel 2.
Closing issues out of nowhere is kinda rude and pointless. Therefore we have so many. Sometimes we go through old issues and most of the time we can just close them...
Sent with GitHawk
@DeMoorJasper, yea, sorry, I may look rude by myself
Closing issues out of nowhere is kinda rude and pointless
I understand this. That's true
I've planned to start a little project in some near future (in a week or two, idk), very likely with server rendering. Will be able to check is this still relevant or not / to make some reproducible steps. Will be here in touch
@JerryGreen SSR is kind of impossible with Parcel 1, multiple issues have come up with the main one being that parcel's workers need the config and node.js config overwrites browser config and vice versa which causes incorrect builds. However most of these bugs could be hacked around either by applying hotfixes to Parcel 1 or by working around them in your project. I've tried it along with another guy and AirBnB also experimented with it a lil while back. Parcel 2 will resolve this and probably make making such tooling very easy as we're working together with other teams to create the most optimal API.
I would definitely love to experiment with Node.js HMR although I'm not sure how this would work. Examples would be very welcome so I can possibly build this for Parcel 2 :)
I think most SSR frameworks currently load in JS bundles dynamically on page request at least that's how I would do it.
@DeMoorJasper there should be a server running which is doing 2 things (in most cases frameworks do only one of these things):
Btw, can't wait Parcel 2, are there any estimates of when it comes?
@JerryGreen Alpha 1 is pretty close you can track progress here: https://github.com/parcel-bundler/parcel/milestones
Hi,
I cannot use console.log
in my middleware when I mount the bundler middleware e.g. I don't get "in middleware". Instead - I just see "Built in ..." of Parcel:
app.use((req, res, next) => {
console.log('in middleware...');
const ejs = readFileSync(ejsPath).toString();
const compiledTmpl = template(ejs);
const htmlStr = compiledTmpl({
initData: JSON.stringify({
a: 111,
b: 222
})
});
writeFileSync(indexHTMLPath, htmlStr)
next();
});
app.use(bundler.middleware());
Maybe setting the logLevel
option to a smaller level works: https://parceljs.org/api.html
@mischnic I haven't tried that but I doubt it'd work because the problem isn't logging - it does log - it's that the console is cleared right after. There doesn't seem to be a conditional around console.clear()
so I'm guessing it's not possible.
Thanks anyway.
To anyone following along who's impatient for v2, I've managed to solve this for v1. Here is a minimal example.
Looks like now if I use it with express I can't assign any other routes. So if I have something like this
app.use(bundler.middleware());
app.get('/hello', (req, res) => {
res.send('Hello world update was great\n');
});
/hello
will direct me to parcel index route
@eddyLazar I think you have to switch those around as parcel will handle every route and express will never go past the parcel catch-all middleware
app.get('/hello', (req, res) => {
res.send('Hello world update was great\n');
});
app.use(bundler.middleware());
Oh, thank you @DeMoorJasper My fault...
Does Parcel v2 support this feature too? I can't figure out how to use it.
I have a recommendation for you guys.
there should be a server running which is doing 2 things (in most cases frameworks do only one of these things):
- Takes a cache of a statically generated page on page request (some landings, .etc, pages which are always the same; unable to use such approach for dynamic data)
- Generates new html on page request (more universal approach, however, a bit slower than first approach, so no real need to use this approach for static pages)
It's a huge problem (the reason why this issue exists) but it's solved by NextJS:
https://nextjs.org/blog/next-9 (read: "Automatic Static Optimization")
So I recommend you guys (literally to everyone in the web field) to use NextJS and all their stack, whether it's frontend part of a web app, or both frontend and backend (backend API).
Their stack is using Webpack under the hood, however. But the good thing, - you don't have to mess with Webpack config. If you do need to change bundler's behaviour, - they have tons of plugins which are easy to install (you may also write one yourself, - which will be equally painful to setup of webpack but for most things the pain is already on other dev's shoulders already bundled in these plugins). GL!
I'm a big fan of NextJS but adopting an entire framework just for this feature seems overkill.
Parcel 2 supports a config for configuring proxies based on the create-react-app proxy support. https://github.com/parcel-bundler/parcel/pull/3281 so this should be even easier in Parcel.
Using plugins you would also be able to go even further and bundle node code alongside browser code and run the node code alongside browser code as Parcel supports multiple targets.
Sorry, I didn't read the whole thread carefully just to understand it, but what's the status of this? Did somebody take this into work already? Or ideas are not settled yet?
tl;dr I would like to help 👍
@faergeek I dont think anyone has taken this up yet.
It could be done fairly easily with a plugin.
On Parcel 2 this should probably be a reporter plugin similar to the hmr server one. We’re gonna work on better node support for parcel 2 so maybe this should be part of that? Maybe it should be opt-in?
Sent with GitHawk
@DeMoorJasper Yeah, I also think it should be opt-in. But may be it would not hurt to have some kind of officially supported simple plugin for that anyway? As a reference at least. And yes, I am talking about version 2. Didn't know it is even possible on version 1. Is it?)
We’re gonna work on better node support for parcel 2
It looks like two issues are being discussed on this thread:
Are there other issues being discussed? Which of these is being added to Parcel 2? Which has been solved (and how) at the moment?
@mikestopcontinues I only consider the original issue as tracked by this issue, which is automatically restarting a node script on changes. For other feature requests look at other issues or create another.
Which has not been implemented yet but could be implemented fairly easily with a reporter. The only concern I have is what to do with multiple targets in this case? Do we run all node.js targets or add a flag in targets config or ... ?
Personally, I'd really like to see a separate middleware instance for each endpoint, which would help the targets issue. This way, only the changed endpoint is swapped out. (Or endpoints, in the event of a shared lib change.) Perhaps the easy way to implement this is to create a separate parcel instance behind the scenes for each target in use.
The reason I think it should would on the endpoint level is that restarting a heavy express api becomes a major impediment to development. Also, it's easy enough for users to reload the whole server on change now. It's not my desired endgame, but I strung it together with very basic package.json scripts:
"api": "npm-run-all api:*",
"api:build": "parcel watch -t node -d .parcel/api --cache-dir .parcel/cache local/api.js",
"api:watch": "nodemon .parcel/api/api.js",
npm-run-all
I tried something similar but it doesn't really work for me.. I can see parcel doing it's job, but nodemon never actually spin up the server
Let's consider simple node.js api based on express that has one endpoint
/test
that would simply returnHello world
.Goal would be to change any file of server and have it
hot reloaded
without need of restarting the server.Is something like this possible/meant to be possible/planned with parcel?
For now - it's seems like front-end only packager.
There is something like
ts-node
orbabel-node
. Would be great to haveparcel-node
with first-class hot reloading support.