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

Feature: Jscodeshift Transformations for --migrate #40

Merged
merged 43 commits into from
Feb 19, 2017

Conversation

okonet
Copy link
Contributor

@okonet okonet commented Jan 26, 2017

What kind of change does this PR introduce?

feature

Summary

This is where the work on #6 is happening.

TODOS

Migrations

  • loaders -> rules
  • pre/postLoaders -> rules with enforce: 'pre/post'
  • solve for -loaders suffix.
  • resolve.root -> resolve.modules
  • remove json-loader
  • add sourceMap: true to UglifyJsPlugin
  • change ExtractTextPlugin syntax
  • remove OccurendeOrderPlugin
  • Remove webpack.optimize.DedupePlugin
  • add LoaderOptionsPlugin with minimize:true ,context and debug
  • change BannerPlugin (https://webpack.js.org/guides/migrating/#bannerplugin-breaking-change)

Does this PR introduce a breaking change?

It should not

Other information

Issues:

@evenstensberg
Copy link
Member

I'm assigning @pksjce for all related work on transformations. Good work! 🎉

@okonet
Copy link
Contributor Author

okonet commented Jan 26, 2017

@ev1stensberg I'm a bit confused. Should I continue working on this?

@evenstensberg
Copy link
Member

Oh yeah, I'm just making Pavithra head of reviewing and getting into the PR, evidently you should ask her for calibration on separation of work when she comes back

@okonet okonet self-assigned this Jan 27, 2017
@okonet okonet requested a review from pksjce January 27, 2017 08:20
@okonet
Copy link
Contributor Author

okonet commented Jan 27, 2017

During my work on this PR I run into some nasty issues with tabs and had to replace them with spaces for fixtures. I saw we have been using eslint --fix to re-format the result of the transformation in order to eliminate those inconsistencies. The problem with this is that:

  1. It basically leaves our code untested since we compare our transformations + eslint transformation with the input
  2. For some reason it completely strip the result of the removeJsonLoaderTransform and I spent a few hours debugging it :(
  3. We should probably allow re-formating the code with eslint but after all of the transforms are done (and not only in test runner)
  4. This required some hard-code of for the jest test runner that is bundled with jscodeshift. This will make upgrading to the next version of jscodeshift very error prone if they decide to change the API internally.

I think it's much better to not rely on eslint formatting for our own tests. In order to be able to pass the ast down to transforms, I'd introduce a wrapper function that would take care of this. This would allow us to still use pre-bundled defineTest from jscodeshift and have modular transformations.

I’m also seeing some of the inconsistencies in the source code itself (as well as mixed usages of tabs and spaces). Should we switch to spaces to ensure we have fewer conflicts (I guess different editors and tools treat tabs differently) and enforce it with eslint? Now that we have auto-formatting in pre-commit hook with lint-staged, it will even fix these automatically.

Looks like webpack repo itself is using tabs, so we should probably stick with it: https://github.com/webpack/webpack/blob/master/.editorconfig#L4 I'd still enforce it with eslint.

Thoughts?

@DanielaValero
Copy link
Contributor

Hi @okonet

About the tabs and spaces, I am with you on staying with tabs, so we are coherent with webpack.

I am not the best expert in code transformations, but anyways will check the branch and the work done on this matter so far, so I can soon enough start also coding :)

@okonet
Copy link
Contributor Author

okonet commented Jan 27, 2017

Another question is if we should check devtool option before applying this transform: https://webpack.js.org/guides/migrating/#uglifyjsplugin-sourcemap

@pksjce
Copy link

pksjce commented Jan 30, 2017

@okonet - Thanks a lot for this! Was looking for a review to validate my approach to this. Looking forward to working with you. Will be adding my comments on this by tomorrow.

const cli_engine = require('eslint').CLIEngine;
const eslintrules = require(process.cwd() + '/.eslintrc.json');
eslintrules.fix = true;
const cli = new cli_engine(eslintrules);
Copy link

Choose a reason for hiding this comment

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

I did this to counteract this issue with recast. But we are using a branch of recast right now, until this issue is fixed. So thanks for cleaning this up.

Copy link

@pksjce pksjce left a comment

Choose a reason for hiding this comment

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

Once you fix the uglifyJsPlugin file reference, this is ready to merge

@@ -1,7 +1,11 @@
const loaderTransform = require('./loaders/loaders');
const resolveTransform = require('./resolve/resolve');
const removeJsonLoaderTransform = require('./removeJsonLoader/removeJsonLoader');
const uglifyJsPluginTransform = require('./uglifyJsPluginTransform/uglifyJsPluginTransform');
Copy link

Choose a reason for hiding this comment

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

This file is uglifyJsPlugin

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean? I'd add Transform suffix to all transforms just to make it more explicit. Thoughts?

j.literal(val)
)]));
var loaderArray = j.arrayExpression(objs);
let objs = p.parent.node.value.value.split('!')
Copy link

