FullHuman / purgecss

Remove unused CSS
https://purgecss.com
MIT License
7.75k stars 250 forks source link

Purgecss with Tailwindcss and Sapperjs #50

Closed ansarizafar closed 4 years ago

ansarizafar commented 6 years ago

I am trying to use Purgecss to remove unused Tailwindcss classes from a SapperJS https://sapper.svelte.technology/ application. Could you please add an example in the documentation for SapperJS.

ansarizafar commented 6 years ago

It would be great If an example of using Purgecss with hyperhtml/viperhtml https://viperhtml.js.org/ is also added to documentation.

I am trying to use Purgecss with hyperhtml and Poijs poi.js.org but it seems that Purgecss is unable to find used css in hyperhtml templates. Could someone please help me find a solution here is my repo https://github.com/ansarizafar/hyperhtml

jsnanigans commented 6 years ago

Hey, I think the problem here is that you are only including the js files immediately inside src with glob.sync('${PATHS.src}/*.js') to be recursive you should use glob.sync('${PATHS.src}/**/*.js')

ansarizafar commented 6 years ago

@jsnanigans It worked. Thanks for the solution.

jsnanigans commented 6 years ago

That's great. Ill keep this Issue open until we figure out how to use it with svelte, and maybe make a custom extractor for viperhtml or hyperhtml syntax.

ansarizafar commented 6 years ago

Any update on using Purgecss with Tailwindcss and Sapperjs?

jsnanigans commented 6 years ago

For tailwind you can follow the tailwind documentation on how to use purgeCSS here: https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css-with-purgecss

We haven't had the time to look into SapperJS yet

harryhazza77 commented 6 years ago

I'm unable to get this to work using the config below and the latest version of nuxt. @ansarizafar did you have any luck?

const PurgecssPlugin = require("purgecss-webpack-plugin");
const glob = require("glob-all");
const path = require("path");

module.exports = {
...
build: {
        extend(config, ctx) {
            // Run ESLint on save
            if (ctx.isDev && ctx.isClient) {
                config.devtool = "source-map";
                config.module.rules.push({
                    enforce: "pre",
                    test: /\.(js|vue)$/,
                    loader: "eslint-loader",
                    exclude: /(node_modules)/
                });
            }
            if (!ctx.isDev) {
                config.plugins.push(
                    new PurgecssPlugin({
                        paths: glob.sync([
                            path.join(__dirname, "./pages/**/*.vue"),
                            path.join(__dirname, "./layouts/**/*.vue"),
                            path.join(__dirname, "./components/**/*.vue")
                        ]),
                        extractors: [
                            {
                                extractor: class {
                                    static extract(content) {
                                        return content.match(/[A-z0-9-:\/]+/g) || [];
                                    }
                                },
                                extensions: ["vue"]
                            }]
                    })
                );
            }
        }
    }
};
ansarizafar commented 6 years ago

@harryhazza77 I am using uncss https://github.com/uncss/uncss

harryhazza77 commented 6 years ago

@ansarizafar believe it or not, I was just trying that out with my nuxt project without luck either :-(

harryhazza77 commented 6 years ago

Ok so i've managed to get it to work for me with the following config:

const pkg = require("./package");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const glob = require("glob-all");
const path = require("path");

module.exports = {
   ...
    css: [
        "@/assets/styles/tailwind.css"
    ],
    build: {
        extractCSS: true,
        extend(config, ctx) {
            if (!ctx.isDev) {
                config.plugins.push(
                    new PurgecssPlugin({
                        paths: glob.sync([
                            path.join(__dirname, "./pages/**/*.vue"),
                            path.join(__dirname, "./layouts/**/*.vue"),
                            path.join(__dirname, "./components/**/*.vue")
                        ]),
                        extractors: [
                            {
                                extractor: class {
                                    static extract(content) {
                                        return content.match(/[A-z0-9-:/]+/g) || [];
                                    }
                                },
                                extensions: ["vue"],
                            }
                        ],
                        whitelist: ["html", "body", "nuxt-loading"]
                    })
                );
            }
        }
    }
};
soullivaneuh commented 4 years ago

Here is my working webpack.config.js:

const webpack = require('webpack');
const path = require('path');
const config = require('sapper/config/webpack.js');
const pkg = require('./package.json');

const mode = process.env.NODE_ENV;
const dev = mode === 'development';

const alias = { svelte: path.resolve('node_modules', 'svelte') };
const extensions = ['.mjs', '.js', '.json', '.svelte', '.html', '.css'];
const mainFields = ['svelte', 'module', 'browser', 'main'];
const preprocess = {
  transformers: {
    postcss: {
      plugins: [
        require('postcss-import')(),
        require('tailwindcss')(),
        require('@fullhuman/postcss-purgecss')({
          content: ["./src/**/*.svelte", "./src/**/*.html"],
          defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
        }),
        require('autoprefixer')({ browsers: 'defaults' }),
      ],
    },
  },
};

module.exports = {
  client: {
    entry: config.client.entry(),
    output: config.client.output(),
    resolve: {
      alias,
      extensions,
      mainFields,
    },
    module: {
      rules: [
        {
          test: /\.(svelte|html)$/,
          use: {
            loader: 'svelte-loader',
            options: {
              dev,
              hydratable: true,
              hotReload: true,
              preprocess: require('svelte-preprocess')(
                preprocess,
              ),
            },
          },
        },
      ],
    },
    mode,
    plugins: [
      // pending https://github.com/sveltejs/svelte/issues/2377
      // dev && new webpack.HotModuleReplacementPlugin(),
      new webpack.DefinePlugin({
        'process.browser': true,
        'process.env.NODE_ENV': JSON.stringify(mode),
      }),
    ].filter(Boolean),
    devtool: dev && 'inline-source-map',
  },

  server: {
    entry: config.server.entry(),
    output: config.server.output(),
    target: 'node',
    resolve: {
      alias,
      extensions,
      mainFields,
    },
    externals: Object.keys(pkg.dependencies).concat('encoding'),
    module: {
      rules: [
        {
          test: /\.(svelte|html)$/,
          use: {
            loader: 'svelte-loader',
            options: {
              css: false,
              generate: 'ssr',
              dev,
              preprocess: require('svelte-preprocess')(
                preprocess,
              ),
            },
          },
        },
      ],
    },
    mode: process.env.NODE_ENV,
    performance: {
      hints: false, // it doesn't matter if server.js is large
    },
  },

  serviceworker: {
    entry: config.serviceworker.entry(),
    output: config.serviceworker.output(),
    mode: process.env.NODE_ENV,
  },
};

For the rest, I followed up this project: https://github.com/pngwn/sapper-webpack-postcss

It partially works, but a few unused variables warnings remain:

app_1  | src/routes/index.svelte
app_1  | Module Warning (from ./node_modules/svelte-loader/index.js):
app_1  | Unused CSS selector (63:0)
app_1  | 60:  */
app_1  | 61: 
app_1  | 62: pre {
app_1  |     ^
app_1  | 63:   font-family: monospace, monospace; /* 1 */
app_1  | 64:   font-size: 1em; /* 2 */
app_1  | src/routes/index.svelte
app_1  | Module Warning (from ./node_modules/svelte-loader/index.js):
app_1  | Unused CSS selector (89:0)
app_1  | 86: 
app_1  | 87: 
app_1  | 88: strong {
app_1  |     ^
app_1  | 89:   font-weight: bolder;
app_1  | 90: }

Did I miss something?