Skip to content
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

Attribute selector with space is being remove #392

Closed
Akumzy opened this issue Apr 22, 2020 · 7 comments
Closed

Attribute selector with space is being remove #392

Akumzy opened this issue Apr 22, 2020 · 7 comments
Labels

Comments

@Akumzy
Copy link

Akumzy commented Apr 22, 2020

Attribute selectors with space are being removed like

Code

[class*=' icon-'],
[class^='icon-'] {
  font-family: 'icomoon' !important;
}

Expected Behaviour

[class*=' icon-'],
[class^='icon-'] {
  font-family: 'icomoon' !important;
}

Actual Behaviour

[class^='icon-'] {
  font-family: 'icomoon' !important;
}
@Akumzy Akumzy closed this as completed Apr 22, 2020
@f-liva
Copy link

f-liva commented Jun 10, 2020

Why closed? Still occurs!

@Akumzy
Copy link
Author

Akumzy commented Jun 10, 2020

@f-liva I can't remember why I closed it either

@Akumzy Akumzy reopened this Jun 10, 2020
@f-liva
Copy link

f-liva commented Jun 10, 2020

The issue is still alive, attribute selectors with space also trying to whitelist with patterns

@ivanange
Copy link

ivanange commented Sep 26, 2020

I too have a similar issue some styles are removed while others aren't, actually using the webpack plugin with gulp to specify different purge whitelist files per entry.

gulpfile.ts

import { series, parallel, src, dest } from "gulp";

const rm = require("rimraf");
const imagemin = require("gulp-imagemin");
// const _ = require("lodash");
const fs = require("fs");
const glob = require("glob");
const webpack = require("webpack");
const prod = require("./webpack.prod");
const exec = require("child_process").exec;

const ASSETS_DIR: string = `./src/assets`;
const DIST: string = `./dist`;
const ENTRIES: Array<{
  [index: string]: string[];
}> = require("./deps").default;

/**
 * delete dist directory
 *
 * @param cb
 */
function clean(cb: () => void) {
  rm(DIST, cb);
}

/**
 * bundle npm + tailwind assets
 *
 * @param cb
 */

function bundle(cb: () => void) {
  let compiler = webpack(
    ENTRIES.map((entry) => {
      let config = prod(entry);
      // console.log(config);
      return config;
    })
  );

  compiler.run((err, stats) => {
    console.log(stats.toJson("verbose"));
    cb();
  });

  // compiler.run(cb);
}

/**
 * Update bundle.json with new file names
 *
 * @param cb
 */

function UpdateBundleInfo(cb: () => void) {
  glob(`${DIST}/assets/bundles/**/*.@(js|css)`, { nodir: true }, function (
    err,
    files
  ) {
    let bundle = files.reduce(
      (acc, file: string) => {
        if (file.match("/css/")) {
          // css file
          let radical = getRadical(file);
          acc.css[radical] = file.replace("./dist", "");
        } else {
          // js file
          let radical = getRadical(file);
          acc.js[radical] = file.replace("./dist", "");
        }
        return acc;
      },
      {
        css: {},
        js: {},
      }
    );

    fs.writeFile("./src/_data/bundle.json", JSON.stringify(bundle), cb);
  });
}

/**
 * Optimize images
 *
 * @param cb
 */
function optimizeImages() {
  return src("src/assets/img/**")
    .pipe(imagemin())
    .pipe(dest("dist/assets/img/"));
}

/**
 * Generate site
 *
 * @param cb
 */
function buildSite(cb: () => void) {
  exec("npm run build:11ty", cb);
}

/**
 * Run tests
 *
 * @param cb
 */
function test(cb: () => void) {
  cb();
}

/**
 * Run all finishing stuff
 *
 * @param cb
 */
function deploy(cb: () => void) {
  // delete public dir
  rm(`public`, function () {
    // rename dist to public
    fs.rename(DIST, "public", cb);
  });
}

function getRadical(file: string): string {
  return file.replace(/.+\/([^\/\\\.]+)\..+$/g, "$1");
}

function onError(error, cb) {
  // log error
  console.log(error);
  fs.writeFile("./log", JSON.stringify(error), function (err) {
    //restore dist.old to dist
    fs.rename(`${DIST}.old`, DIST, cb);
  });
}

exports.default = series(
  clean,
  parallel(
    series(bundle, UpdateBundleInfo, buildSite, test)
    // optimizeImages
  ),
  deploy
);

webpack.common.js

/* eslint-disable no-var, strict, prefer-arrow-callback */
"use strict";

var path = require("path");

module.exports = {
  entry: {
    index: "./src/assets/bundles/js/index.ts",
    article: "./src/assets/bundles/js/article.ts",
    about: "./src/assets/bundles/js/about.ts",
  },
  module: {
    rules: [{
        test: /\.ts(x?)$/,
        exclude: /node_modules/,
        use: [{
            loader: "babel-loader",
          },
          {
            loader: "ts-loader",
          },
        ],
      },
      {
        test: /\.js$/i,
        exclude: /node_modules/,
        use: [{
          loader: "babel-loader",
        }, ],
      },
      {
        test: /\.html$/i,
        use: [
          "file-loader?name=[name].[ext]",
          "extract-loader",
          {
            loader: "html-loader",
            options: {
              attributes: false,
              minimize: true,
            },
          },
        ],
      },
      {
        test: /\.pug$/i,
        use: [
          "file-loader?name=[name].[ext]",
          "extract-loader",
          {
            loader: "html-loader",
            options: {
              attributes: false,
              minimize: true,
            },
          },
          {
            loader: "pug-html-loader",
            options: {
              data: {},
            },
          },
        ],
      },
    ],
  },
  plugins: [],
  resolve: {
    extensions: [".ts", ".tsx", ".js"],
  },
  output: {
    filename: "js/[name].js",
    path: path.resolve(__dirname, "dist/assets/bundles"),
  },
};

webpack.prod.js

const merge = require("webpack-merge");
const common = require("./webpack.common.js");
const glob = require("glob-all");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
//const ImageminPlugin = require("imagemin-webpack-plugin").default;
//const imageminMozjpeg = require("imagemin-mozjpeg");
var path = require("path");
const PATHS = {
  src: path.join(__dirname, "src"),
};

module.exports = function (entry) {
  let fileName = Object.keys(entry)[0];
  let key = fileName.replace(/.+\/([^\/\\]+)\.[^\.]+$/g, '$1');
  return merge.smart(common, {
    mode: "production",
    entry: {
      [key]: fileName
    },
    output: {
      filename: "js/[name].[chunkhash].js",
    },
    optimization: {
      minimizer: [
        new TerserJSPlugin({}),
        new OptimizeCSSAssetsPlugin({
          cssProcessorPluginOptions: {
            preset: [
              "default",
              {
                discardComments: {
                  removeAll: true,
                },
              },
            ],
          },
        }),
      ],
    },
    module: {
      rules: [{
          test: /\.css$/i,
          use: [{
              loader: MiniCssExtractPlugin.loader,
            },
            {
              loader: "css-loader",
              options: {
                url: false,
              },
            },
            "postcss-loader",

          ],
        },
        {
          test: /\.s[ac]ss$/i,
          use: [{
              loader: MiniCssExtractPlugin.loader,
            },
            {
              loader: "css-loader",
              options: {
                url: false,
              },
            },
            "postcss-loader",

            // Compiles Sass to CSS
            'sass-loader',
          ],
        },
      ],
    },
    plugins: [
      new MiniCssExtractPlugin({
        filename: "css/[name].[contenthash].css",
        chunkFilename: "[id].css",
      }),

      new PurgecssPlugin({
        paths: glob.sync(console.log(Object.values(entry)[0]) || Object.values(entry)[0], {
          nodir: true
        }),
        whitelist: ["hide", "show"],
        whitelistPatterns: [],
        whitelistPatternsChildren: [],
        keyframes: true,
        fontFace: true,
        rejected: true,
        defaultExtractor: (content) =>
          content.match(/[\w-/:]+(?<!:)/g) || [],
        // defaultExtractor: content => {
        //   // Capture as liberally as possible, including things like `h-(screen-1.5)`
        //   const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []

        //   // Capture classes within other delimiters like .block(class="w-1/2") in Pug
        //   const innerMatches = content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || []

        //   return broadMatches.concat(innerMatches)
        // }
      }),

      new CompressionPlugin({
        filename: "[path].gz[query]",
        algorithm: "gzip",
        test: /\.js$|\.css$|\.html$/,
        minRatio: 1,
      }),

      new CompressionPlugin({
        filename: "[path].br[query]",
        algorithm: "brotliCompress",
        test: /\.(js|css|html|svg)$/,
        compressionOptions: {
          level: 11,
        },
        minRatio: 1,
      }),
    ],
  });

}

