Open weaverryan opened 7 years ago
It looks like there is a way to enable HMR for SASS compilation, using css-hot-loader
in this issue.
I'm still trying to figure out how to add it to Encore.
Interesting... I think I saw that library - https://github.com/shepherdwind/css-hot-loader - before, but it looked really low quality (even if it worked). But a lot of work has been done over the past 2 months. So, I'm curious to investigate this :).
@TheMaxoor To try this in Encore for now, you'd need to hack it a little bit. Something like this:
var config - Encore.getWebpackConfig();
// 5 is just a guess at the correct index for the .scss loader - you'll need to find out which is correct
// this is just a hack for now ;)
config.module.rules[5].use = ['css-hot-loader'].concat(config.module.rules[5].use);
module.exports = config;
That may not be 100% correct - I put it together quickly. But if you have time to try it, I'd love to know your feedback.
Cheers!
@weaverryan It's not working for me... I've adopted your lines as well as i've tested the origial variant inject the ExtractTextWebpackPlugin directly:
const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");
config.module.rules[1].use = ['css-hot-loader'].concat(ExtractTextWebpackPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader'],
}));
After that, I've updated an scss file and the recompile worked:
WAIT Compiling... 23:54:59
webpack: Compiling...
DONE Compiled successfully in 571ms 23:55:00
Hash: b058ff23a19307486590
Version: webpack 3.6.0
Time: 571ms
Asset Size Chunks Chunk Names
6fa2d9cde5b42b66ea41.hot-update.json 44 bytes [emitted]
app.js 1.71 MB 0 [emitted] [big] app
32825a78dbf5cce8faca.hot-update.json 35 bytes [emitted]
app.css 819 bytes 0 [emitted] app
manifest.json 130 bytes [emitted]
[./app/Resources/assets/shared.scss] ./app/Resources/assets/shared.scss 41 bytes {0} [built]
[./node_modules/webpack/hot ^\.\/log$] (webpack)/hot nonrecursive ^\.\/log$ 170 bytes {0} [built]
+ 90 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/index.js??ref--4-2!node_modules/resolve-url-loader/index.js??ref--4-3!node_modules/sass-loader/lib/loader.js??ref--4-4!app/Resources/assets/shared.scss:
Asset Size Chunks Chunk Names
6fa2d9cde5b42b66ea41.hot-update.json 44 bytes [emitted]
But the hot-update.json only contains the following lines
{"h":"b058ff23a19307486590","c":{}}
And the logs told me that nothing was updated:
[WDS] App updated. Recompiling...
client:80
[WDS] App hot update...
client:212
[HMR] Checking for updates on the server...
log.js:23
[HMR] Nothing hot updated.
log.js:23
[HMR] App is up to date.
log.js:23
Any idea?
@tburschka Hmm, we just need to make sure that my hack was in fact the right hack (and that it's not the problem). What happens if you console.log(config.module.rules[1].use)
? I want to make sure that looks right.
Also, did you try my hack more directly? e.g.
config.module.rules[1].use = ['css-hot-loader'].concat(config.module.rules[1].use);
What you had was probably identical to this in practice, but just in case... :)
@weaverryan i've found the solution. in my case, i'm not using .enableSassLoader()
anymore but adding the hot loader direct:
const Glob = require('glob');
const Path = require('path');
const Encore = require('@symfony/webpack-encore');
const ExtractText = require("extract-text-webpack-plugin");
const AssetsHostname = process.env.ASSETS_HOSTNAME || 'localhost';
Encore
.setOutputPath('web/static/')
.setPublicPath(Encore.isProduction() ? '/static' : 'http://' + AssetsHostname + '/static')
.setManifestKeyPrefix('/static')
.cleanupOutputBeforeBuild()
.autoProvidejQuery()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
;
Encore.createSharedEntry('shared', Glob.sync('./{app,src,vendor}/**/assets/shared.js'));
let alias = { app: Path.resolve(__dirname, 'app/Resources/assets') };
for (let entryPath of Glob.sync('./{src,vendor}/**/assets/!(shared)*.js')) {
const regex = new RegExp('/(.*\/(.*)Bundle\/Resources\/assets)\/(.*).js');
const matches = regex.exec(entryPath);
alias[(matches[2] + 'bundle').toLowerCase()] = Path.resolve(__dirname, matches[1]);
Encore.addEntry((matches[2] + matches[3]).toLowerCase(), entryPath);
}
let config = Encore.getWebpackConfig();
config.resolve.alias = Object.assign(config.resolve.alias, alias);
config.watchOptions = { poll: true, ignored: /node_modules/ };
config.devServer = {
contentBase: Path.join(__dirname, 'web'),
host: AssetsHostname,
port: 80,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
},
open: false,
overlay: true,
compress: true
};
config.module.rules.push({
test: /\.(s?c|sa)ss$/,
use: ['css-hot-loader'].concat(ExtractText.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader'],
}))
});
config.module.rules.push({
test: /\.(eot|svg|ttf|woff2?)$/,
loader: 'file-loader'
});
module.exports = config;
The second thing i've needed to to is to ensure that for javascript i've add in the specific entry point the following snipped:
if (module.hot)
module.hot.accept();
Awesome! And this works really well?
Can you tell me more about why the module.hot.accept()
is needed?
It's documented here https://webpack.js.org/api/hot-module-replacement/#accept but you can find lot of examples on stackoverflow...
What about the integration of this inside encore ? With Vuejs, it really lacks styles update.
It's on the TODO list :). HMR has some complexities because we always dump .css
files, even in dev, instead of using the style-loader
trick. That gives us consistency across environments (you always get styles from real .css
files). But, we need to do some extra work to get HMR rocking.
Hey I know it's been a while, but I was stressed that HMR didn't work for style, so I went take a look around and came up with this solution,
const Encore = require('@symfony/webpack-encore');
Encore
// .... your config here
// You have to disable the sass loader
// .enableSassLoader()
// enable source maps during development
// I didn't try without it
.enableSourceMaps(!Encore.isProduction())
.enableVueLoader(function(options) {
options.loaders['scss'] = ['vue-style-loader',
{loader: 'css-loader', options: {sourceMap: true}}, //Probably should change here with (!Encore.isProduction())
{loader: 'sass-loader', options: {sourceMap: true}}
];
options.loaders['sass'] = options.loaders['scss'];
})
You need to disable the Encore sassLoader then force let the vue-style-loader taking care of the style. It works for my project but I wanna know if that could work for an another project :)
Yea, that's pretty valid... basically HMR doesn't work with the css-loader, but works fine (and is intended for) the normal style-loader. We chose to use the css-loader consistently, because I think it's a bit weird to not need link
tags in dev, but suddenly need them in production. But, this is totally valid
And, it does highlight a second possible approach to HMR: allow people to opt in to disabling the css-loader in dev... which would make HMR for styles just, work (basically an option to do what you're doing).
Anyone have luck getting it to work with LESS?
I tried modifying @henri-ly's approach, but no go...
@weaverryan have you taken a look at this project: https://github.com/man27382210/watchFile-webpack-plugin I'm not sure if I fully understand the issue, but if I did, this should be able to also use it for all kind of files (including changes in twig I think, not sure how the recompiling would be handled there though)
Just fixed it like this:
const webpackConfig = Encore.getWebpackConfig()
for (let rule of webpackConfig.module.rules) {
if (rule.test.toString() === '/\\.vue$/') {
rule.use = ['css-hot-loader'].concat(rule.use)
}
}
@Grawl Vue seems to manage HMR directly with webpack 4. So the only thing to do for me is this:
for (const rule of config.module.rules) {
if (rule.test.toString() === '/\\.s[ac]ss$/') {
rule.use = ['css-hot-loader'].concat(rule.use);
}
}
@Soullivaneuh cool! So it's time to upgrade to v0.21.0
or latest version of Encore
Starting with 0.24 the above concat based solutions had to be updated a little to this at least for me:
for (const rule of config.module.rules) {
if (rule.test.toString() === '/\\.s[ac]ss$/') {
rule.oneOf.forEach(function(i) {
i.use = ['css-hot-loader'].concat(i.use);
})
}
}
Following this change: https://github.com/symfony/webpack-encore/pull/508/files#diff-8beacd21a12ca072bafa4e8e3f1aae6b
need hmr css please
@ohot2015 You can already use it by calling disableCssExtraction()
and then running yarn encore dev-server --hot
:
if (Encore.isDevServer()) {
Encore.disableCssExtraction();
}
There is a PR that could make it work with the CSS extraction enabled, but it's kinda stuck because it leads to inconsistent hashes in filenames.
We should document this... and maybe also make disableCssExtraction()
have a boolean first argument so you can use Encore.disableCssExtraction(Encore.isDevServer)
Hey Guys, so what is required to make this work with CSS?
@aniolekx: Hey Guys, so what is required to make this work with CSS?
Use dev server and disable CSS extraction. That's all. See https://github.com/symfony/webpack-encore/issues/3#issuecomment-487617913
@aniolekx: Hey Guys, so what is required to make this work with CSS?
Use dev server and disable CSS extraction. That's all. See #3 (comment)
and what about Sass loader?
Works for me as well.
пт, 25 окт. 2019 г. в 15:07, aniolekx notifications@github.com:
@aniolekx https://github.com/aniolekx: Hey Guys, so what is required to make this work with CSS?
Use dev server and disable CSS extraction. That's all. See #3 (comment) https://github.com/symfony/webpack-encore/issues/3#issuecomment-487617913
and what about Sass loader?
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/symfony/webpack-encore/issues/3?email_source=notifications&email_token=AACMMF2DVUQ3XZLOFYNBWPLQQJ5IDA5CNFSM4DO56ZT2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECHGH4A#issuecomment-546202608, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACMMF2F6NULOAFFJLKLXATQQJ5IDANCNFSM4DO56ZTQ .
-- Анатолий Пашин.
and what about Sass loader?
@aniolekx it does work with Sass loader for me.
Has anyone got this working on webpack 5? As I found, mini-css-extract-plugin supports HMR w/ webpack 5 so disableCssExtraction()
isn't needed anymore.
Does Symfony with Webpack Encore support HMR for React? Everyone talks about Vue here 😅
Thank you for this suggestion. There has not been a lot of activity here for a while. Would you still like to see this feature? Every feature is developed by the community. Perhaps someone would like to try? You can read how to contribute to get started.
This should be easily possible for React and Vue.js (at least). It's not currently possible with CSS, because we're using ExtractTextWebpackPlugin all the time.