Choose a reason for hiding this comment

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

Note - Let's move such references(which are necessary) to some common meaningful methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure it will work in any context but I agree we should try reuse as much as possible. I'd wait till we see more repetitions before we start adding abstractions.

if(val === 'true') literalVal = true;
if(val === 'false') literalVal = false;
let literalVal = val;
// We'll need String to native type conversions
Copy link

Choose a reason for hiding this comment

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

How to do this? Is there some generic way to convert?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, this is what it methods implements, basically. ↓

@@ -0,0 +1,3 @@
[*]
indent_style = space
indent_size = 4
Copy link

Choose a reason for hiding this comment

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

Does this need to be committed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does if you use editoconfig plugin in your IDE. Why not include it?

@@ -0,0 +1,7 @@
module.exports = {
plugins: []
Copy link

Choose a reason for hiding this comment

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

Better to remove the plugins param if the array is empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was thinking about it but still not sure about it. Do you think it won't be too obscure to just remove it from the config?

@pksjce
Copy link

pksjce commented Jan 31, 2017

Also, the no-var lint rule is breaking the build. Maybe turn it into a warning and slowly move up to error?

@pksjce pksjce mentioned this pull request Jan 31, 2017
1 task
.eslintrc.json Outdated
@@ -29,6 +29,7 @@
"always"
],
"no-unused-vars": 1,
"no-console": 0
"no-console": 0,
"no-var": "error"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pksjce I've added this rule to enable eslint --fix for it but I agree this should be in a separate PR at least. I'll revert the commit for now and rebase the branch.

@evenstensberg
Copy link
Member

@pksjce You've got conflicts

@okonet
Copy link
Contributor Author

okonet commented Feb 13, 2017

I've fixed all confilcts 😎

@okonet
Copy link
Contributor Author

okonet commented Feb 15, 2017

Some updates on this PR:

  • Lots of changes in the folder structure. We could simplify even more since there are still lots of bootstrapping code in there but I wanted to stop somewhere :)
  • Switched to Jest Snapshots to simplify test cases creation
  • Exporting transform function that takes source and list of transformations as arguments. This one is re-used in the migrate command

Help needed:

@pksjce
Copy link

pksjce commented Feb 15, 2017

For Validation you should use https://github.com/webpack/webpack/blob/master/lib/webpack.js#L58

@evenstensberg
Copy link
Member

@okonet @pksjce In the parser branch, the validation logic is included. Should wait until that is merged perhaps? I'm aiming to get it ready before monday.

@okonet
Copy link
Contributor Author

okonet commented Feb 15, 2017

I'm fine with merging this as soon as we get all transforms ready. We can continue in separate PRs after that.

