-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add watch option for cache validation #13
base: master
Are you sure you want to change the base?
Conversation
I think running another watcher to watch the DLL watch list files on the fly is a bit overkill. So I'll hold that for now. It's already working to validate the DLL cache every time there are changes in the contents of watch list on the next webpack start. works for folders too, so changing something in node_modules will trigger DLL recompilation on the next start. |
@viankakrisna this is awesome! Running the watch examples made me very happy, it worked beautifully. I noticed now there's no cleanup before each build, is it intentionally?
That will be a great addition to be able to make changes to the files without re-running webpack. Many thanks 🙏 |
It unintentional 😅 I've updated the code so the build output will be in the separate folders based on the hash and get cleaned up accordingly.
Yes, there's a whole lot about webpack hooks that I don't understand yet. I think this is more on your area, like how to retrigger compilation based on external file changes? Is adding more to compilationDependencies is the right way to do it?
Thanks to you I can reimplement this idea on a webpack plugin 🙏 😄 |
Hi, @viankakrisna, I would like to fix a few bug about multiple instances and I think It might be wiser to work on your branch instead of the master. I saw that you already handle it using a counter and also store the environment. I like what you did with the hash! Do you feel that it's ready from your side? Btw, how do you debug your code? Do you know how to set it up? If not, tell me, I would gladly show you how. |
Yeah, sorry the diff is a mess, I can't live without prettier anymore.... So i think all is well from my side. Right now i'm just trying to find a way to improve hashing perf, but haven't got anything substantial to add. Feel free to merge this to other branch on your repo / push to my branch. Need to go to bed now :) |
I really wondered if you ever sleep 😉 Good night, my friend. |
Just wanted to let you know that I'm really happy with the way you handled the instances problem! I fixed the cleanup and made a few style changes, but other than that, it worked like a charm. I saw what you mean about the perf problem of getContents, I comment it out for now. Also, you can take advantage of bluebird's non standard api, it's very elegant and pleasant to use. Take a lot at the cleanup function for examples: The sync version of const cleanup = settings =>
fs
.readdirSync(cacheDir)
.filter(fileName => fileName.includes(settings.nodeEnv))
.filter(fileName => fileName.includes(settings.id))
.forEach(p => del(path.join(cacheDir, p))); In The beauty of bluebird's non-standard api is that now you can iterate over the promise's values as if it were just a regular array: import fs from './utils/fs';
...
const cleanup = settings => () => {
return fs
.readdirAsync(cacheDir)
.filter(fileName => fileName.includes(settings.nodeEnv))
.filter(fileName => fileName.includes(settings.id))
.each(p => del(path.join(cacheDir, p)));
}; This is equivalent to: const cleanup = settings => () => {
return fs
.readdirAsync(cacheDir)
.then(arr => {
return arr.filter(fileName => fileName.includes(settings.nodeEnv));
})
.then(arr => {
return arr.filter(fileName => fileName.includes(settings.id));
})
.then(arr => {
return arr.each(p => del(path.join(cacheDir, p)));
});
}; This is the branch worked on: https://github.com/asfktz/autodll-webpack-plugin/tree/pr/13 Thank you for the awesome work you made (: |
Nice! I like what you did there. And thanks for sharing the beauty of bluebird :) The problem with
It's unfortunate if we ship without the ability to watch the changes of the contents of directories, maybe we can just enable it via a flag? |
Of course, there's a penalty in enabling folder hashing. But it makes the cache invalidation more accurate. Btw, it's only enabled only when we define |
I absolutely believe this is our next milestone. But for now, I needed to ship a release to fix two critical bugs:
I help some big projects to implement the plugin and these two are show stoppers. Now that this is out of the way, we can focus on detecting file changes. |
Ok then, ship it! 👍 |
I figure maybe instead of hashing the contents we could just calculate the hash via name + last modified time? Interestingly, reading last modified date is slower on my machine rather than reading the content itself. Will do proper reporting when I have time. Btw, CI failing on node 4 because while testing, the hash on the first run is not written, and on node 8 because of unhandledRejection. |
Note: It's nice if we can run tests locally for multiple versions of node. 😄 |
Really? that's interesting... Maybe we can also find a way to reduce the number of files needed to be watched For examples, if we setup the plugin like so: new AutoDllPlugin({
watch: true,
entry: {
vendor: [
'react',
'react-dom',
'moment'
]
}
}) When can only check for changes in And if we want to add another file to the watch list we can do something like: new AutoDllPlugin({
watch: {
files: [
'./package.json'
]
},
entry: {
vendor: [
'react',
'react-dom',
'moment'
]
}
}) (Not sure about the format, but that's the main idea) What do you think? |
The problem with that is if somehow, moment has external dependency, and it is hoisted to the top level folder in node_modules, changes to that folder is not detected. We already let the user to specify which folder or file they want to watch by giving them the watch option as array, if they don't want to watch node_modules they can remove that from the array. I think that's a fair tradeoff and simpler :) if in the future we want to add more setting to watch, we can detect if it is an object. |
I think it's great if we want to give the option on how the hash is created though, eg. switch between reading content or last modified date.
|
Either way, I'm fine as long as the user can control the list of paths (file and folder) that we should watch for changes :) |
Maybe the question is how to find a reasonable defaults for
or
I'll go with the former because it's more magic and solve most edge cases |
How about reading the module's dependencies in its
Just read those and you're done. |
Interesting, maybe we can use require.resolve for it? |
but then, what if we change the file required from the |
Not sure I understand, can you show me an example? |
ok, so imagine this
the content of
And then the user modify this |
Hm... but npm modules are precompiled, isn't it already resolved at this stage? |
hmm, I don't know what you mean by precompiled, but isn't importing like this means that it's a different file from the main entry point? |
We could just watch the dependency folder from the entry files and its dependencies by parsing the package.json of entry files. How deep we want to go here? Do dependencies of the dependencies needs to be watched too? I think in the end we will watch most of the node_modules, so it's simpler to just watch it recursively in the first place.... |
btw, played around with adding a setting for different implementation of reading the hash source here |
Sorry. My bad.
It depends on what are the use cases going to be. For example: If you just want to add a If you're working on a PR on the other hand, you sure do, but then you probably gonna use a symlink instead anyway. My original intention was that when you want to work on a module from the DLL, So in my option:
I believe that should be enough for the initial release of the feature. I someone will need more than that, he/she will open an Issue for it. What do you think? With that said, if you find a way to watch all the possible dependencies without affecting performance - that will be a whole different story. |
I think it's a trade off, and the user that configuring it should know that there will be a tradeoff for adding And rather than |
It could be |
run npm install before running examples on test re-add watch examples
7f4798f
to
d9820b5
Compare
tweak test names
remove redundant io return on catch
played around with this idea on this CRA PR facebook/create-react-app#2786 And the performance for mtime is consistently faster than that content (of course). 3s vs 9s for hashing CRA's node_modules. |
That's nice, @viankakrisna. You're really doing a great job at improving the performance, I admire that. But Ade, additional 3 seconds for a plugin that aim to improve performance is still quite a lot, even 1s is, especially if this is gonna be the defaults for create-react-app. How about instead, provide the create-react-app user with a simple way to exclude that module from the DLL as long as he's making changes to it (from his package.json for example). What do you think? |
yeah but 3 second delay is only happen only if the user setup to watch node_modules. I think the real win from this pr is ability to watch changes to package.json, yarn.lock, and package-lock.json for cache invalidation (this surely wont take 3 seconds). Watching node_modules is entirely for the user to make decision. As for CRA, there are some discussion of placing Note: we should add a test that adding this plugin won't make the take longer than without it. Just to be sure :) |
btw nice work on the docs! 👍 |
Also, i think the point of this PR is lost because it can be implemented from outside of this plugin. As long as we stringify and hash the settings object. |
That already exists. This is why the That will invalidate the cache whether or not you used the new AutoDllPlugin({
...
shouldInvalidate (next) {
// whether or not the cache should invalidate
next(true);
}
})
Thanks! much more works to be done |
Where do you have this information from? I have never heard of this, and can also not reproduce this behaviour.
is not correct. |
Reopening for visibility of more discussion 👍 |
@danez I'm sorry to hear about it. let's see what we can do to prevent it from happening again. I use find-cache-dir to create the path for the cache directory. sindresorhus/find-cache-dir#1 (comment)
I realized that I made a mistake. I apologize for the confusion. I should have double check that. I will add Also, I'll add a new option in the config to allow the user to tap into the invalidation step: new AutoDllPlugin({
// always invalidate
shouldInvalidate: true,
invalidate: () => {
// force invalidation for specific environment
return process.env.NODE_ENV === 'production';
}
invalidate: (state) => {
// read the current state
state.rebuild // Boolean. Is it a regular build or a rebuild triggered by devServer
// only build on first run, but not for rebuilds
return !state.rebuild
}
invalidate: () => {
// it also except a promise
return new Promise((resolve, reject) => {
fs.readFile('...', (err) => {
if (err) {
return reject(err);
}
resolve(true / false);
})
})
}
invalidate: (state, config, hash) => {
// build your own hash
// For example, below is the general idea for the new default.
// you can gradually build your hash by calling hash.add() as many times you want
// here, we add the config passed into the plugin.
// hash is immutable.
hash = hash.add(config);
return new Promise(() => {
var pkgPath = path.resolve(config.context, './package.json');
fs.readFile(pkgPath, (err, content) => {
if (err) throw err;
// read package.json's content and add that too.
hash = hash.add(content);
// when you are done, return the hash.
// when a hash returned instead of a boolean,
// the plugin will compare it to previous one (if exists)
// and then it stores the hash in the cache,
// so it can be compared against the next one.
resolve(hash);
});
});
}
}) |
No need to apologize. What I did now is adding I like the idea to be able to modify the hash. I could then simply add the two files mentioned before to the hash. |
1st pass of providing watch mode.
Right now this PR only hash the files and folders in watch settings to calculate the value of
isCacheValid
To test:
examples/watch
TODOS:
- [ ] Watch for the changes in these files and folder and rebuild without restarting devServerholding this one for future development