deps.js

var path = require("path");

exports.default = [{
        "./src/assets/bundles/js/index.ts": [
            "./src/index.njk",
            "./src/_includes/layouts/base.njk",
            "./src/_includes/contact.njk",
            "./src/_includes/footer.njk",
            "./src/_includes/navbar.njk",
            "./src/_includes/team.njk",
            "./src/_includes/objectives.njk",
            "./src/_includes/features_articles.njk",
            "./src/_includes/welcome.njk",
        ],
    },
    {
        "./src/assets/bundles/js/about.ts": [
            "./src/about.njk",
            "./src/_includes/layouts/base.njk",
            "./src/_includes/contact.njk",
            "./src/_includes/footer.njk",
            "./src/_includes/navbar.njk",
            "./src/_includes/team.njk",
            "./src/_includes/welcome.njk",
        ],
    },
    {
        "./src/assets/bundles/js/article.ts": [
            "./src/articles/**/*.njk",
            "./src/_includes/layouts/base.njk",
            "./src/_includes/layouts/article.njk",
            "./src/_includes/layouts/articles.njk",
            "./src/_includes/macros/embeds.njk",
            "./src/_includes/contact.njk",
            "./src/_includes/footer.njk",
            "./src/_includes/navbar.njk",
        ],
    },
]
// .map(entry => ({
//     [key = Object.keys(entry)[0]]: entry[key].map(filepath => path.resolve(__dirname, filepath))
// }));

this is the content of the src folder src.zip

I tried a little seperate test with purgecss itself and an unpurged tailwind generated css file ( dev build ) and I got the right ouput so think the issue is with the plugin beacause disabling also gives me the right output even for dev build

@ivanange
Copy link

sorry finally found out it was an error in my webpack.common.js file where I defined entry points again

@Ffloriel
Copy link
Member

v4.0.2 contains a fix to handle attribute selectors with spaces. Let me know if you are experiencing any issues.

@MartinAmsinck
Copy link

MartinAmsinck commented Jul 28, 2021

upgrading to v4.0.x didnt work for me, the solution was to upgrade vue-cli, i was running a v4 cli.
https://forum.vuejs.org/t/vue-3-postcss-8/112492

how to vue-cli Migrate from v4

{
  "dependencies": {
    "bootstrap": "^4.6.0",
    "bootstrap-icons": "^1.5.0",
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vue-class-component": "^7.2.3",
    "vue-property-decorator": "^9.1.2",
    "vue-router": "^3.2.0",
    "vuex": "^3.4.0",
    "yargs": "^17.0.1"
  },
  "devDependencies": {
    "@fullhuman/postcss-purgecss": "^4.0.3",
    "@fullhuman/vue-cli-plugin-purgecss": "~4.0.3",
    "@typescript-eslint/eslint-plugin": "^4.18.0",
    "@typescript-eslint/parser": "^4.18.0",
    "@vue/cli-plugin-babel": "^5.0.0-beta.2",
    "@vue/cli-plugin-eslint": "^5.0.0-beta.2",
    "@vue/cli-plugin-router": "^5.0.0-beta.2",
    "@vue/cli-plugin-typescript": "^5.0.0-beta.2",
    "@vue/cli-plugin-vuex": "^5.0.0-beta.2",
    "@vue/cli-service": "^5.0.0-beta.2",
    "@vue/eslint-config-typescript": "^7.0.0",
    "eslint": "^7.20.0",
    "eslint-plugin-vue": "^7.6.0",
    "node-sass": "^4.12.0",
    "sass-loader": "^8.0.2",
    "typescript": "~4.1.5",
    "vue-template-compiler": "^2.6.11"
  }
}

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

No branches or pull requests

5 participants