Skip to content
This repository has been archived by the owner on Jun 8, 2019. It is now read-only.

Webpack plugin #99

Closed
mbrevda opened this issue Feb 8, 2017 · 17 comments
Closed

Webpack plugin #99

mbrevda opened this issue Feb 8, 2017 · 17 comments

Comments

@mbrevda
Copy link

mbrevda commented Feb 8, 2017

I was wondering how feasible it would be to convert this to a webpack plugin? It would seem that might be one way to resolve the race issue when trying to save all the strings to a single file.

@ericf
Copy link
Collaborator

ericf commented Feb 8, 2017

I don't think turning this into a Webpack plugin is the right change. This will stay a Babel plugin as it's dealing with syntax and not bundling.

Have you thought about all the possible ways a race condition could come in when writing to a single file? I believe Babel processes files single-threaded, but maybe it's the case where the someone is using Gulp or something and it's kicked off many Babel processes?

@ericf
Copy link
Collaborator

ericf commented Feb 8, 2017

I'm also not super worried about this because I can't think of a scenario where the developer doesn't have to transform the extracted messages .json files into a form that fits for their translation system. The glob call to gather all the files is likely the simplest part of that script to write.

@mbrevda
Copy link
Author

mbrevda commented Feb 8, 2017

Use case

I'm not sure that any of the current methods work for my use case. By way of introduction, I should point out that I was using browserify until now, and I'm just switching to webpack (react-intl is my last task).

I'm my use case, I'm building multiple apps/entry points concurrently. Hence, I couldn't just let babel save the files somewhere and then process them, as those .json files would contain more than one apps' worth of strings. I also can't, say, save the files to different directories as .babelrc can't be configured differently during concurrent runs . Here is the relevant part of my gulp file:

Object.keys(jsFiles).map(file => {
    return tasks.jspack(opts, moreOpts, jsFiles[file], watch)
})

That being the case, the only method that worked for me until now was to intercept the metadata from babel programmatically and save the files on my own:

b.on('transform', tr => { // b is the browserify object
    if (tr instanceof babel) {
        tr.on('babelify', res => {
            res.metadata['react-intl'].messages.forEach(m => messages[m.id] = m.defaultMessage)
            saveMessages() // method not shown here
        })
    }
})

Pedant

If I may be pedantic for a moment:

as it's dealing with syntax and not bundling

As part of building bundles, a lot of what webpack does is it extracts code that needs to be processed separately from regular js (for example css). A loader would probably be well suited for the webpack model.

Summary

I don't mean to suggest that webpack is better or more correct than babel, or vise versa. I'm merely looking for a simple and clean way to save my strings, and think that webpack might be a good fit 😃.

Thoughts?

@ericf
Copy link
Collaborator

ericf commented Feb 9, 2017

Can you have a separate task which then processes all the extracted messages how you need them to be processed?

It seems like you don't need/want to bundle the extracted messages with your source code — assuming you treat them and the translations derived from them as data that's separate from the code.

@mbrevda
Copy link
Author

mbrevda commented Feb 9, 2017 via email

@mbrevda
Copy link
Author

mbrevda commented Feb 10, 2017

I've spent way too much time trying to come up with an elegant solution, so I'm open to pretty much anything that works 😄. What did you have in mind?

@ericf
Copy link
Collaborator

ericf commented Feb 22, 2017

I'm just saying that likely want another build script to run to process all your extracted messages so they can be sent to the translator. This doesn't seem like something you need to couple with Webpack. I usually try to think of the messages passed to <IntlProvider> as data and not code.

@mbrevda
Copy link
Author

mbrevda commented Feb 23, 2017

I'd be ok with it being a standalone - so long as it would return the results as an object so that they can be formatted without worrying about a race condition (with another process writing files in the same directory).

@ericf
Copy link
Collaborator

ericf commented Feb 23, 2017

Assuming each file is only processed by one process, once, then there should be an issue since every source JS file that has messages that need to be extracted will have a corresponding JSON file.

@mbrevda
Copy link
Author

mbrevda commented Feb 23, 2017

The race condition I mentioned wasn't related to writing the files, rather it was with reading them after a build. If another process is building at the same time, your messages output directory will contain messages related to different bundles and you have no way of knowing which messages belong to which bundle.

@ericf
Copy link
Collaborator

ericf commented Feb 23, 2017

Right, but I don't get why this can't be staged. Run the webpack build, then run the script that processes the translations.

@mbrevda
Copy link
Author

mbrevda commented Feb 23, 2017

Staging works fine with a single bundle entry point and a single "tenant". In the use case I illustrated above (albeit not well enough), there are both multiple tenants (which can have custom includes and/or messages).

To elaborate a bit on tenants: we have multiple sites running with almost the same code and differ mostly in branding. During a "vendors" build, we concurrently iterate over all the tenants, and build all entry points - resulting in many bundles being built at once. Here is a quick pseudo-example:

Promise.all(vendors.map(vendor => {
    return Promise.all(jsEntries.map(file => {
        return buildJs(vendor, file)
    }))
})).then(/* collate all those messages, if you can figure out which files belong to who/what */)

Does that properly explain the use case?

@ericf
Copy link
Collaborator

ericf commented Feb 24, 2017

Sure, but I don't see why you can't first build all the JS, then process all the messages.

npm run build:js && npm run build:messages

@mbrevda
Copy link
Author

mbrevda commented Feb 26, 2017

Ideally, collated messages should be mapped back to their bundle. So app.js should have a corresponding messages/en-US/app.js, etc. All this takes place under tenants, so like:

tenant1/app.js
tenant1/messages/en-US.app.js

etc.

With the babel plugin, all messages are output to a single directory, making it impossible to know which messages file belongs to which app/tenant.

@ericf
Copy link
Collaborator

ericf commented Mar 3, 2017

I'm not sure what to say as I don't think I can help with your custom situation here. I don't have any plans to make this a Webpack plugin.

@mbrevda
Copy link
Author

mbrevda commented Mar 5, 2017

Personally, I'd be happy with the programmatic method, which utilized babel (eliminating the need for another plugin) but is more dependant on the current build step. With @Ognian's changes here, it should finally be possible to integrate this easily with webpack, while leveraging the babel plugin.

@longlho
Copy link
Member

longlho commented May 26, 2019

close due to stale

@longlho longlho closed this as completed May 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants