sysgears / webpack-virtual-modules

Webpack Virtual Modules is a webpack plugin that lets you create, modify, and delete in-memory files in a way that webpack treats them as if they were physically presented in the file system.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CSS example

AustinGil opened this issue · comments

Is there any chance you have a basic example of how I can use this to inject some CSS into my bundle?

I have it almost working, but my build never completes. Im useing webpack loader utils to generate a path like this

const cssPath = loaderUtils.interpolateName(
    this,
    '[path][name].[hash:base64:7].css',
    {
      content: 'p { text-align: center }'
    }
  );

But when I log the cssPath, it looks like it just builds onto itself

/example-project/src/styles.MINrvtm.css
/example-project/src/styles.MINrvtm.MINrvtm.css
/example-project/src/styles.MINrvtm.MINrvtm.MINrvtm.css
/example-project/src/styles.MINrvtm.MINrvtm.MINrvtm.MINrvtm.css
/example-project/src/styles.MINrvtm.MINrvtm.MINrvtm.MINrvtm.MINrvtm.css

@Stegosource Where do you use webpack-virtual-modules?

Thanks. Right now all Im trying to do is tell webpack to inject some CSS into whatever output CSS file. I've been trying to copy another project that does something similar and uses this pattern with virtual modules. My project looks something like this:

// virtualModules.js
const VirtualModulesPlugin = require('webpack-virtual-modules');
module.exports = new VirtualModulesPlugin();
// loader.js
const loaderUtils = require('loader-utils');
const virtualModules = require('./virtualModules')

async function loader(input, inputSourceMap) {
  const cssPath = loaderUtils.interpolateName(
    this,
    '[path][name].[hash:base64:7].css',
    {
      content: 'p { text-align: center }'
    }
  );

  console.log(cssPath)

  virtualModules.writeModule(cssPath, 'p { text-align: center }');

  const importLine = `import '${cssPath}';`;
  this.callback(null, importLine);
}

module.exports = loader
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const virtualModules = require('./virtualModules')

module.exports = {
  entry: {
    app: './src/index.js',
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new MiniCssExtractPlugin(),
    virtualModules,
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: path.resolve('./loader.js'),
          },
          'css-loader',
        ],
      },
    ],
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

Closing the issue, as it seems more a question than an actual issue which will be unlikely answered here

ok... :(

@AustinGil I can only propose an idea where your code does not look quite right. When in the code you do virtualModules.writeModule(cssPath, 'p { text-align: center }');, it has the same effect as writing the file - it changes the file timestamp each time and webpack sees it as a change to the file even though the contents of the file is the same. You should probably check i n the code if the contents of the file changed - and if it is not the case - avoid calling writeModule

Thanks @larixer. I actually meant that last comment kind of jokingly. Didn't mean for you to keep this open and no need to explain further. I think you're right that this was more of a question and no need to keep the issue open.

I found this issue because I was looking for an example, and think that this would be an excellent addition to the documentation. Here’s what I did (I’m using Vue CLI, so I may get some of the normal Webpack details incorrect):

// webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const VirtualModulesPlugin = require('webpack-virtual-modules')

const cssVars = Object.keys(clientTheme).map((key) => `  --component-${key}: ${clientTheme[key]};`).join('\n')
const theme = `:root {\n${cssVars}\n}\n`
const virtualModules = new VirtualModulesPlugin({ 'node_modules/theme.css': theme })

module.exports = {
  entry: {
    app: './src/index.js',
  },
  plugins: [
    new HtmlWebpackPlugin(),
    virtualModules,
    new MiniCssExtractPlugin(),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
        ],
      },
    ],
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
import Vue from 'vue'
import App from './src/App'
import 'theme.css' // <-- This does the magic

new Vue({
  el: '#app',
  render: (h) => h(App),
})

This module has let me accomplish something that I’ve been trying to do for months.

Oh that's really interesting @halostatue. Thanks for taking the time to share. I'm trying to use this in a library, so it may not work for me, but it's worth playing around with.

In any case, I think this WILL be helpful for some project in the future :)

It should work even for a library, but as a consumer of libraries where I serve with a strict CSP policy…please make sure you configure Webpack to extract the CSS into a separate file, because I disallow the use of style attributes (the default if Webpack isn’t set up for extraction).

@larixer I think that this is definitely worth adding to the README or in an example.

@halostatue To be fair I don't see how it is much different from the current example

Technically, it is the same as the current example. But there’s a conceptual break for people who don’t really understand the internals of Webpack and have to deal with it. I’ve literally spent months trying to figure out how to inject some dynamically generated CSS into my bundle (we use a single repo to generate ~10 different themed versions for different clients). This is a non-obvious solution to this particular problem to most people who are just having to work with Webpack.

The recommendation for adding this to the documentation is to make the solution to dynamic CSS injection discoverable—and I’m hoping that if it’s more discoverable, the next person in my situation, or in @AustinGil’s situation, simply has a solution available instead of having to figure it out from scratch. This plugin is spectacular in its power (and it may also help with other plug-in type problems that I have), but IMO could use a wider variety of examples of just what it can do.

Yeah, as I take a second look, I can see how this could be used for a library. Will need to test it.

I also agree that this would make a good example. I looked through this and compared to the one in the README and find this one to be intuitive. While the other is still a bit hard for me to get what's going on. That may just be me, but the example in this thread seems to make a bit more sense on what I need to do.

@AustinGil @halostatue Feel free to open PR and update current example or add CSS example next to the current one