FountainJS / generator-fountain-webapp

Yeoman 'fountain' generator to start a webapp
http://fountainjs.io
MIT License
963 stars 67 forks source link

Full page reload when change SCSS file #120

Open zarv1k opened 8 years ago

zarv1k commented 8 years ago

Any change of SCSS file causes full page reload. Is it possible to make css injection without page reload during development by default? Thank you.

Config

{
  "generator-fountain-angular1": {
    "version": "0.7.1",
    "props": {
      "framework": "angular1",
      "modules": "webpack",
      "js": "typescript",
      "ci": [
        "travis"
      ],
      "css": "scss",
      "resolved": "/usr/local/lib/node_modules/generator-fountain-webapp/node_modules/generator-fountain-angular1/generators/app/index.js",
      "namespace": "fountain-angular1",
      "argv": {
        "remain": [],
        "cooked": [],
        "original": []
      },
      "sample": "hello",
      "router": "uirouter"
    }
  }
}

Environment

Tell us which operating system you are using, as well as which versions of Node.js, npm, and yo. Run the following to get it quickly:

Node.js v5.6.0
darwin 15.6.0
yo --version
1.8.4
npm --version
3.6.0
Swiip commented 7 years ago

I noticed this too. Don't really understand why. Must look deeper

wojciechpolak commented 7 years ago

In the gulp_tasks/styles.js just change the last line:

.pipe(browserSync.stream());

to

.pipe(browserSync.stream({match: "**/*.css"}));

This will restore injecting the styles instead of full page reloads.

Toub commented 7 years ago

Thanks @wojciechpolak, your solution is probably good for projects without webpack.

With Webpack, a similar issue is discussed here: https://github.com/Va1/browser-sync-webpack-plugin/issues/4

They suggest to use webpack-dev-server, which provide hot module replacement:

Each mode also supports Hot Module Replacement. In Hot Module replacement, the bundle is notified that a change happened (rather than a full page reload). A Hot Module Replacement runtime could then load the updated modules and inject them into a running app.

To use it over browsersync, use browser-sync-webpack-plugin which can be configured to proxy to webpack-dev-server.

var BrowserSyncPlugin = require('browser-sync-webpack-plugin');

module.exports = {
    server: server,
    open: false,
    plugins: [
      new BrowserSyncPlugin(
        // BrowserSync options
        {
          // browse to http://localhost:3000/ during development
          host: 'localhost',
          port: 3000,
          // proxy the Webpack Dev Server endpoint
          // (which should be serving on http://localhost:3100/)
          // through BrowserSync
          proxy: 'http://localhost:3100/'
        },
        // plugin options
        {
          // prevent BrowserSync from reloading the page
          // and let Webpack Dev Server take care of this
          reload: false
        }
      )
    ]
  }
Toub commented 7 years ago

By the way, webpack-dev-server is used by angular cli.

We can see the script who generates the config here: https://github.com/angular/angular-cli/blob/master/packages/angular-cli/tasks/serve-webpack.ts

    const webpackDevServerConfiguration: IWebpackDevServerConfigurationOptions = {
      contentBase: path.resolve(
        this.project.root,
        `./${CliConfig.fromProject().config.apps[0].root}`
      ),
      historyApiFallback: {
        disableDotRule: true,
      },
      stats: webpackDevServerOutputOptions,
      inline: true,
      proxy: proxyConfig,
      compress: commandOptions.target === 'production',
      watchOptions: {
        poll: CliConfig.fromProject().config.defaults.poll
      },
      https: commandOptions.ssl
    };
orzarchi commented 7 years ago

Since running two different webservers just to hot reload some css seemed like overkill to me, I solved it differently (I use the derived generator-fountain-angular1 with webpack):

1) I've used the webpack ExtractTextPlugin in my dev webpack config, just like the dist config. This creates a dedicated css file in my .tmp folder. 2) I've passed the emitted files from webpack.watch callback to browsersync.reload() function:

const changedFiles = stats.toJson({ assets: true })
                        .assets
                        .filter(x=>x.emitted && !x.name.includes('.map'))
                        .map(x=>x.name);
browsersync.reload(changedFiles);

The result: when only scss files change, they are injected. otherwise, reload the whole page as normal.

stephengardner commented 7 years ago

+1

IdanCo commented 7 years ago

@orzarchi great tip, i had to do one change to make it work -

in webpack-dist.conf.js the line goes

new ExtractTextPlugin('index-[contenthash].css'),

but for this to work in webpack.conf.js i had to change to

new ExtractTextPlugin('styles.css'),
orzarchi commented 7 years ago

Since it's been a few months since this issue was opened, maybe the maintainers should adopt one of the solutions? @Swiip As I see it the options are: 1) Disable browsersync when using webpack with the generator, and use webpack-dev-server instead. Will be awsesome if it works, since there will be one less tool to worry about. Also Webpack+webpack dev server is the obvious combination. This will probably complicate the generator code the most though. 2) Use the workaround I posted above to integrate the webpack watch callback with browsersync. I've been using it for two months and everything works great.

Just don't use webpack dev server and browsersync in tandem! That will really be a tool overload.

rmckeel commented 6 years ago

@orzarchi Brilliant and simple solution. I had been searching / trying things, but intercepting changed files was exactly what the doctor called for. Thank you!