webpack-rtl-plugin
webpack-rtl-plugin copied to clipboard
Dynamically change direction
@romainberger very good job working on this project and the rtl-css-loader!
One thing though - the solution in these libraries assumes a different html file for different directions: This plugin requires a tag with different href (.rtl.css), and the rtl-css-loader requires a dir attribute on the tag.
I have a language selector and I'd like to allow switching languages without reloading the page (which will also cause to lose state).
Is there any way to make it work without loading a different html file?
Maybe load into the page the two css bundles (rtl + lrt) and rely on a css class somewhere up the tree, so all rtl styles will be nested under .rtl and the ltr styles will be nested under :not(.rtl) ?
Thanks!
I've chosen this way of working for now as at Dailymotion we're using server-side rendering, which let us choose between the regular and the reversed css.
We can definitely get it to work with a class, but that would load two stylesheet right away, including for users that may never switch to the other version. Which is why I don't recommend using the rtl-css-loader
on prod since both versions are present in the bundle.
But if you can change a class somewhere you should be able to change the dir
attribute, right?
Sure, I forgot to mention that I'm using React, hence, changing a class in some tag is straight forward while manipulating the html tag is not the React way.
Regarding the duplication - maybe we can make only the diff duplicated, as most of the styles are not direction dependent. Also, this can be customisable.
BTW, when you say "using trl-css-loader on prod" do you mean to build the assets with it ? Because I've did it and I don't see both versions on the output... ? If it will generate both rtl and ltr versions on the css this actually can be very helpful for me.
I totally get what you're saying about it not being the react way, and I'm all about the react way :)
The rtl-css-loader
does generate both versions in the output, here's the output in the example (makes me realize I forgot to gitignore the dist). You can see the regular css and the rtl version, with a simple ternary to determine what version to use.
About making a diff with only the different style, I actually thought about this solution but it would need some work I haven't had time to do.
The main issue I think is that the condition that dictates which version to use is coded in the loader. To make it customizable it would need an option where the developer would give the code that would be used in the bundle. Same as above I wanted to give it a shot but didn't have the time.
I understand what you're saying..
Regarding the rtl-css-loader
I think I now get that maybe it doesn't work with extract-text-plugin
?
I'm using extract-text-plugin
for development as well, when I removed it I saw the ternary operator like in the example..
Oh yeah if you're using it with the extract-text-plugin
it will behave like the css-loader
, I should specify this in the doc sorry :( It's supposed to be used with the style-loader.
But I'm using it with the style-loader
I'm sorry, I think I had to write the full background of my configuration instead of providing it in small pieces :)
So, basically I'm extracting css to different file (styles.css
) using extract-text-plugin
(in dev + prod)
I'm also using html-webpack-plugin
that builds my HTML. This is why when I'm using webpack-rtl-plugin
there's no link tag with href to styles.rtl.css
(the href to styles.css
exists because extract-text-plugin
makes sure that html-webpack-plugin
is aware of it. Maybe it's a good idea for your plugin to support html-webpack-plugin
. Just thinking out loud..)
Bottom line - the minimal solution for me (and for anybody that wants to change direction on client side) is that rtl-css-loader
will support extract-text-plugin
. This way all the (duplicated) css will go into style.css
and I'll have to manipulate the dir attribute.
It's not the React way but I can live with that for now, also with the duplicated styles.
Later, if your webpack-rtl-plugin
will support html-webpack-plugin
in that way that it will generate two HTMLs:
- with no dir attribute and href to
styles.css
- with
dir='rtl'
and href tostyles.rtl.css
This will solve the duplication issue.
Sorry it turned out long :(
Edit We were writing at the same time, I'm checking your answer.
Can you paste your config so I can see? Sorry I have troubles being clear when I try to explain stuff
By using it with the style-loader I mean without the extract-text-plugin. If you use extract-text-plugin
+ style-loader
, the style-loader is actually used as a fallback loader for dynamic chunks. Which means the css file created will be "regular" css (as if you were using the css-loader
, no rtl), then only the dynamic chunks would benefit from the rtl-css-loader
. Am I clear?
// will work
{
test: /\.css$/,
loaders: ['style', 'rtl-css']
},
// this will behave like the css-loader for the css file created, but will have the rtl for the dynamic chunks
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'rtl-css-loader'),
}
This is why we have a dev and a prod config:
- in dev we use the
style-loader
with thertl-css-loader
, noextract-text-plugin
. The css/rtl-css is used according to thedir
attribute. - in prod we use the
extract-text-plugin
with thewebpack-rtl-plugin
then we handle which css to load ourself server-side.
Thank you for your answer! It was very clear and I've learned now that style-loader
is bypassed by the extract-text-plugin
when the styles are not dynamic :)
My configuration is:
module: {
loaders: [
{
test: /\.s(a|c)ss$/,
loader: ExtractTextPlugin.extract('style', 'rtl-css!sass'),
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'rtl-css'),
},
],
},
plugins: [
new HtmlWebpackPlugin({ template: 'src/index.html' }),
new ExtractTextPlugin('styles.css'),
],
So according to what you say, let's assume I'll split my configuration to dev and prod, and in dev I'll remove the extract-text-plugin
and in prod I'll use webpack-rtl-plugin
then the options I have are:
- Build a server that will serve a different HTML to different directions
- Implementing integration between
webpack-rtl-plugin
andhtml-webpack-plugin
as I suggested above that will generate two static HTMLs and I'll serve them in different routes.
I've never used the html-webpack-plugin
, I'll have to check it out to see how it can work with it.
I think using a different configuration for dev and prod is pretty great and most people do it, as it allows you to use plugins on one environment only, like uglify or all the webpack dev server / hmr stuff.
IMO the bundle containing the regular and rtl css would be doable only if we can generate only a diff of what needs to change. I'm not fan of this solution anyway because it makes the bundle bigger for all users, even though the proportion of users that switch from a ltr to a rtl language may be very small.
I think the best way would be to achieve all this would be to pass options to the plugin:
- one option to determine the condition between ltr and rtl (that would be for the
rtl-css-loader
) - one option so the rtl file only includes the diff between ltr and rtl. I have no idea how postcss works if it can be useful in this case. And if not I'd have to parse the css and whatnot to do this, so maybe not easy.
- one option so the rtl is included in the same file in the end. This would need to prefix a root element with a class or something so once again we need to parse the css to add that prefix to all selector.
So that's a lot of work :)
I'll probably write a blog post about our setup at Dailymotion for all this to make it more clear how we use both packages :)
If you don't use html-webpack-plugin
then how do you add a fingerprint (hash) to the js / css filenames ?
It is indeed a lot of work.
I'm working now on separating my dev / prod configs, so in dev I can use rtl-css-loader
as you suggested.
Regarding prod I'll use webpack-rtl-plugin
but that means I need to have two different index.html, so IMHO integrating it with html-webpack-plugin
is the most important task because I need the two index.html files to include the correct fingerprint, the rest are nice features but if I'm gonna serve different html they are less important.
For dev we don't use hashes so there's no issue, and for prod we use a module (not open source for now) that generates multiple bundles for each language, and creates a json file with the name of all the files. You can use the assets-webpack-plugin that does a similar thing, it will output a json file with the name and path of the files.
I'll check the html-webpack-plugin
asap.
I've made a quick example app using both modules for dev/prod if it can help :) https://github.com/romainberger/webpack-rtl-example
Awesome!
So I removed the html-webpack-plugin
and I serve the index.html
/ index.rtl.html
from my server as you suggested. Assuming that assets-webpack-plugin
will give me everything I need with the hashes this solution works pretty well!
Thanks a lot for your time and your help! 👍
BTW, I still didn't split my dev / prod configuration and I still use the extract-text-plugin
with webpack-rtl-plugin
in dev and it seem to work well with the hot reload and everything...
Is there any special reason for me to use rtl-css-loader
in that case ?