Skip to content
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

Issue #11257 - Apply "files" npm whitelist at build time #11404

Conversation

yu-tian113
Copy link
Contributor

Compare files/folders in package/npm to "files" entries in package.json, only copy whitelisted files/folders to build.

@gaearon
Copy link
Collaborator

gaearon commented Oct 31, 2017

I'm thinking that we also probably want to fail the build if there is a .js file in the package root that doesn't have an npm/*.js equivalent.

@yu-tian113
Copy link
Contributor Author

Thanks for the advice @gaearon, I can do a file check after copyBundleIntoNodePackage resolved, and either return another promise to continue the build or fail it if files don't match.
My only question is I'm not sure in what cases, in npm consumption packages, a .js file can be added to package root from somewhere other than npm/*.js, did I miss anything or is this a safeguard for anything unexpected in the future?

@gaearon
Copy link
Collaborator

gaearon commented Oct 31, 2017

I'm not sure in what cases, in npm consumption packages, a .js file can be added to package root from somewhere other than npm/*.js

We use files like react-dom/server.js for local testing and bundling, but we need corresponding files like react-dom/npm/server.js to point to compiled bundles in the built packages. We want to ensure that we can't add a new entry point like react-dom/my-entry-point.js that would pass the tests without also adding a corresponding react-dom/npm/my-entry-point.js file and adding that file to "files" in the package.json.

Does this make sense?

@yu-tian113
Copy link
Contributor Author

Awesome @gaearon.
I see the current react-dom build will fail then because the index.fb.js in the package root does not exist in react-dom/npm.
I'll need to create an equivalent in react-dom/npm to pass this file matching check. I'm thinking

'use strict';
module.exports = require('./index');

It won't be exposed in npm packages as it's not whitelisted in package.json.
How does it sound to you?

@gaearon
Copy link
Collaborator

gaearon commented Nov 1, 2017

Hmm. Good point, I haven't though about this.
Let's just make an exception for .fb.js files?

@yu-tian113 yu-tian113 force-pushed the #11257-Apply-files-npm-whitelist-at-build-time branch 3 times, most recently from 52a4d3b to af7f44f Compare November 2, 2017 14:03
@yu-tian113
Copy link
Contributor Author

Hi @gaearon, please review the updated code as per our discussion above.
Lint is failing on the master branch right now, I'll follow up once it's fixed.
Cheers.

@gaearon
Copy link
Collaborator

gaearon commented Nov 2, 2017

Can you rebase now?

@yu-tian113 yu-tian113 force-pushed the #11257-Apply-files-npm-whitelist-at-build-time branch from af7f44f to 9a0189b Compare November 2, 2017 23:18
@yu-tian113
Copy link
Contributor Author

Done, please review. Thanks @gaearon.

@yu-tian113 yu-tian113 force-pushed the #11257-Apply-files-npm-whitelist-at-build-time branch from e2d1516 to 507357f Compare November 2, 2017 23:48
Copy link
Collaborator

@gaearon gaearon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nits.

const packageJson = resolve(`${from}/package.json`);
const whitelistedFiles = fs.existsSync(packageJson)
? require(packageJson).files
: null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just fall back to []? Then you don't have to check for existence later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Also need to check require(packageJson).files is not undefined, as files entry is missing in some package.json(e.g. react-call-return).
Updated to
const whitelistedFiles = (fs.existsSync(packageJson) && require(packageJson).files) || [];
And deleted the existance check below.
if (whitelistedFiles && whitelistedFiles.length > 0) {}
if (whitelistedFiles.length > 0) {}

}
});
if (whitelistedFiles && whitelistedFiles.length > 0) {
let asyncCopyProxies = [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless assignment: it's reassigned right afterwards. Let's combine?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, done.

if (whitelistedFiles && whitelistedFiles.length > 0) {
let asyncCopyProxies = [];
asyncCopyProxies = npmRootFiles.reduce((proxies, file) => {
if (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment here would help understand what this does and why

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments added

return proxies;
}, asyncCopyProxies);
return Promise.all([
...asyncCopyProxies,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe promisesForForwardingModules?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hehe, sorry, didn't realise I typed these promises as proxies.
Variables renamed.

@yu-tian113 yu-tian113 force-pushed the #11257-Apply-files-npm-whitelist-at-build-time branch 2 times, most recently from b4ddd28 to cf2656b Compare November 4, 2017 02:37
@yu-tian113
Copy link
Contributor Author

Thanks @gaearon. All updated, please see my comments.

@gaearon
Copy link
Collaborator

gaearon commented Nov 4, 2017

Shouldn't we also fail if an entry point is not in files in package.json?

@yu-tian113
Copy link
Contributor Author

Good point, the problem is some package like react-call-return omits the files field, which indicates

everything except automatically-excluded files will be included in the publish

I'm going to check the existence of files field, if not exists, everything in ./npm are whitelisted and will be copied to build.

Another defect l noticed, wildcard patterns("glob/*.{js,json}") in files field is not supported properly in the current solution.

Working on these two issues now, talk soon.

@gaearon
Copy link
Collaborator

gaearon commented Nov 7, 2017

Good point, the problem is some package like react-call-return omits the files field

This actually sounds like a problem we should fix in that package. 😉
Let's mandate that the field exists.

@gaearon
Copy link
Collaborator

gaearon commented Nov 7, 2017

I fixed react-call-return in b2ff29d. We should throw if files doesn't exist unless it is a private package (in which case it's fine).

@yu-tian113 yu-tian113 force-pushed the #11257-Apply-files-npm-whitelist-at-build-time branch from cf2656b to d445df9 Compare November 7, 2017 15:13
@yu-tian113
Copy link
Contributor Author

yu-tian113 commented Nov 7, 2017

No problem, thanks for the fix.
Just done some updates to handle these and also the wildcard pattern issue I mentioned above.
All the checks we added should work with globs like *.js in files now.
Please review.

`'files' field is missing from package.json in package ${packageName}`
);
process.exit(1);
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a hard exit, can you remove the else and just leave it after this code unindented?

@yu-tian113 yu-tian113 force-pushed the #11257-Apply-files-npm-whitelist-at-build-time branch 3 times, most recently from 879231a to 8b33c91 Compare November 13, 2017 23:51
- Terminate the build if 'files' field is missing from package.json
- Terminate the build if any entry point doesn’t have equivalent in ./npm folder
- Handle patterns in 'files' field
@yu-tian113 yu-tian113 force-pushed the #11257-Apply-files-npm-whitelist-at-build-time branch from 9a988d9 to 703fb32 Compare November 13, 2017 23:55
@yu-tian113
Copy link
Contributor Author

Yes, makes sense, please review, thanks @gaearon.

@gaearon
Copy link
Collaborator

gaearon commented Nov 21, 2017

Seems like file permissions were changed accidentally?

scripts/rollup/packaging.js 100644 → 100755

fs.mkdirSync(to);
let existingDirCache = {};
// looping through entries(single file / directory / pattern) in `files`
const whitelistedFiles = whitelist.reduce((list, pattern) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is a bit complicated. Is there any module we can use for this? Or maybe there's some simpler way to write it? At least let's extract it to a separate function.

Copy link
Contributor Author

@yu-tian113 yu-tian113 Nov 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gaearon, some modules may help with bits and pieces, but I'm a little hesitant including any as new dev dependencies, considering we already use things like ncp and glob(which these modules are also build upon).
The other reason I did't use a prebuild module is I don't want to encapsulate tasks together. For example, glob composes a whiteListedFiles list during the copy process, which is used later for checking all entry points are whitelisted. If a module doing things like copy with glob, we'll have to run glob again separately to get the list.
node-mkdirp can help creating nested directories. Do you think I can add it as dev dependency?
I will extract it to a separate function, make the code flow more intuitive.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node-mkdirp seems fine. Why didn't we need it before?

@yu-tian113
Copy link
Contributor Author

Thanks @gaearon, mkdirp creates parent directories on the fly, help us get rid of the reduce inside reduce in the old code :)
I didn't know about this module before you suggested making the code simpler. Thought I could just build my own in about 10 lines, but it did complicate the function a lot.
I also reset the file permission back to 644.
Please review.

@gaearon
Copy link
Collaborator

gaearon commented Nov 28, 2017

This still seems complicated. My biggest issue is we're essentially reimplementing npm's files inclusion logic.

I think it would make more sense if we used npm pack instead of copying the directory. Then we'd literally test what npm publish actually does (but "deploy" to our build folder): http://podefr.tumblr.com/post/30488475488/locally-test-your-npm-modules-without-publishing

What do you think?

@yu-tian113
Copy link
Contributor Author

Sorry, I'm a little lost here. Do you mind explaining the idea using npm pack?
How will it deal with the file replacement(entry points) and copy(Circle.js... in react-art package) from /npm?
Besides, reimplementing the files inclusion logic also make sure the build will warn and fail if an entry point is not whitelisted.
Thanks!

@gaearon
Copy link
Collaborator

gaearon commented Nov 29, 2017

I was thinking that maybe we need to change the build step to be:

  • Build to a temporary folder
  • npm pack it
  • Unpack into our build/packages folder structure

This way we simulate what would actually happen during npm publish.

Besides, reimplementing the files inclusion logic also make sure the build will warn and fail if an entry point is not whitelisted.

That's true. But I added a suite of tests that run on bundles in build/packages/ folder a week ago. So if something is missing there, those tests would fail. In other words, instead of trying to validate it ourselves, we can just "simulate" a publish and then run the tests on the packages folder.

@yu-tian113
Copy link
Contributor Author

Build to a temporary folder

Here we'll still copy everything inside /npm directory to the temporary folder as we've been doing.

npm pack it
Unpack into our build/packages folder structure

I think npm pack and unpack is pretty handy to prepare the build packages, but not much of help validating the packages, as they just silently skip any missing files. So all the validation need to be handled in the test suite.

I'm happy to give it a try.

@gaearon
Copy link
Collaborator

gaearon commented Nov 30, 2017

So all the validation need to be handled in the test suite.

Yes, but this is enough because our test suite covers all public API (or at least it should—if not, we should fix the test suite), and >92% tests run on bundles.

@yu-tian113
Copy link
Contributor Author

Hi @gaearon, I've created a new pull request #11750 for the updates as per our discussion above.
Please review, thanks!

@gaearon
Copy link
Collaborator

gaearon commented Dec 5, 2017

We decided to go with #11750 instead.

@gaearon gaearon closed this Dec 5, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants