I'm trying to import some SCSS into a Javascript file with mixed results. I've found that this works:
style.styleString.scss
body {
background: #556;
}
.test {
&__child {
color: red;
}
}
index.js
import "./index.style"; // making sure that nothing we do breaks normal SCSS importing
const css = require("!!raw-loader!sass-loader!./style.stringStyle.scss").default;
console.log(css);
index.style.scss is correctly compiled to a file and style.stringStyle.scss is correctly printed in the console.
What I'd like to do is move this loader pipeline into my webpack config. This is what I have at the moment:
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import path from "path";
const config = {
mode: "development",
entry: {
"app": "./src/index.js",
},
output: {
path: path.resolve(process.cwd(), "dist"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.stringStyle.scss$/i,
use: [
"raw-loader",
"sass-loader",
],
},
{
test: /\.scss$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader:"css-loader",
options: {
url: false,
},
},
"sass-loader",
],
},
],
},
resolve: {
extensions: [".js", ".scss", ".css"],
},
devtool: "source-map",
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
};
export default config;
index.js
import "./index.style"; // making sure that nothing we do breaks normal SCSS importing
const css = require("./style.stringStyle.scss").default;
console.log(css);
With this configuration, an empty string is printed to the console (index.style.scss still correctly renders to a file).
What am I doing wrong here? I was sort of under the impression that using the inline ! syntax in imports works just like lining up loaders in the config file, but I'm clearly missing something.
Is it possible to setup loading SCSS files as CSS strings in my Webpack config?
Both SCSS tracking rules are getting applied to style.stringStyle.scss. Adding a negative look-behind to the normal import rule's test regex will make sure only the correct rule is selected:
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import path from "path";
const config = {
mode: "development",
entry: {
"app": "./src/index.js",
},
output: {
path: path.resolve(process.cwd(), "dist"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.stringStyle.scss$/i,
use: [
"raw-loader",
"sass-loader",
],
},
{
test: /(?<!\.stringStyle)\.scss$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader:"css-loader",
options: {
url: false,
},
},
"sass-loader",
],
},
],
},
resolve: {
extensions: [".js", ".scss", ".css"],
},
devtool: "source-map",
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
};
export default config;
Related
any idea how to fix this, the webpack config in the ckeditor folder is set like this:
const path = require("path");
const webpack = require("webpack");
const { bundler, styles } = require("#ckeditor/ckeditor5-dev-utils");
const CKEditorWebpackPlugin = require("#ckeditor/ckeditor5-dev-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
module.exports = {
devtool: "source-map",
performance: { hints: false },
entry: path.resolve(__dirname, "src", "ckeditor.js"),
output: {
// The name under which the editor will be exported.
library: "CKSource",
path: path.resolve(__dirname, "build"),
filename: "ckeditor.js",
libraryTarget: "umd",
libraryExport: "default",
},
optimization: {
minimizer: [
(compiler)=>{
const TerserPlugin = require('terser-webpack-plugin');
new TerserPlugin({
terserOptions: {
compress: {},
}
}).apply(compiler);
}
],
},
plugins: [
new CKEditorWebpackPlugin({
// UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
// When changing the built-in language, remember to also change it in the editor's configuration (src/ckeditor.js).
language: "en",
additionalLanguages: "all",
}),
new webpack.BannerPlugin({
banner: bundler.getLicenseBanner(),
raw: true,
}),
],
module: {
rules: [
{
test: /\.svg$/,
use: ["raw-loader"],
},
{
test: /\.css$/,
use: [
{
loader: "style-loader",
options: {
injectType: "singletonStyleTag",
attributes: {
"data-cke": true,
},
},
},
{
loader: "css-loader",
},
{
loader: "postcss-loader",
options: {
postcssOptions: styles.getPostCssConfig({
themeImporter: {
themePath: require.resolve("#ckeditor/ckeditor5-theme-lark"),
},
minify: true,
}),
},
},
],
},
],
},
};
I tried to delete package-lock.json and delete node_modules and reinstall everything, but it did not work.
Tried other solutions from other Stack overflow questions that had similar issues, nothing worked
this happens for ckeditor by the way.
I am trying to split code of styles into smaller chunks due to the size of generated output. I am developing using react so i solved javascript loading with React.lazy().
Lets say that there is one big application with 50 different views you can open. Not all views are available to all users.
What i did in my router is:
...
const view = React.lazy(() => import("./views/view"));
...
...
<view />
...
What this did is divided entire application to 50 separate js files that are dynamically loaded which is good.
It however did not divide styles the same way. So lets look into one of the views:
import React, { Component } from "react";
import "../../scss/view.scss";
class view extends Component {
...
}
export default view;
So each view has its own scss files dedicated for this view, which makes them virtually standalone. The problem is that webpack is still producing only one big style[hash].css file.
Webpack config:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "index.html"
});
const extractTextPlugin = new ExtractTextPlugin({
filename: "css/style.[hash:8].css",
allChunks: true
});
module.exports = {
output: {
filename: "js/main.[hash:8].js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.(png|jpg|gif|ico|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 25000,
outputPath: "/assets/",
name: "[name].[hash:8].[ext]"
}
},
{
test: /\.(scss|sass|css)$/i,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{ loader: "css-loader" },
{ loader: "postcss-loader", options: { sourceMap: true } },
{ loader: "sass-loader", options: { sourceMap: true } }
]
})
}
]
},
resolve: {
extensions: [".js", ".jsx", ".json"]
},
plugins: [htmlPlugin, extractTextPlugin],
devServer: {
historyApiFallback: {
rewrites: [{ from: /^\/$/, to: "/index.html" }]
}
}
};
Is there any way to make styles also produced and loaded dynamically respective to their js file, so for example if i open view 10 it loads 10.main[hash].js and 10.style[hash].css ?
Answer to this problem is to replace deprecated extract-text-webpack-plugin package that is actually missing this functionality (splitting styles into respective chunks).
Instead mini-css-extract-plugin should be used and it automatically works.
updated working webpack config file:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "index.html",
});
const miniCssExtractPlugin = new MiniCssExtractPlugin({
filename: "css/style.[hash:8].css",
chunkFilename: "css/[id].style.[hash:8].css",
});
module.exports = {
output: {
filename: "js/main.[hash:8].js",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader",
},
{
test: /\.(png|jpg|jpeg|gif|ico|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 25000,
outputPath: "/assets/",
name: "[name].[hash:8].[ext]",
},
},
{
test: /\.(scss|sass|css)$/i,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
],
},
resolve: {
extensions: [".js", ".jsx", ".json"],
},
plugins: [htmlPlugin, miniCssExtractPlugin],
devServer: {
historyApiFallback: {
rewrites: [{ from: /^\/$/, to: "/index.html" }],
},
},
};
I am getting a syntax error in one of my css files from monaco-editor in node_modules. It is an unknown word error:
> 1 | // Imports
| ^
2 | import ___CSS_LOADER_API_IMPORT___ from "../../../../../../css-loader/dist/runtime/api.js";
3 | var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});
# ./node_modules/monaco-editor/esm/vs/platform/contextview/browser/contextMenuHandler.css 2:12-317 9:17-24 13:15-29
However, I have css-loader configured in my webpack.config.js:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const PerspectivePlugin = require("#finos/perspective-webpack-plugin");
const path = require("path");
const plugins = [
new HtmlWebPackPlugin({
title: "Perspective React Example",
template: "./src/frontend/index.html",
}),
new PerspectivePlugin(),
];
module.exports = {
context: path.resolve(__dirname),
entry: "./src/frontend/index.tsx",
mode: "development",
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
plugins: plugins,
module: {
rules: [
{
test: /\.ts(x?)$/,
//exclude: /node_modules/,
loader: "ts-loader",
},
{
test: /\.css$/,
//exclude: /node_modules/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders: 1,
},
},
'postcss-loader'
],
},
],
},
devServer: {
// superstore.arrow is served from here
contentBase: [
path.join(__dirname, "dist"),
path.join(__dirname, "node_modules/superstore-arrow"),
],
},
experiments: {
executeModule: true,
syncWebAssembly: true,
asyncWebAssembly: true,
},
output: {
filename: "app.js",
path: __dirname + "/dist",
},
};
I also have a config file for postcss-loader:
module.exports = {
plugins: [
require('autoprefixer')
]
};
I'm not sure what is wrong with what I'm doing, so I'm wondering if there is another loader I need to add to webpack.config.js or if my configuration is incorrect?
I had same issue, try this:
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
// Options
},
],
],
},
},
},
],
I am using these three css imports from various packages:
// want to do import 'path/to/css.css'
import slickCss from "slick-carousel/slick/slick.css"
import slickCssTheme from "slick-carousel/slick/slick-theme.css"
import leafcss from 'leaflet/dist/leaflet.css'
console.log(`Slick Css: `, slickCss)
console.log(`Slick Theme Css: `, slickCssTheme)
console.log(`leaf css: `, leafcss)
If I log those out they are all empty objects:
Slick Css: {}
Slick Theme Css: {}
leaf css: {}
I assume that something is going wrong with how I am using the loader for webpack. For the most part that I can see everything else is working as far as the react bundle goes. For now I will attach my webpack to not over complicate things. If there is no problem with the webpack I will start adding the necessary files. I tried the alias and still got the same result.
var path = require(`path`)
module.exports = {
mode: `development`,
entry: `./scripts/inject.js`,
output: {
path: path.resolve(__dirname, `dist`),
filename: `bundle.js`,
},
resolve: {
extensions: [`.html`, `.js`, `.json`, `.scss`, `.css`],
alias: {
leafModule: __dirname + `/node_modules/leaflet/dist/leaflet.css`,
},
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: `file-loader`,
},
],
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: `file-loader`,
options: {
name: `[name].[ext]`,
outputPath: `fonts/`,
},
},
],
},
{
test: /\.css$/i,
use: [`style-loader`, `css-loader`],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: `babel-loader`,
options: {
presets: [`#babel/preset-env`],
},
},
},
],
},
}
I'm not sure your setup is able to collect your style properly. From my point of view, you can use mini-css-extract-plugin to help you collect your css. Here is additional code you may add to your webpack.config.js:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
// ...
modules: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: `css-loader`,
options: {
// Enable css as module so we can import
modules: true,
},
},
],
},
],
},
plugins: [
// ...
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
]
}
However, keep in mind that if you switch css to module, it won't inject automatically anymore since each class name will be renamed so you have to import and add manually like:
import css from "path/to/css";
<div classSName={css.headerClass} />
As a result of that, you will have trouble with 3rd packages which have css files to import as your case.
I am using Webpack 2 for my portfolio website, but it's not an SPA - therefore, the intention is not to output everything into my bundled JS.
I have a few entry points for the .pug, .scss and .js files. Like so:
entry: {
app: [
path.resolve(__dirname, 'src/pug/app.pug'),
path.resolve(__dirname, 'src/js/app.js'),
path.resolve(__dirname, 'src/scss/app.scss')
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].js'
}
However, when looking at the source for the app.js, I see the rendered HTML from my .pug files.
For the .pug compiling, I'm using HtmlWebpackPlugin. I guess the easiest way for me to explain what's going on is to show you the webpack.config.babel.js file:
import webpack from 'webpack';
import path from 'path';
import autoprefixer from 'autoprefixer';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import SvgStorePlugin from 'external-svg-sprite-loader/lib/SvgStorePlugin';
import bourbon from 'bourbon';
import neat from 'bourbon-neat';
const extractScss = new ExtractTextPlugin({
filename: 'css/[name].css',
allChunks: true
});
const config = {
entry: {
app: [
path.resolve(__dirname, 'src/pug/app.pug'),
path.resolve(__dirname, 'src/js/app.js'),
path.resolve(__dirname, 'src/scss/app.scss')
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].js'
},
module: {
rules: [
{
test: /\.pug$/,
use: [
{
loader: 'html-loader'
},
{
loader: 'pug-html-loader',
options: {
pretty: false,
exports: false
}
}
]
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
['es2015']
]
}
}
]
},
{
test: /\.(jpe?g|png|gif)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '/images/[name].[ext]'
}
},
{
loader: 'image-webpack-loader',
options: {
progressive: false,
optipng: {
optimizationLevel: 7,
quality: '90',
speed: 5
},
mozjpeg: {
quality: 90
},
gifsicle: {
interlaced: false
}
}
}
]
},
{
test: /\.svg$/,
use: [
{
loader: 'external-svg-sprite-loader',
query: {
name: 'svg/sprite.svg',
iconName: '[name]'
}
}
]
},
{
test: /\.scss$/,
use: extractScss.extract([
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
plugins() {
return [
autoprefixer({
browsers: ['last 2 versions', 'Explorer >= 9', 'Android >= 4']
})
];
}
}
},
{
loader: 'sass-loader',
options: {
includePaths: [
bourbon.includePaths,
neat.includePaths
]
}
}
])
}
]
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
stats: 'errors-only',
open: false
},
plugins: [
new SvgStorePlugin(),
new HtmlWebpackPlugin({
title: 'Portfolio',
minify: {
collapseWhitespace: true
},
hash: true,
template: 'src/pug/app.pug',
filetype: 'pug',
filename: 'index.html'
}),
extractScss
]
}
process.traceDeprecation = false;
export default config;
I don't see any CSS in the app.js bundle and the entry point is setup just the same, so might it have something to do with the HtmlWebpackPlugin itself? Perhaps I'm not understanding how this works correctly and my configuration is wrong.
I'm new to Webpack (coming from Gulp), so please bear with me if the answers to my questions seem rather obvious.
Thanks for your help.
Update:
For reference, my project structure is as follows:
And I would call an image from my .pug file in /pug/components/example.pug with a path like img(src="../images/example.jpg"). This worked prior to removing .pug as an entry point in the Webpack config as user Tatsuyuki suggested below.
Do not add the template as an source:
app: [
// path.resolve(__dirname, 'src/pug/app.pug'),
path.resolve(__dirname, 'src/js/app.js'),
path.resolve(__dirname, 'src/scss/app.scss')
]
Instead, specify the template option for HtmlWebpackPlugin:
new HtmlWebpackPlugin({
template: 'src/index.pug'
})
Reference