Estoy tratando de implementar módulos CSS con SCSS.
Me las arreglo para llegar a los módulos para trabajar con SCSS. Sin embargo, no puedo hacer importaciones normales de SCSS, he intentado presionar varias reglas y excluir module.scss pero no funciona. Sería bueno si alguien aquí me puede dar una mano en esto.
Esta es mi configuración de trabajo actual solo para SCSS con módulos, pero importación normal.
Gracias.
'use strict';
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const scssPlugin = new ExtractTextPlugin(
'static/css/[name].[hash:8].css'
);
module.exports = {
modify: (baseConfig, { target, dev }, webpack) => {
const appConfig = Object.assign({}, baseConfig);
appConfig.resolve.modules.push('src', 'node_modules');
// Setup SCSS
if (target === 'web') {
appConfig.module.rules.push(
dev
? {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
localIdentName: '[local]__[hash:base64:5]'
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
plugins: () => [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
}),
],
},
},
'sass-loader',
],
}
: {
test: /\.scss$/,
use: scssPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
minimize: true,
importLoaders: 1,
localIdentName: '[hash:base64:5]'
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
plugins: () => [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
}),
],
},
},
'sass-loader',
],
}),
}
);
} else {
// On the server, we can just simply use css-loader to
// deal with scss imports
appConfig.module.rules.push(
dev ? {
test: /\.scss$/,
use: scssPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
minimize: true,
importLoaders: 1,
localIdentName: '[local]__[hash:base64:5]'
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
plugins: () => [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
}),
],
},
},
'sass-loader',
],
})
}
: {
test: /\.scss$/,
use: scssPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
minimize: true,
importLoaders: 1,
localIdentName: '[hash:base64:5]'
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
plugins: () => [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
}),
],
},
},
'sass-loader',
],
}
),
});
}
appConfig.plugins.push(scssPlugin);
return appConfig;
},
};
echa un vistazo a
https://github.com/natanelia/razzle-afterjs-redux-rnw-example
En ese ejemplo, after usa una versión anterior de razzle (que usa webpack3), pero la configuración relacionada con sass funciona. Tendría que eliminar ExtractTextPlugin porque no es compatible con webpack4 (en el que se basa el nuevo razzle).
Además, si desea aprovechar mis actualizaciones de ese ejemplo (para el paquete web 4), obtenga un botín a continuación:
const path = require('path');
const resolve=path.resolve;
const autoprefixer = require('autoprefixer');
const fs=require('fs');
//var treeify = require('treeify');
const { BundleAnalyzerPlugin } = require( "webpack-bundle-analyzer" );
const paths= require ('razzle/config/paths');
//does not yet work with webpack4
//const InlineChunkManifestHtmlWebpackPlugin = require('inline-chunk-manifest-html-webpack-plugin');
//keep it here,but could not get to work for sass...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
/* finds an index of babel rules in array of webpack rules */
/*
{
'ruleIdx':'',
'useIdx':''
}
*/
function getIdx_RulesByLoader (inRulesArr,
IS_DEV,
IS_WEB,
loaderStr,
extentionRegExTest) {
let jsRulesBabelLoaderIdx = -1;
let useIdx=-1;
jsRulesBabelLoaderIdx=inRulesArr.findIndex(
(rule) =>{
if (rule.test // rule.test is a reg expr
&& rule.test.exec
&& rule.test.exec(extentionRegExTest)
&& rule.use)
{
useIdx=rule.use.findIndex(
(useItem)=> {
if (useItem.options
&& useItem.loader.includes(loaderStr) ){
return true;
}
}
);
/*return true if useIdx is a valid index */
return (useIdx>-1);
}
}
);
const res={
'ruleIdx':jsRulesBabelLoaderIdx,
'useIdx':useIdx
};
return res;
}
module.exports = {
modify(baseConfig, secondArg, webpack) {
const {target, dev}=secondArg;
/* make a copy of config */
const config = Object.assign({}, baseConfig);
const IS_NODE = target === 'node';
const IS_WEB = target === 'web';
const IS_PROD = !dev;
const IS_DEV = dev;
const MYpostCssLoader = {
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: IS_DEV,
plugins: () => [
autoprefixer({
browsers: ['>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9'],
}),
],
},
};
const MYscssLoader = {
loader: 'sass-loader',
options: {
includePaths: [path.resolve(__dirname, './node_modules')],
sourceMap: IS_DEV
}};
const MYcssLoader = IS_NODE ?
{loader:"css-loader"}
:{
loader: "css-loader",
options: {
minimize: !IS_DEV,
sourceMap: IS_DEV,
importLoaders: 1,
localIdentName:
IS_DEV?'[path]__[name]___[local]':undefined,
}
};
/*
MiniCssExtractPlugin
plugin should be used only on
production builds without style-loader
in the loaders chain, especially if you
want to have HMR in development.
*/
const newSaasRule= {
test: /\.(sass|scss)$/,
exclude:[path.resolve(__dirname, './node_modules')],
use: IS_NODE
? [MYcssLoader, MYscssLoader]
: IS_DEV
? [
'style-loader',
MYcssLoader,
MYpostCssLoader,
MYscssLoader
]
:[
//'style-loader',
MYcssLoader,
//cannot get this to work MiniCssExtractPlugin.loader,
MYpostCssLoader,
MYscssLoader
]
};//end of newSaasRule
config.module.rules.push(newSaasRule);
/* make babel to transply My symlinked directors
This is relevant to My seetup (others may not have symlinks..)
and from some directories containing react native modules
@start<strong i="10">@step</strong>:1
*/
/* match with config-override.js on the csr side */
config.resolve.alias['web_common'] = path.resolve('./src/wc.src');
config.resolve.alias['app_src'] = path.resolve('./src/app.src');
config.resolve.alias['rnjs_common'] = path.resolve('./src/js.app');
//config.resolve.alias.AppStyles$ = path.resolve('./src/app.src/styles/AppStyles')
//copied from cra config
//Probably not needed,
config.resolve.alias['babel-runtime']=path.dirname(require.resolve('babel-runtime/package.json'));
/*
* add ./src to module resolver so you can import
* modules with absolute path
* again, this might not be of use to others...
*/
config.resolve.modules.push('./src');
let resOfBabelRule=getIdx_RulesByLoader(config.module.rules,
IS_DEV,
IS_WEB,
'babel-loader', //loader name
'./testFileNm.js' //test file name for regex
);
/* noticed besides my sources, I also had to add react-native-vector-icons
this was not the only change for RN-vector-icons though, but other changes
for RN-vector icons are in babel related rules outside of this config file */
const pathsToMySourcesArr=
[
fs.realpathSync(paths.appSrc+'/js.app'),
fs.realpathSync(paths.appSrc+'/app.src'),
fs.realpathSync(paths.appSrc+'/wc.src'),
fs.realpathSync(paths.appNodeModules+'/react-native-vector-icons'),
fs.realpathSync(paths.appNodeModules+'/react-native-vector-icons/node_modules'),
];
config.module.rules[resOfBabelRule.ruleIdx]
.include
.push(...pathsToMySourcesArr);//use spread to push invidiual elements
//this is a must
config.resolve.symlinks=false;
/* react native vector icons @start<strong i="11">@step</strong>:1 */
const newRNVectorIconsRule={
test: /\.ttf$/,
loader: require.resolve("file-loader"), // or directly file-loader
include: fs.realpathSync(paths.appNodeModules+'/react-native-vector-icons')
};
config.module.rules.push(newRNVectorIconsRule);
/* react native vector icons @end<strong i="12">@step</strong>:1 */
if (IS_WEB) {
if ( !IS_DEV ) {
config.plugins.push( new BundleAnalyzerPlugin( {
analyzerMode: "static",
reportFilename: "webpack-report.html",
openAnalyzer: false,
} ) );
}
}
/*
* I share some of my react components with my
* react native part of the system
* So UsefulComponent.web.js is for web
* UsefulCompoenent.android.js is for android
* Usefulcomponent.ios.js is for IOS
*
* By the way, react's CRA allows for web.js convention
* so this should probably be a feature of razzle too
* rather than a customization
*/
config.resolve.extensions = config.resolve.extensions.concat([
'.web.js'
]);
return config;
},
};
He logrado hacerlo funcionar, gracias por la ayuda. Haré un PR con ejemplo pronto.
¿Podría proporcionar un ejemplo @MaxGoh
Un poco tarde para esto, pero esto es lo que funcionó para mí:
const path = require("path");
module.exports = {
modify(config, { target, dev }, webpack) {
for (const rule of config.module.rules) {
if (rule.test && rule.test.toString() === "/\\.module\\.css$/") {
const scss = { ...rule };
scss.test = /\.scss$/;
scss.include = path.join(__dirname, "src");
scss.use.push({ loader: "sass-loader" });
config.module.rules.push(scss);
break;
}
}
return config;
}
};
Comentario más útil
Un poco tarde para esto, pero esto es lo que funcionó para mí: