I'm doing a proof of concept to include vuetify in an existing web app that is already partially using vue.
I'm have a concern with CSP, by default all vuetify styles are pushed in inline <style> tags. I don't want to allow style-src 'unsafe-inline' in my CSP.
So far there is 95 inline style tags inserted by vuetify in the <head>section. I did tried the option to put an nonce like described here, but the nonce is only added on the last tag, so still 94 to go. Moreover, I don't have a solid solution to generate nonces, so I'd prefer not relying on this.
Generating a hash for each tag is of course not realist.
I also saw this answer, but I don't think it apply to my context, I'm not server-side renderring.
I am using webpack 4.41.2, vue 2.6.10, vuetify 2.2.8.
Here are some extracts of config files.
webpack.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin');
[...]
et entryPoints = Object.assign([...], { vendor: ['vue', 'vue-router', 'axios', 'vue-i18n', 'lodash', 'interactjs'] });
var config = {
entry: entryPoints,
output: {
path: __dirname,
filename: 'module/[name].js'
},
[...]
plugins: [
new MiniCssExtractPlugin({ filename: 'module/[name].css', chunkFilename: 'module/[name].css' }),
new VueLoaderPlugin(),
new VuetifyLoaderPlugin()
],
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
}
}
},
runtimeChunk: { name: 'manifest' }
}
};
Initialisation file
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
import 'vuetify/dist/vuetify.min.css';
[...]
Vue.use(Vuetify);
const vuetifyOptions = new Vuetify();
// Création de l'instance Vue.js, qui sera dessiner dans l'element définit par l'attribut el
window.Vue = new Vue({
el: '#app',
render: h => h(App),
vuetify: vuetifyOptions
});
I finally found the solution, I was already importing MiniCssExtractPlugin, but used it with less module, but I had to add it to sass module also, used by vuetify.
{
test: /\.s(c|a)ss$/,
use: [
'vue-style-loader',
MiniCssExtractPlugin.loader, // <-- that line
'css-loader',
{
loader: 'sass-loader',
// Requires sass-loader#^8.0.0
options: {
implementation: require('sass'),
sassOptions: {
fiber: require('fibers'),
indentedSyntax: true // optional
}
}
}
]
}
Related
Problem:
Button class being overridden by default tailwind base classes. Not sure why my classes on the element aren't being applied.
Question:
How can I get my styles to apply properly?
Screenshot:
As you can see background color on .documentCategory__row is being overridden by button, [type=button] on index.scss which is being defined within #tailwind/base.
/* index.scss */
:root {
--color-primary: #00a3e0;
--color-secondary: #470a68;
--color-success: #87d500;
--color-accent: #e87722;
/* Dark themes below */
--color-dark-primary: rgba(31, 41, 55, 1);
--dark-text: rgba(187, 193, 198, 1);
}
#import "tailwindcss/base";
#import "tailwindcss/components";
#import "tailwindcss/utilities";
I'm not sure if this has to do with me switching to dart-scss so here is my webpack configuration in case I am missing something
import path from 'path'
import { Configuration as WebpackConfiguration, HotModuleReplacementPlugin } from 'webpack'
import { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server';
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
import ESLintPlugin from 'eslint-webpack-plugin'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
const CopyPlugin = require('copy-webpack-plugin');
interface Configuration extends WebpackConfiguration {
devServer?: WebpackDevServerConfiguration;
}
const config: Configuration = {
mode: 'development',
devServer: {
static: path.join(__dirname, 'build'),
historyApiFallback: true,
port: 4000,
open: true,
hot: true,
},
output: {
publicPath: '/',
},
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.(ts|js)x?$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-env',
'#babel/preset-react',
'#babel/preset-typescript',
],
},
},
},
{
test: /\.(sa|sc|c)ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader',
{
loader: 'postcss-loader', // postcss loader needed for tailwindcss
options: {
postcssOptions: {
ident: 'postcss',
plugins: [tailwindcss, autoprefixer],
},
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
outputPath: '../fonts',
},
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
}),
new HotModuleReplacementPlugin(),
new CopyPlugin({
patterns: [
// relative path is from src
{ from: 'public/images', to: 'images' },
],
}),
// Add type checking on dev run
new ForkTsCheckerWebpackPlugin({
async: false,
}),
// Add lint checking on dev run
new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx'],
}),
],
devtool: 'inline-source-map',
};
export default config
If there are other files I am missing that are needed let me know!
without seeing what your index.tsx looks like I can only make a guess, but here's what caused this issue in our app:
in our index.tsx we were importing index.css after importing our component tree with import App from 'src/App. thus the css was loaded into the site in the wrong order. imports from components first (css modules, normal css imports), tailwind last.
go to your entry file (probably index.tsx) and try moving your import 'index.scss' line above importing the root component.
like this for example
/* index.tsx */
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css'; // this file holds all tailwind styles
import { App } from 'src/App';
// ...
read more here:
https://github.com/tailwindlabs/tailwindcss/discussions/7304#discussioncomment-2256226
Even i faced the same issue but I am using Vue3 + element-ui-plus, after spending more than 6 hours my solution is to set :native-type='null':
<el-button type='primary' round #click='handleClick' :native-type='null'>Click Me</el-button>
but this is kinda "hack", this either need to be fixed by Tailwind or by element-ui team. Anyhow, for now enjoy ;)
And the discussion is on here
I got the same issue using tailwindcss v3 and NextUI, and button's background were "transparent". By adding type = {null}, to button's I solve the issue
I am trying to get under the hoods of styled-components library.
reading this article have helped me a-lot:
How styled-components works
But there is something I can't fully understand:
the article describes how styled-component creates the 'style' tag inside the 'head' section and at runtime injects the component style in-there.
so I have created a minimal react project and the UI is working fine, except I don't
see the injected CSS style in the DOM.
I do see an empty styled tag in the head:<style data-styled-components=""></style>.
scratching my head how the css manages to apply successfully...
I even downgraded the library version to 3.3.3, the same as in the article - and it still doesn't work.
Assuming it will be more efficient to ask Stack-overflow than in the article,
may be someone here can help?
webpack-config:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const config = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'), // base path where to send compiled assets
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
// config for sass compilation
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
'css-loader'
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
// plugin for inserting scripts automatically into html
template: 'src/index.html',
}),
new MiniCssExtractPlugin({
// plugin for controlling how compiled css will be outputted and named
filename: '[name].css',
}),
],
};
module.exports = config;
the react code
import React from 'react'
import styled from 'styled-components'
import ReactDOM from 'react-dom';
let counter = 6
const Button = styled.button`
color: coral;
padding: 0.25rem 1rem;
border: solid 2px coral;
border-radius: 3px;
margin: 0.5rem;
font-size: ${({size}) => { return size }}px;
`
const MyButton = (props) => {
return (<Button onClick={()=>update()} size={props.size}> Hi, I am your new button </Button>)
}
const update=()=>{
counter ++;
ReactDOM.render(<MyButton size={counter}/>, document.getElementById('root'))
}
export default MyButton
:
I have set my global.css file which I import in index.js
--root {
--main-color: red;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
index.js
import "./global.css";
import App from "./App.svelte";
const app = new App({
target: document.body
});
My webpack setup
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
},
module: {
rules: [
{
test: /\.(html|svelte)$/,
exclude: /node_modules/,
use: {
loader: "svelte-loader",
options: {
emitCss: true,
hotReload: true
}
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: { loader: "style-loader", options: { sourceMap: true } },
use: [
{ loader: "css-loader", options: { sourceMap: true } },
{
loader: "postcss-loader",
options: {
sourceMap: true,
ident: "postcss",
plugins: loader => [
require("postcss-import")({}),
require("postcss-preset-env")(),
require("cssnano")()
]
}
}
]
})
}
]
},
plugins: [new HtmlWebpackPlugin(), new ExtractTextPlugin("styles.css")]
};
Works perfect for setting up global css for the entire app. But I am trying to use the --main-color in my svelte components. Is there a way to inject them down to all the components' css ?
Since I import global.css first, it should work as it emits a file with --root{} first then rest of the component styles.
You can place global styles under /routes/index.svelte file, like the example below:
<style>
:global(:root){
--header-color: purple
}
</style>
And simply use it anywhere like normally how you use CSS variables like so:
h1 {
color: var(--header-color);
}
I was busy with this, trying different webpack settings etc., seeing that the output css should work, I just could not find why it did not work. I wrote the post before trying for one last time, which wasted another hour. I finally found the error.
Instead of using :root{} I have mistyped it --root{}. I have posted it anyways, in case someone is stuck with the same mistake.
I'm trying to set up a very basic css configuration for my react project. I'm using webpack and style loaders, like so:
// webpack.config.js
const {resolve} = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const port = process.env.PORT || 3000;
module.exports = {
entry: "./src/js/index.js",
output: {
filename: "bundle.[hash].js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}, {
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader, {
loader: "css-loader",
options: {
modules: true,
camelCase: true,
sourceMap: true
}
}, {
loader: "sass-loader",
options: {
sourceMap: true,
precision: 8,
data: "$ENV: " + "PRODUCTION" + ";"
}
}
]
}
]
},
devServer: {
host: 'localhost',
port: port
},
devtool: 'inline-source-map',
plugins: [
new HtmlWebpackPlugin({
template: resolve("public", "index.html"),
favicon: resolve("public", "favicon.ico")
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
};
My problem is that changes in my css file aren't reflected in the html that my react components return.
So if I have a component like:
import React from 'react'
require('../../styles/style.scss')
const App = () => (<div className="root">
<div id='banner1' className='banner'>
<h1>foo</h1>
<h2>bar</h2>
</div>
</div>)
export default App
... and an scss file like:
#banner1 {
height: 100vh;
background: blue;
width: 100%;
}
h1 {
font-size: 30px;
color: white;
}
... my styles will show up initially, but any changes while the server is still running won't be reflected if I refresh the page. It will only reflect the changes in my stylesheet when I restart the server.
My suspicion is that the mini-css-extract-plugin package is minifying the css and packing it into a bundle that react doesn't see in the development environment whenever it's changed, and it doesn't get rebundled.
If I'm right, my conflict is that this is the ubiquitous way I've read in tutorials to set up your webpack configuration, and there is literally zero mention of this side effect being present in a dev environment. Is there an alternate configuration I should be specifying for a dev environment? Is there something I'm missing?
Try using classname={styles.banner} in case of scss.
I am attempting to change a button's style in ReactJS with the "className" element. However, I get back an error stating "Unresolved variable nameOfClass" in WebStorm, and the stylistic changes are not made when I run webpack and open the page on localhost. I have attempted different methods of importing the CSS file and naming conventions to no avail.
The file with the React Component class is here:
import * as React from "react";
var styles = require('./Roster.css');
export class Roster extends React.Component<{},{}> {
render() {
return (
<div>
<button className={styles.nameOfClass} type="button" >Players</button>
</div>
);
}
}
And the Roster.css file is here:
.nameOfClass {
background-color: #ff0000;
}
webpack.config.js
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "./dist/bundle.js",
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
externals: ['axios'],
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
},
module: {
loaders: [
// All files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'.
{ test: /\.tsx?$/,
loader: "ts-loader"
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'),
}
],
preLoaders: [
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ test: /\.js$/, loader: "source-map-loader" }
]
},
plugins: [
new ExtractTextPlugin('styles.css', { allChunks: true })
],
// When importing a module whose path matches one of the following, just
// assume a corresponding global variable exists and use that instead.
// This is important because it allows us to avoid bundling all of our
// dependencies, which allows browsers to cache those libraries between builds.
externals: {
"react": "React",
"react-dom": "ReactDOM"
},
};
You don't have to require the styles file.
import * as React from "react";
export class Roster extends React.Component<{},{}> {
render() {
return (
<div>
<button className="nameOfClass" type="button" >Players</button>
</div>
);
}
}
and your css file:
.nameOfClass {
background-color: #ff0000;
}
Should look something like:
import * as React from "react";
export class Roster extends React.Component<{},{}> {
render() {
return <div>
<button className="nameOfClass" type="button">Players</button>
</div>
}
}
You can't require css files, only typescript/javascript files.
There's the css-modules thing, and there are some js solutions for react/css, such as Radium and reactCss.