* @param { Node } node - Node to start search from
* @returns Path
* */
function findPluginsRootNodes(j, node) {
Copy link

Choose a reason for hiding this comment

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

Hey why can't this be like findAnyRootNode(j, node, nodeName){}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It can totally be if you need it to!

function createProperty(j, key, value) {
return j.property(
'init',
j.literal(key),
Copy link

Choose a reason for hiding this comment

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

This has to be j.identifier(key). Will change this and also related snapshots.

expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot();
});

it('should create properties for non-literal keys', () => {
Copy link

Choose a reason for hiding this comment

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

Do we ever create properties with non-literal keys?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't think so but we should be aware of the issue.

@@ -83,7 +83,7 @@ function findPluginsRootNodes(j, node) {
function createProperty(j, key, value) {
return j.property(
'init',
j.literal(key),
j.identifier(key),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This won't work with anything more complex like foo-bar but I think it's okay in the scope of this project.

Copy link

Choose a reason for hiding this comment

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

Yeah, so key in a Property can be Identifier or Literal, so for safety we'll keep it Literal?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah but as far as I can see we don't use anything but identifiers in our code so I'd create a separate GHI, replace it to j.identifier and add a comment to the GHI for now. Since this style will break linting of lots of code I guess.

foo: true,
bar: \"baz\",
foo: false,
baz-long: true
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here: it's not a valid JS anymore

@@ -23,7 +23,7 @@ describe('utils', () => {
expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot();
});

it('should create properties for non-literal keys', () => {
xit('should create properties for non-literal keys', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this a typo?

@pksjce
Copy link

pksjce commented Feb 19, 2017

Hey! @okonet - I have passed the tests and checked off ExtractPlugin changes. I will add more special cases in smaller PRs later?

This needs more work but ready to merge for now.

@okonet
Copy link
Contributor Author

okonet commented Feb 19, 2017

Yes, I think the opened issues should be separate GHIs and PRs accordingly. Let's make this mergable by rebasing on master and we're good to go.

@pksjce pksjce force-pushed the feature/jscodeshift-transforms branch from 60d8789 to e0539a1 Compare February 19, 2017 20:58
@pksjce pksjce changed the title WIP: JS Codeshift Transformations Feature: Jscodeshift Transformation for --migrate Feb 19, 2017
@pksjce pksjce changed the title Feature: Jscodeshift Transformation for --migrate Feature: Jscodeshift Transformations for --migrate Feb 19, 2017
@pksjce pksjce merged commit f0abf0c into master Feb 19, 2017
@pksjce pksjce deleted the feature/jscodeshift-transforms branch February 20, 2017 10:19
@dentuzhik
Copy link

dentuzhik commented May 2, 2017

I know this is a stupid for this PR, but my searches resulted in pretty much nothing.
Is there any way to use this already, or this is still a WIP?

I tried to clone and run it on my configs which are constructed using webpack-config, did not work out nicely :)

I have nothing against manual upgrade, but having an automatic version is always better :)

@evenstensberg
Copy link
Member

Yeah, you can use npm link, then webpack-cli --migrate myconfig

@okonet
Copy link
Contributor Author

okonet commented May 2, 2017

@dentuzhik I'm not sure it will work with webpack-config. You can report issues with input and output but I'm not sure we'll support non-standard syntaxes in the beginning.

@missing1984
Copy link

This is great, is there any way that i can provide a webpack1 config object instead of a file?

@okonet
Copy link
Contributor Author

okonet commented May 4, 2017

@missing1984 what do you mean by that? stdin? Or what do you have in mind? Also, not at the moment and I'm not sure what's the use case.

@missing1984
Copy link

@okonet In our use case, we break the webpack config into many small pieces and merge(webpack-merge) or layer them together to serve different deployment needs. Is the migration cli going to help?

@dentuzhik
Copy link

@missing1984 I achieve the same thing via webpack-config package, I linked above and seems that in this case automatic migration will not be entirely possible.

@okonet
Copy link
Contributor Author

okonet commented May 8, 2017

I think it will work if you operate on objects. The best way to know would be to try running it on your setup and let us know if something isn't working.

@thom801
Copy link

thom801 commented Jun 23, 2017

@pksjce and @okonet you guys are amazing thank you for working so hard and creating this.

@arthurgeron
Copy link

I'm a little lost, I've tried using webpack-cli --migrate webpack.config.babel.js but it says migrate is an unknown argument.

@evenstensberg
Copy link
Member

Try without the dashes

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.

8 participants