Skip to content

Extract CSS from SCSS and deferred lazy load into app #105

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

Closed
fillippeyton opened this issue Apr 20, 2018 · 12 comments
Closed

Extract CSS from SCSS and deferred lazy load into app #105

fillippeyton opened this issue Apr 20, 2018 · 12 comments

Comments

@fillippeyton
Copy link

fillippeyton commented Apr 20, 2018

I have a few SCSS theme files I want to extract to CSS files and later load them into the page. I want to be able to use contenthash for long term caching.

Since I'm using Webpack 4, I am using mini-css-extract-plugin. I started down the path of creating a splitChunks in my webpack config.

// webpack.config.js
module.exports = {
  plugins: [
      new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: "[name].[contenthash].css",
      chunkFilename: "[id].[contenthash].css"
    })
  ],
  optimization: {
    splitChunks: {
      cacheGroups: {
        'theme-a': {
            test: /theme-a.\scss/,
        },
        'theme-b': {
            test: /theme-b.\scss/,
        },
        // more themes
      }
    }
  }
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader"
        ]
      }
    ]
  }
}

I've then tried dynamically importing the css in my app:

// app.js
class App extends React.Component {
  // constructor

  login(themeName) {
    import(/* webpackChunkName: "`${themeName}`" */ `./path/to/${themeName}.scss`).then(theme => {
      // do something with `theme`
    }
  }
  
  // other stuff
}

I need to be able to load that css file dynamically in login() and I'm just not sure how to reference it when it has a generated [contenthash]. Is there a good way to reference the split css chunks in my app when using mini-css-extract-plugin?

@fillippeyton
Copy link
Author

Related issue: #94

@fillippeyton
Copy link
Author

@alexander-akait
Copy link
Member

alexander-akait commented May 11, 2018

@johnelliott how this issue related to your problem? use [contenthash] for long term caching, also writing your problems in other issues without actual/expected/minimum reproducible test repo will not help in solving your problem

@alexander-akait
Copy link
Member

alexander-akait commented May 11, 2018

@fillippeyton sorry i can't help your here, please create new issue with minimum reproducible test repo and what you have and what you expected and description. Why do I ask to do this? Because we have hundreds of requests (issues and PRы) and it takes a lot of time, the more accurately you can formulate the problem and demonstrate it using a small configuration, the sooner your problem will be solved or you can start investigating problem yourself and send us PR

@fillippeyton
Copy link
Author

@johnelliott The solution I've come up with is using extract-text-webpack-plugin and creating a "theme manifest" injected into my HtmlWebpackPlugin template. I then reference that on login() and inject a "theme" link into the <head> like <link href="theme-a.css" />. Here's my related SO post: https://stackoverflow.com/a/49993381/401393

I would love to dynamically import these via a named import or some way that feels less hacky.

@alexander-akait
Copy link
Member

@fillippeyton can we close issue?

@johnelliott
Copy link

johnelliott commented May 14, 2018

@fillippeyton my solution was to use the extract-loader and file-loader after the css-loader. From there I would conditionally emit the file on the client or server webpack config and have the output file name be the content hash. This would allow me to import the file name on disk in both server and client.

Then in the client when the webpack mode is development I would use the style-loader instead of the extract-loader and file-loader chain.

I realize it’s a bit difficult to describe some of these configurations without some code to look at. :/

@fillippeyton
Copy link
Author

Appreciate the effort looking into this @johnelliott ! I'll take a swing at that solution when I have some time.

@danburzo
Copy link

@johnelliott thank you for the idea! Would you be able to share your setup? I'm looking into doing something similar, and would greatly appreciate it.

@johnelliott
Copy link

@danburzo I’m working until 6pm EST but I’ll follow up. Gotta find the branch too :p

@danburzo
Copy link

danburzo commented Aug 24, 2018

Thank you @johnelliott for the idea! I was able to adapt it to suit our needs, like below. (It actually ended up not using mini-css-extract-plugin).

webpack.config.js

module: {
  rules: {
	// Font stylesheets
	{
		test: /\.css$/,
		use: [
			{
				loader: 'file-loader',
				options: {
					name: config.local ? 'css/[name].[ext]' : 'css/[hash].[ext]'
				}
			},
			'extract-loader',
			'css-loader',
			'postcss-loader'
		],
		include: [/fonts/]
	},

	// Font files
	{
		test: /\.(woff|woff2|ttf|otf)$/,
		loader: 'file-loader',
		include: [/fonts/],

		// awkward path config to make everything work
		// See: https://github.com/webpack-contrib/file-loader/issues/261
		options: {
			name: config.local ? '[name].[ext]' : '[hash].[ext]',
			outputPath: 'css/',
			publicPath: '../css/'
		}
	},
  }
}

With this setup:

postcss-loader > css-loader > extract-loader > file-loader

I am able to have individual, content-hashed CSS files whose URLs I can obtain in the JS code with require('fonts/somefont/style.css'), and the files themselves are plain CSS.

@johnelliott
Copy link

Good to hear Dan :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants