parcel: Parcel 2 doesn't detect changes in linked dependencies.
đ bug report
When working on a dependency locally by linking it, Parcel 2 doesnât detect changes and therefore doesnât rebuild. You also need to remove the cache manually in order for it to work on re-runs.
đ Configuration (.babelrc, package.json, cli command)
Package.json
{
"name": "parcel-tamplate",
"version": "1.1.0",
"description": "My personal Parcel Template",
"main": "public/index.html",
"source": "src/index.html",
"author": "Samuel Elgozi <samu.elgozi@gmail.com>",
"license": "none",
"private": true,
"scripts": {
"dev": "parcel src/index.html",
"build": "parcel build src/index.html"
},
"targets": {
"main": {
"includeNodeModules": true
}
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"babel-eslint": "^10.0.2",
"eslint": "^6.0.1",
"less": "^3.9.0",
"parcel": "^2.0.0-alpha.3.2"
},
"dependencies": {
"firebase-auth-lite": "^0.4.1"
}
}
The commands I use:
parcel src/index.html
đ¤ Expected Behavior
Like in version 1, Parcel should detect changes in linked dependencies, invalidate the cache and rebuild.
đŻ Current Behavior
No changes are made, which require manual removal of .parcel-cache
and then building again.
đŚ Context
I use Parcel to work on npm modules often. Without detecting the changes in linked packages there is no reason for me to use parcel. In fact, it becomes painful to do soâŚ
đ Your Environment
Software | Version(s) |
---|---|
Parcel | 2.0.0-alpha.3.2 |
Node | v13.10.1 |
Yarn | 1.22.1 |
Operating System | MacOs Catalina 10.15.3 |
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 42
- Comments: 78 (21 by maintainers)
Commits related to this issue
- Minimal code to reproduce issue https://github.com/parcel-bundler/parcel/issues/4332 — committed to am-creations/parcel-issue-4332-symlink-watch by PhenX 2 years ago
This issue keeps me from migrating to v2, too. I wonder how other developers handle this workspaces issue - also considering monorepos are now en vogue. We canât possibly be alone here @ramirofages
@samuelgozi thanks for creating the repo, I can reproduce it pretty consistently, will try and figure out why it happens and hopefully fix it
This does not seem like a difficult feature to implement, and I think it would help a good number of folks. If those in charge of this project are up for such a change, Iâd be happy to try my hand at a PR for this.
My suggested approach is to simply add a CLI flag to explicitly specify other paths to watch outside the project root. If the user does not explicitly specify any folders, the default behavior is the current one: only files within the project root are watched for changes. While not ideal for all use cases, I think this approach provides the most flexibility without changing existing behavior.
Thoughts?
This is really bad⌠Parcel 1 used to work with symlinked packages as already mentioned in this thread. Not being able to symlink packages basically means one needs to restart the bundler every single time a change is made to external package.
Imagine working on an app that has a thin shell and a number of libraries that deliver parts of the app in the form of components. Unless you go monorepo it is just not possible to do it with Parcel right now.
Thatâs really a shame. I wanted to base my next set of projects on Parcel 2, after waiting for so long for it to go GA and now it turns out it has this limitation đŚ
Any idea about other bundlers that donât have that limitation?
This was actually working in parcel 1. Currently I had to revert back to parcel 1 while keeping its dependencies in parcel 2 to correctly build as module.
FYI, thanks for @jondlm, there is a new
--watch-root
CLI option to configure the root directory where the watcher listens which will be available in the next release. See #9424 for details.This issue is a true blocker, and I tend to regret having upgraded from parcel 1 because of this đŚ This is a PITA when working with workspaces now. Having builds that take 3 seconds instead of 4 is cool, but not when you need to stop, delete cache and rebuild.
Iâm really hoping this issue (in the short term roadmap) is addressed quickly.
Also, thank you for this great bundler !
A very hacky workaround I found:
--no-cache
, andpackage.json
to trigger a rebuildBut I definitely agree that this should just work, Create React App does pick up changes in packages that are added with
npm link ../../another-project
so that could be inspiration?This is because the file watcher only watches for changes in the project root. It would be somewhat hard to implement support for symlinks outside the project I think. If we implemented this in the watcher weâd need to somehow crawl the whole file system to detect symlinks in the first place which would be very slow. We could potentially do it by detecting files that resolve to symlinks as we build the asset graph and keep nodes in the request graph to track watch roots. Then weâd have to re-watch all of those on startup and invalidate each of them for changes as opposed to just the project root.
(https://github.com/parcel-bundler/watcher/pull/32)
This issue is easy to fix if the path to watch is configurable. Basically, borg this line:
https://github.com/parcel-bundler/parcel/blob/de1569572ab681bb6e90d2b330d002b5df7947ea/packages/core/core/src/Parcel.js#L376
And assimilate it to accept another option from the initial option, which it parsed inside the resolve option:
https://github.com/parcel-bundler/parcel/blob/de1569572ab681bb6e90d2b330d002b5df7947ea/packages/core/core/src/resolveOptions.js#L33
In particularly, this line: https://github.com/parcel-bundler/parcel/blob/de1569572ab681bb6e90d2b330d002b5df7947ea/packages/core/core/src/resolveOptions.js#L68
can be made to handle another optional input from the initialOption that would override the âproject rootâ. Better yet, I think we should just separate the darn watcherâs root from the projectRoot altogether - as in letting user specify a âwatchRootâ and just use that in the parcel watcher instead.
@devongovett - Agreed. Portability across machines could be compromised a bit if one could specify arbitrary folders to watch. Although playing devilâs advocate, this at least allows users to do it. I can foresee a situation where users want to watch changes for a dependency that is
npm link
-ed into a project root. Many âhacksâ like these are temporary while dependencies are still under heavy development.Hereâs the most common use case, IMHO. Imagine, for example, a Git repository with
backend
,frontend
, andcommon
folders. The Parcel root project folder might befrontend
(i.e. wherepackage.json
is located), but there might be isomorphic code shared between thebackend
andfrontend
inside of thecommon
folder. In this case, it would be nice if Parcel could listen for changes in thecommon
folder, even though this is a sibling folder outside of the project root.I agree it would be great to have this fixed. My scenario seems even simpler:
some_root_dir/ â ââ client/ â ââ index.html â ââ package.json â ââ package-lock.json â ââ client.js â ââ shared/shared.js
where client.js imports shared.js â When I change client.js Parcel does its thing, updates the browser and life is good. When I updated shared.js nothing happens. So to me, the file-watching issue comes down to: Parcel should watch all files referenced starting from index.html as entry point no matter which directories these are in.
The approach @jameslaneconkling outlined applies to those with parcels as their only bundler invoked at the projectâs root. It works because Parcel symlinks resolver works just fine.
The key issue here is that Parcel watcher will ignore any resolved symlink path thatâs outside of the project root. Bundling/building will work just fine, but watching will not.
FYI while Parcel doesnât currently support global symlinks created via
npm link
, it does work fine when building a monorepo (cc @krnlde , @danmarshall , @yume-chan , @theopolisme ). The configuration is hard to get right and isnât documented super well. Hereâs a super minimal example:Make sure only the workspace root has a
package-lock.json
file and no packages do. Ditto only project root should havenode_modules/
and.parcel-cache/
directories.Would an option to set the project root explicitly via the CLI to override the inferred root based on the lockfile work for you? Watching outside the project root is much harder, but if you could set the project root manually that might be a reasonable workaround?
Itâs on the roadmap, but it will be a bit complex to implement. We somehow need to discover all of the watch roots as parcel builds a project for the first time. We also need to check them all on startup when building from cache.
In addition, we will have to figure out how to handle paths that are outside the project root. Parcelâs cache is meant to be portable between machines, or if you move your project directory, but symlinks outside the project root break this.
Also, symlinks tend to break node_modules resolution. For example, if your project has a dependency on React, and you symlink another module which also has a dependency on React, you will get two copies of React in your build and it most likely wonât work at runtime.
Speaking from personal experience in the past trying to symlink projects together, I would definitely not recommend a setup like this. It breaks many things, not just watching. Using yarn/npm workspaces is much better in basically every way.
Here to provide my project structure that would be helped by this functionality. I have an
example
directory in my npm library repo which provides a fully ready togo example project that uses the library. The library is included in theexample/package.json
asfile:..
. The library code is not auto updated due to parcel inexample
not traversing symlinks.I am currently using this as a workaround:
Good workaround, attach my code for example:
But thereâs a minor issue with the workaround, LINKED_DEPENDENCIES changed will trigger the whole page reload, not HMR.
@bminer I donât see why at least giving developers an option through a flag as you suggested would be an issue, if respecting symlinks outside the project root as before is out of the question. In our case, the package Iâm working on is a dependency on more than one in-house project, and is not an integral part of any of the parent projects. It doesnât make sense to build all as âworkspacesâ as the parent projects have no relation between them.
@Systemcluster - As discussed above, allowing Parcel to watch symlinks outside the project root is trickier to implement. Allowing users to specify additional paths to watch outside of Parcelâs project root seems like a fair compromise - and it sounds rather easy to do. As many have mentioned, the âproject rootâ means the folder containing the package lock file.
Hello, @devongovett I made a repository to reproduce the issue I had : https://github.com/am-creations/parcel-issue-4332-symlink-watch
The project structure in this example is similar to our projects : /src/package.json and /vendor/whatever/package.json, so the âmainâ package.json file is not in the project root.
If you are having problems, could you please explain your setup in more detail? Parcel 2 works fine with yarn workspaces for example. As long as the symlinks are within your project root (i.e. git repo), it should already work fine.
If you are symlinking outside, how do you set this up? Manual
npm link
or similar? Is this only temporary? Do you work with a team? How do you ensure all devs have the same setup? I feel that monorepos i.e. yarn/npm workspaces are the true solution here. Happy to eventually add support for watching outside the project root but there is complexity there and I want to understand why this issue gets so much attention. So, please help me understand your setups.Afaik parcel canât look outside its start context so if you want to watch all workspaces in a workspace root youâll need to start parcel in that root. Did you do that? Be extra sure to not have any lock files inside any of the workspaces. Parcel unfortunately has no warning for that and will just silently fall back to the workspace scope instead of root scope, which took a lot of lifetime from me in the past the point where I wanted to quit my job and start a lumber business đ
I run into this issue recently, the fact that it is standing for 3 years is amazing. unfortuntly, such limitition in parcel 2 makes it less productive when working with linked dependencies. Possible workaround I found is to refresh
package.json
for triggering new build. any convenient solution proposed so far?Iâm getting the same issue. Building a package and I have a demo app using Parcel 2 in an folder
example
, I donât want to mix my.lock
files and I would like to be able to get the app refreshing when I apply changes on the package components.Wow it really has been 3 years! Like Iâve said, Iâd be happy to open a PR to resolve this one if I can get some feedback from the devs that itâs likely to be merged. If the devs explicitly donât want this feature, I donât want to waste my time.
Thoughts? @devongovett
I am having a very similar issue. We are using a workspace for convenience. The packages are standalone and have their own
.lock
files. The workspace is optional. Being able to specify the root would solve what seems to be a common problem.Edit: We are âsolvingâ the issue for now by temporarily removing the lock file and checking it back out before committing changes. This is a horrible workflow, but the one weâve chosen so we can still use Parcel.
We have a similar setup too.
I may not know all the aspects of the watcher, and Iâm certainly ignoring a lot, but I donât think the entire file system needs to be traversed, only the paths we need to resolve.
After having replaced all aliases, and resolved any ââŚâ in paths ans such, when a âreal pathâ is not the same as the path to resolve, we may consider it to have at least one symlink, and the common root between these two paths could be taken as a new directroy to watch.
That was an option I tried, but got issues as NPM has a inheritance mechanism that is a PITA because we use preinstall scripts : all modules in a directory inside the root execute the scripts, for example. And there are maybe issues I could not identify because I was blocked by the first issue. And as that it worked fine with parcel 1, we structured all our projects like this.
Does someone have an example with a working setup with npm workspaces? I tried setting up my new project with them, but still need to (re)start manually when referring to packages by name like:
Using a relative path works though
@JanMisker thanks for the workaround idea.
In my case, I have more than 2 levels of dependencies in a monorepo, and this technique only seems to work one level deep.
Parcel 1 âjust workedâ quite magically. Without this ability, Parcel 2 is a step back in productivity. I would not have updated if it werenât for the many security issues of Parcel1 's dependencies.
âonly files inside of that are watchedâ essentially ignores symlinks. This is mostly because the file watching APIs from the various OSs only fire change events for the actual parent directories and donât traverse through every symlink
So
node_modules
is watched, butnode_modules/symlinked-package/*
isnâtSo this is more of a technical limitation at the moment, as explained in https://github.com/parcel-bundler/parcel/issues/4332#issuecomment-706837311 and not a design decision
What do you mean? It intentionally watches node_modules so that updating dependencies and rerunning Yarn triggers a Parcel rebuild for changed files.
Okay yes it is the âEditâ there that is my problem then. The confusing thing is that this did work with parcel v1. When I would
npm link
package-b, parcel would rebuild package-a whenever it changed.As mentioned,
project-a
does contain a lockfile and a.git
directory, butnode_modules
are within that folder so I expected them to be watched, or at least not permanently cached when I restart withnpm run example
. I currently have to delete.parcel-cache
in order for it to include the updatednode_modules
.As long as the node_modules is inside the parcel start context it works. Again parcel picks its start context by probing all folders for .lock files starting with the most-inner one from your start path:
parcel serve workspaces/workspace-a/index.html
probes:workspaces/workspace-a/*.lock
workspaces/*.lock
*.lock
wherever a lock file is found it will not recognize changes beyond that folder. Ever. And they are not planning to change that.
That linked issue doesnât resolve this for me. I donât have a dangling yarn.lock file, just the one in my primary repository Iâm working on. Linked dependency changes donât trigger a recompile, and it seems even restarting parcel and running it with
--no-cache
donât trigger a full rebuild. I have the delete.parcel-cache
in order to have the changes picked up : /Ok, here you go: https://github.com/samuelgozi/Parcel2-issue-4332 Further instructions can be found in the repoâs README file.