Closed husayt closed 6 years ago
Purgecss can't read the selectors inside the components that come from vuetify, A workaround would be to add the vuetify components into the paths
option. Although this would keep a lot of unused css from vuetify, at least it would not break your layout.
Thia could work with vuetify's a-la-carte option. Do I just add paths to vuetify components in nodeModules?
I have not tested it myself but yes, that should work. Let me know if you have any issues with that
@jsnanigans I tried it many times and it still didn't work
@husayt I'm very sorry but I have no other solution for you. I am currently also working on a project where I use Vuetify and am not using purgecss.
When the purgecss-loader
for webpack will be done, this problem will be solved but until then the only solution I can think of is to include the vue templates from vuetify itself.
@jsnanigans @Ffloriel layout also breaks with nuxt and bootstrap-vue as many classes get wrongly purged
Is purgecss-loader planned to release soon?
@husayt I got purgecss to work with vuetify with this configuration:
paths = glob.sync(
[
path.join(__dirname, '../src/**/*.vue'),
path.join(__dirname, '../index.html'),
path.join(__dirname, '../node_modules/vuetify/src/**/*.js'),
]
).filter(function(f) { return !/\/$/.test(f); })
however this includes all of vuetify and will not purge css for components you don't use, but maybe you can fiddle with path.join(__dirname, '../node_modules/vuetify/src/**/*.js')
and only include the components that you use, just be careful because for example VBtn
includes VProgressCircular
which intern includes ../../mixins/colorable
so you'll neet to add all three of those just to keep the styles for v-btn
, and even then all the btn--*
classes will persist.
@syffs I have not tested this with bootstrap-vue but the structure looks very similar.
is sadly nowhere near being released, in fact development has not even really began. but this will solve this issue once and for all because the idea is to tap into webpack compile step and get the content html and the css straight from there.
Ill close this issue because with proper configuration it can work, let me know if you need some more help.
@jsnanigans thanks for the explanation. I've tried adapting your suggestion to bootstrap-vue
:
if (!isDev) {
config.plugins.push(
new PurgecssPlugin({
paths: glob.sync([
path.join(__dirname, './pages/**/*.vue'),
path.join(__dirname, './layouts/**/*.vue'),
path.join(__dirname, './components/**/*.vue'),
path.join(__dirname, './node_modules/bootstrap-vue/src/**/*.js')
]).filter(function (f) { return !/\/$/.test(f) }),
whitelist: ['html', 'body']
})
)
}
for some reason, the layout still breaks
@syffs you could try to put your paths into a variable on top of the .js file, then console.log() them out, like this you can see if the files are actually inclduded
@jsnanigans good idea! no problem with the paths though, list is quite huge and bootstrap-vue
files are well listed:
...
'./node_modules/bootstrap-vue/src/components/button-group/fixtures/button-group.js',
'./node_modules/bootstrap-vue/src/components/button-group/index.js',
'./node_modules/bootstrap-vue/src/components/button-toolbar/button-toolbar.js',
'./node_modules/bootstrap-vue/src/components/button-toolbar/button-toolbar.spec.js',
'./node_modules/bootstrap-vue/src/components/button-toolbar/fixtures/button-toolbar.js',
'./node_modules/bootstrap-vue/src/components/button-toolbar/index.js',
'./node_modules/bootstrap-vue/src/components/button/button-close.js',
'./node_modules/bootstrap-vue/src/components/button/button-close.spec.js',
'./node_modules/bootstrap-vue/src/components/button/button.js',
...
FYI, if anybody wants to get this working with Vue CLI 3, CSS modules and Bootstrap Vue, you can add the plugin to vue.config.js
:
const glob = require("glob-all");
const path = require("path");
module.exports = {
configureWebpack: {
plugins: [
new PurgecssPlugin({
whitelistPatterns: [/^_/], // Don't remove classes with underscore prefix
paths: glob.sync([
path.join(__dirname, "/src/**/*.vue"),
path.join(__dirname, "/src/**/*.js")
])
}),
new CompressionPlugin()
]
},
css: {
loaderOptions: {
css: {
localIdentName: "_[name]-[hash]" // Prefix CSS modules with _ so we can whilelist them
}
}
}
};
For Bootstrap Vue, you need to a add more whitelist items for dynamically generated classes that are not present in the Bootstrap Vue source files. An examples of this is button variants, eg. variant="dark"
dynamically generates .btn-dark
. The same applies to some responsive classes where you specify the breakpoint on the component as a prop, eg. toggleable="sm"
, which dynamically generates classes like .navbar-expand-md
. To get around this, you can whitelist generated classes with whiteListPattern
, eg:
whitelistPatterns: [/(nav).*/, /(btn).*/]
whitelistPatterns: [/(nav)./, /(btn)./]
@constantm Your solution and pattern worked for me like a charm. I am using Laravel-Mix, which is a wrapper around webpack.
For anyone with my setup, this was how I got the path:
path.join(__dirname, 'node_modules/bootstrap-vue/src/**/**/*.js')
While my whitelist pattern looks like this:
whitelistPatterns: [/(nav).*/,/(bg).*/, /(btn).*/],
For BootstrapVue, you probably also want to white list the following:
/(col).*/
(column layout)/(text).*/
(text alignment, colors)/(border).*/
(border colors, sizes)/(table).*/, /(b-table).*/
(tables)/(alert).*/
(alerts and alert variants)/(d-).*/
(display utilities)Another alternative is to just include the appropriate Bootstrap v4.3 SCSS files needed (i.e. utilities, grid, table, etc)
This works for Vuetify ^2.1.0
module.exports = { "transpileDependencies": [ "vuetify" ], configureWebpack: { plugins: [ new PurgecssPlugin({ paths: glob.sync([ path.join(__dirname, './public/index.html'), path.join(__dirname, './**/*.vue'), path.join(__dirname, './src/**/*.js'), path.join(__dirname, './node_modules/vuetify/src/**/*.ts'), ]) }) ] } }
@lukakoczorowski what file is that?
I've just tried adding nuxt-purgecss
to a Nuxt + Vuetify application and everything broke as all Vuetify CSS classes got purged.
@lobo-tuerto that is vue.config.js If you want to use it in nuxt.config.js, add the same directories to the paths module option.
I managed to remove a lot of unused CSS in my Nuxt + Vuetify + Tailwind app. It took me a while to figure out but I ended adding these options to my purgeCSS configuration which matched my requirements pretty nicely.
whitelist: ['v-application', 'v-application--wrap'],
whitelistPatterns: [/^v-((?!application).)*$/, /^theme--*/, /.*-transition/],
whitelistPatternsChildren: [/^v-((?!application).)*$/, /^theme--*/],
I basically wanted to get rid of all v-application--is-rtl
classes plus all vuetify utility classes and use tailwinds. My CSS is now ~83kb rather than ~245kb. You could also whitelist just theme--light
if you would like to remove the dark theme styles.
I did also disable $color-pack
. https://vuetifyjs.com/en/styles/colors/#sass-color-pack
$color-pack: false;
my nuxt config with vuetify 2
buildModules: [ '@nuxtjs/vuetify', [ 'nuxt-purgecss', { paths: ['/node_modules/vuetify/src/**/*.ts'], }, ], ], PurgeCSS: { whitelist: ['v-application', 'v-application--wrap'], whitelistPatterns: [/^v-((?!application).)*$/, /^theme--*/, /.*-transition/], whitelistPatternsChildren: [/^v-((?!application).)*$/, /^theme--*/], },
@IsraelOrtuno I tried your method but it strips away too much. Somehow not all classes that are captured by the whitelistPattens regex are preserved. I created a minimal repo here: https://github.com/patrickxchong/nuxt-vuetify-purgecss and you can see how it looks right now here: https://nuxt-vuetify-purgecss.now.sh. I hope that either you or someone else can help me figure out what's wrong :pray:
@sovofeel I tried your method as well but it didn't strip away the css classes that I don't need such as v-application--is-rtl
and theme--dark
(I tried intentionally whitelisting only theme--light). I'm not too sure why but I think it has to do with declaring module options both within buildModules section and the nuxt.config object.
@patrickxchong since tailwind handles purgeCSS (last version I believe) itself this stopped working
I was trying to get vuetify and purgeCSS to play nicely together first, I've not tried adding tailwind to the mix (I'm using tailwind for another project and I did get the recent update that integrates purgeCSS as well).
I did realize that one reason why it wasn't working was because I copied the line posted by @sovofeel initially but it was using PurgeCSS instead of purgeCSS, that's why it wasn't working (no offense @sovofeel intended, just wanted to make sure that people are aware of the typo).
I fixed the typo and the whitelist is working pretty well now, but it's still a little wonky (there are some things off with the UI) so I'll give an update here once I figure that out.
Just an update for anyone who may be interested to get Vuetify and purgeCSS working together: If you use the whitelist shared by @IsraelOrtuno, it works well in really stripping away a lot of the unnecessary vuetify classes. However, they do strip a little too much away, particularly css that targets tags that are used within vuetify such as input and button, so the input of purgeCSS can look quite ugly: https://nuxt-vuetify-purgecss-3srh60r82.now.sh/.
To deal with that, the best way I can think of is for one to dig around, find out what's missing/looks weird, and whitelist the required tags/classes/attribute selectors. This is how the site looks after whitelisting input, button and spacer: https://nuxt-vuetify-purgecss.now.sh
@sovofeel I think I understand why your approach doesn't work with stripping away the classes, I believe by including all Vuetify components in paths
, you're essentially telling purgeCSS to consider that you're using all the Vuetify components and to not purge any of the classes used by them.
The reason I wanted to add PurgeCSS to my Vuetify app was to be able to add TailwindCSS to the mix. Now with the lastest TailwindCSS version there is no need to do that because it includes a preconfigured PurgeCSS that just works and doesn't mess up your Vuetify classes anymore.
@lobo-tuerto does that automatic purge coming from new tailwind purge vuetify's unused classes?
@IsraelOrtuno No, only Tailwind's own classes. But now you don't have to worry about whitelisting Vuetify or other CSS classes or fear having them wiped out.
Just an update for anyone who may be interested to get Vuetify and purgeCSS working together: If you use the whitelist shared by @IsraelOrtuno, it works well in really stripping away a lot of the unnecessary vuetify classes. However, they do strip a little too much away, particularly css that targets tags that are used within vuetify such as input and button, so the input of purgeCSS can look quite ugly: https://nuxt-vuetify-purgecss-3srh60r82.now.sh/.
To deal with that, the best way I can think of is for one to dig around, find out what's missing/looks weird, and whitelist the required tags/classes/attribute selectors. This is how the site looks after whitelisting input, button and spacer: https://nuxt-vuetify-purgecss.now.sh
@sovofeel I think I understand why your approach doesn't work with stripping away the classes, I believe by including all Vuetify components in
paths
, you're essentially telling purgeCSS to consider that you're using all the Vuetify components and to not purge any of the classes used by them.
Can you share an update on @sovofeel 's method which includes input button and spacer and other stuff that you might have found not working?
thank you
@stephenjason89 I decided to revisit how I used PurgeCSS and changed things up a little. I used @fullhuman/postcss-purgecss as a PostCSS plugin on Nuxt and combined it with another PostCSS plugin (css-byebye) and got the CSS file size down by a LOT without requiring too much manual whitelisting labor (you do have manually whitelist the transition classes used).
Attached is the Nuxt build configuration that I used, you can see the full configuration in the demo here: https://github.com/patrickxchong/nuxt-vuetify-purgecss
/*
** Build configuration
*/
build: {
extractCSS: true,
postcss: {
plugins: {
"@fullhuman/postcss-purgecss": {
content: [
'components/**/*.vue',
'layouts/**/*.vue',
'pages/**/*.vue',
'plugins/**/*.js',
'node_modules/vuetify/src/**/*.ts',
],
styleExtensions: ['.css'],
safelist: {
standard: ["body", "html", "nuxt-progress"],
deep: [
/page-enter/,
/page-leave/,
/dialog-transition/,
/tab-transition/,
/tab-reversetransition/
]
}
},
"css-byebye": {
rulesToRemove: [
/.*\.v-application--is-rtl.*/,
/.*\.theme--dark.*/
]
}
}
},
/*
** You can extend webpack config here
*/
extend(config, ctx) {
}
}
@patrickxchong Thank you for your work and the github link. it worked but over stripped styles. as you can see here
this is how it was supposed to look like
Am i missing something?
Basically I installed the packages (@fullhuman/postcss-purgecss & css/byebye) then copied your postcss config to my build conf
Thank you for taking the time to reply :)
This actually turned my app.css 372kb (unpacked) to 61.5kb
@stephenjason89 I checked out https://foodat.ph/ and it seems like you're writing your own custom css for row and column layouts. I suspect that PurgeCSS stripped away some of those CSS away somehow. Is there a staging environment where I can see the site with PurgeCSS enabled? Otherwise the best advice I can give you is to figure out the classes that PurgeCSS removed and add them to the safelist.
@patrickxchong I appreciate you taking the time to reply. Here's the template at the home page where you can search address
<template>
<v-card max-width="344" light rounded class="searchCard">
<v-card-text>
<p class="display-1 text--primary">Greetings</p>
<p class="display-2 text--primary">Let's explore good food near you.</p>
</v-card-text>
<v-card-actions>
<v-row>
<v-col cols="12">
<Geosearch @confirmedAddress="startShopping"></Geosearch>
</v-col>
<v-col cols="12">
<v-btn width="100%" color="orange accent-3" rounded to="cravings" :disabled="shop">
I'm Hungry!
</v-btn>
</v-col>
</v-row>
</v-card-actions>
</v-card>
</template>
and for the template of geosearch component
<template>
<div>
<v-row dense align="center">
<v-col>
<v-autocomplete
v-model="select"
light
autocomplete="new-password"
:outlined="true"
:rounded="true"
color="orange accent-3"
height="12"
:loading="isLoading"
:items="results"
:search-input.sync="search"
:filter="filterAddress"
cache-items
hide-no-data
hide-details
item-text="description"
item-value="place_id"
label="Delivery Address"
@keyup="keyTimer"
>
</v-autocomplete>
</v-col>
<v-col cols="1" class="ml-n9 px-0">
<v-icon class="gpsIcon" @click.stop="findMe">{{ mdiCrosshairsGps }}</v-icon>
</v-col>
</v-row>
<Map v-if="showMap" :place="place" @save="confirmLocation"></Map>
</div>
</template>
Please just visit https://foodat.ph again, i've updated it to run with postcss-purgecss and css/byebye There you'll be able to see that store layout and cravings were also affected.
@stephenjason89 Thanks for the code snippets. One way of fixing this would be to whitelist all col-*
classes in PurgeCSS (see here: https://github.com/patrickxchong/nuxt-vuetify-purgecss/blob/master/nuxt.config.js#L73). You can see your search card working at: https://nuxt-vuetify-purgecss.now.sh/foodat.
I personally DO NOT recommend this, as by whitelisting all col- classes, vuetify ships a lot of its unnecessary layout classes in the css bundle (you can compare the bundle sizes on your end after whitelisting `col-`). I would recommend that you not use v-row and v-col for layout and instead write your own layouts with CSS Grid and Flexbox.
@patrickxchong Thank you for the help using /col-*/ made the bundle size 62.9kb from 61.5kb which is still a big improvement from the original 372kb. It fixed most of my layout issue. :) You are a lifesaver!
I'm using @nuxtjs/vuetify
and nuxt-purgecss
, so the following nuxt.config.js
configuration worked for me:
export default {
// ...
buildModules: [
// ...
['@nuxtjs/vuetify', {
defaultAssets: false
}],
[
'nuxt-purgecss', {
paths: [
'node_modules/@nuxtjs/vuetify/**/*.ts',
'node_modules/@nuxt/vue-app/template/**/*.html',
'node_modules/@nuxt/vue-app/template/**/*.vue'
],
whitelist: [
'v-application',
'v-application--wrap'
],
whitelistPatterns: () => [
/^v-((?!application).)*$/,
/^\.theme--light*/,
/.*-transition/
],
whitelistPatternsChildren: [/^v-((?!application).)*$/, /^theme--light*/]
}
]
],
build: {
extractCSS: true
// ...
}
}
@patrickxchong thank you for the guidance here. I went ahead and wrote a script to analyze all the vuetify helper classes our application uses and further purge the ones that aren't. Things like mt-md-4
and order-xl-8
.
// nuxt.config.js
const rules = require('./purgeUnusedCss.js')
...
"css-byebye": {
rulesToRemove: [
/.*\.v-application--is-rtl.*/,
/.*\.theme--dark.*/,
...rules
]
}
Hey! My nuxt.config.js
is giving no results... Only 1 component, 1 plugin, and 1 page connected (test nuxt project).
buildModules: [
'nuxt-purgecss',
],
...
purgeCSS: {
styleExtensions: ['.css', '.scss', '.styl', '.sass', '.postcss'],
paths: [
'components/**/*.vue',
'layouts/**/*.vue',
'pages/**/*.vue',
'plugins/**/*.js',
'node_modules/@nuxt/vue-app/template/**/*.html',
'node_modules/@nuxt/vue-app/template/**/*.vue',
],
extractors: [
{
extractor: (content) => content.match(/[A-z0-9-:\\/]+/g) || [],
extensions: ['html', 'vue', 'js'],
},
],
whitelist: ['v-application', 'v-application--wrap'],
whitelistPatterns: () => [
/^v-((?!application).)*$/,
/^\.theme--light*/,
/.*-transition/,
],
whitelistPatternsChildren: [/^v-((?!application).)*$/, /^theme--light*/],
},
...
build: {
analyze: true,
extractCSS: true,
postcss: {
plugins: {
'postcss-custom-media': {},
'postcss-hexrgba': {},
'postcss-mixins': {},
'postcss-nested': {},
'postcss-responsive-type': {},
'postcss-sorting': {},
'postcss-url': {},
'postcss-utilities': {},
precss: {},
'@fullhuman/postcss-purgecss': {
content: [
'./components/**/*.vue',
'./layouts/**/*.vue',
'./pages/**/*.vue',
'plugins/**/*.js',
],
extractors: [
{
extractor: (content) =>
content
.replace(/<style[\s\S]*>[\s\S]*<\/style>/gi, '')
.match(/[\w-/:]+/g) || [],
extensions: ['vue'],
},
],
},
},
},
...
parsed All (532.1 KB), gzipped All (162.71 KB)
How to exclude unused? Or what's wrongly connected here?
@andrejsharapov I see that you're using both nuxt-purgecss and @fullhuman/postcss-purgecss. For starters, can you remove one of them and refer to the config of either of them in the working examples above?
Working examples @fullhuman/postcss-purgecss: https://github.com/FullHuman/purgecss/issues/67#issuecomment-699853192 nuxt-purgecss: https://github.com/FullHuman/purgecss/issues/67#issuecomment-746988946
@patrickxchong Thx! I ended up with the same result as in my example. So it works :laughing:
I will leave this for posterity.
My App:
nuxt-purgecss
= parsed All (890.96 KB), gzipped All (208.99 KB)
buildModules: [ [ 'nuxt-purgecss', { paths: [ 'node_modules/@nuxtjs/vuetify/**/*.ts', 'node_modules/@nuxt/vue-app/template/**/*.html', 'node_modules/@nuxt/vue-app/template/**/*.vue', ], whitelist: ['v-application', 'v-application--wrap'], whitelistPatterns: () => [ /^v-((?!application).)*$/, /^\.theme--light*/, /.*-transition/, ], whitelistPatternsChildren: [/^v-((?!application).)*$/, /^theme--*/], }, ],
parsed All (551.17 KB), gzipped All (167.62 KB)
buildModules: [ [ 'nuxt-purgecss', { paths: [ 'node_modules/@nuxtjs/vuetify/**/*.ts', 'node_modules/@nuxt/vue-app/template/**/*.html', 'node_modules/@nuxt/vue-app/template/**/*.vue', ], whitelist: ['v-application', 'v-application--wrap'], whitelistPatterns: () => [ /^v-((?!application).)*$/, /^\.theme--light*/, /.*-transition/, ], whitelistPatternsChildren: [/^v-((?!application).)*$/, /^theme--*/], }, ], ], build: { analyze: true, extractCSS: true,
parsed All (532.1 KB), gzipped All (162.71 KB)
buildModules: [ [ 'nuxt-purgecss', { paths: [ 'node_modules/@nuxtjs/vuetify/**/*.ts', 'node_modules/@nuxt/vue-app/template/**/*.html', 'node_modules/@nuxt/vue-app/template/**/*.vue', ], whitelist: ['v-application', 'v-application--wrap'], whitelistPatterns: () => [ /^v-((?!application).)*$/, /^\.theme--light*/, /.*-transition/, ], whitelistPatternsChildren: [/^v-((?!application).)*$/, /^theme--*/], }, ], ], build: { analyze: true, extractCSS: true, postcss: { plugins: { '@fullhuman/postcss-purgecss': { content: [ 'components/**/*.vue', 'layouts/**/*.vue', 'pages/**/*.vue', 'plugins/**/*.js', 'node_modules/vuetify/src/**/*.ts', ], styleExtensions: ['.css'], safelist: { standard: ['body', 'html', 'nuxt-progress'], deep: [ /page-enter/, /page-leave/, /dialog-transition/, /tab-transition/, /tab-reversetransition/, ], }, }, 'css-byebye': { rulesToRemove: [/.*\.v-application--is-rtl.*/, /.*\.theme--dark.*/], }, }, }, },
parsed All (532.1 KB), gzipped All (162.71 KB)
@stephenjason89 Thanks for the code snippets. One way of fixing this would be to whitelist all
col-*
classes in PurgeCSS (see here: https://github.com/patrickxchong/nuxt-vuetify-purgecss/blob/master/nuxt.config.js#L73). You can see your search card working at: https://nuxt-vuetify-purgecss.now.sh/foodat.I personally DO NOT recommend this, as by whitelisting all col- classes, vuetify ships a lot of its unnecessary layout classes in the css bundle (you can compare the bundle sizes on your end after whitelisting `col-`). I would recommend that you not use v-row and v-col for layout and instead write your own layouts with CSS Grid and Flexbox.
I second this. I was losing my mind trying to whitelist v-layout elements (v-col etc.) which even when whitelisted didn't behave as expected on prod build, so I chose to go with CSS grid layouts. Ended up with 19.kb index.html vs 350kb when not using purgecss / postcss.
I followed the instructions on setting up purgecss with nuxt and added it to simple vuetify nuxt project.
https://github.com/husayt/nuxt-vuetify-purgecss
As you can see with
npm run build
andnpm run start
layout just breaks apart.Vuetify is the most popular material ui framework for vue and it would be great to get purgecss working with it