react-native-sass-transformer
react-native-sass-transformer copied to clipboard
Styles are imported as empty object with RN 73
I am importing the styles in the following way but when I console.log(styles)
, it is returning{}
import styles from '#/screens/auth/SignIn.scss';
I have attached my files.
metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.transformer.babelTransformerPath = require.resolve("react-native-sass-transformer")
config.resolver.sourceExts.push("scss");
config.resolver.sourceExts.push("sass");
module.exports = config;
babel.config.js
module.exports = function(api) {
api.cache(true);
return {
plugins: [
['module:react-native-dotenv'],
'react-native-reanimated/plugin',
'@babel/plugin-proposal-export-namespace-from',
],
presets: [['babel-preset-expo']],
};
};
app.json
{
"expo": {
"version": "3.3.2",
"privacy": "public",
"android": {
"icon": "./assets/icon.png",
"package": "main",
"permissions": [
"LOCATION",
"CAMERA",
"MEDIA_LIBRARY",
"AUDIO_RECORDING",
"RECORD_AUDIO",
"READ_EXTERNAL_STORAGE",
"WRITE_EXTERNAL_STORAGE",
"POST_NOTIFICATIONS",
"PUSH_NOTIFICATIONS",
"NOTIFICATIONS",
"ACCESS_BACKGROUND_LOCATION",
"ACCESS_COARSE_LOCATION",
"ACCESS_FINE_LOCATION",
"FOREGROUND_SERVICE"
],
"versionCode": 332,
"googleServicesFile": "./google-services.json"
},
"assetBundlePatterns": [
"assets/**/*"
],
"description": "",
"web": {
"bundler": "metro"
},
"packagerOpts": {
"config": "metro.config.js",
"sourceExts": ["ts", "tsx", "scss", "sass"]
},
"ios": {
"buildNumber": "3.3.2",
"config": {
"usesNonExemptEncryption": false
},
"icon": "./assets/notification-icon.png",
"infoPlist": {
"LSApplicationQueriesSchemes": [
"comgooglemaps",
"citymapper",
"uber",
"lyft",
"waze"
],
"UIBackgroundModes": [
"location",
"fetch"
],
"NSLocationAlwaysAndWhenInUseUsageDescription": "App requires geolocation to improve the quality of the service",
"NSLocationAlwaysUsageDescription": "App requires geolocation to improve the quality of the service",
"NSLocationWhenInUseUsageDescription": "App requires geolocation to improve the quality of the service"
},
"bundleIdentifier": "main"
},
"name": "Arelli",
"orientation": "portrait",
"platforms": [
"android",
"ios"
],
"scheme": "main",
"slug": "main",
"updates": {
"fallbackToCacheTimeout": 10000,
"url": "https://u.expo.dev/13ced000-95fd-4620-b3f7-09c1a2e0651b"
},
"splash": {
"image": "./assets/splashscreen.png",
"backgroundColor": "#292929"
},
"notification": {
"icon": "./assets/push/icon-notification.png",
"color": "#000000"
},
"plugins": [
[
"expo-notifications",
{
"icon": "./assets/push/icon-notification.png",
"color": "#000000"
}
],
"sentry-expo",
"expo-font"
],
"runtimeVersion": "1.0.0"
}
}
package.json
"name": "main",
"version": "3.2.3",
"private": true,
"main": "sources/index.tsx",
"scripts": {
"codestyle:check": "prettier --check \"mocks/**/*.ts\" \"sources/**/*.{ts,tsx}\"",
"codestyle:fix": "prettier --write \"mocks/**/*.ts\" \"sources/**/*.{ts,tsx}\"",
"lint:check": "tslint --project tsconfig.lint.json",
"lint:fix": "tslint --fix --project tsconfig.lint.json",
"start": "expo start --dev-client",
"test": "jest --passWithNoTests",
"test:coverage": "jest --coverage --passWithNoTests",
"typecheck": "tsc",
"android": "react-native run-android",
"ios": "react-native run-ios"
},
"dependencies": {
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
"@expo/react-native-action-sheet": "^3.12.0",
"@react-native-async-storage/async-storage": "1.21.0",
"@react-native-community/datetimepicker": "7.6.1",
"@react-native-community/netinfo": "11.1.0",
"@react-native-community/slider": "4.4.2",
"@react-navigation/native": "^5.9.2",
"@react-navigation/stack": "^5.14.2",
"@reduxjs/toolkit": "^1.8.1",
"@sentry/react-native": "5.19.1",
"axios": "^0.27.2",
"babel-plugin-module-resolver": "^5.0.0",
"babel-plugin-react-native-platform-specific-extensions": "^1.1.1",
"babel-preset-expo": "^10.0.0",
"expo": "^50.0.0",
"expo-application": "~5.8.3",
"expo-asset": "~9.0.2",
"expo-av": "~13.10.5",
"expo-camera": "~14.0.5",
"expo-checkbox": "~2.7.0",
"expo-constants": "~15.4.5",
"expo-device": "~5.9.3",
"expo-file-system": "~16.0.7",
"expo-font": "~11.10.3",
"expo-image-picker": "~14.7.1",
"expo-linking": "~6.2.2",
"expo-location": "~16.5.5",
"expo-notifications": "~0.27.6",
"expo-splash-screen": "~0.26.4",
"expo-status-bar": "~1.11.1",
"expo-task-manager": "~11.7.2",
"expo-updates": "~0.24.11",
"expo-video-thumbnails": "~7.9.0",
"firebase": "^9.6.5",
"geolib": "^3.3.3",
"is-color": "^1.0.2",
"lodash": "^4.17.21",
"moment": "^2.29.3",
"react": "18.2.0",
"react-hook-form": "^7.20.2",
"react-i18next": "~10.13.1",
"react-native": "0.73.4",
"react-native-animation-hooks": "~1.0.1",
"react-native-async-storage": "^0.0.1",
"react-native-collapsible": "^1.6.0",
"react-native-dotenv": "^3.4.8",
"react-native-elements": "^2.0.0",
"react-native-gesture-handler": "~2.14.0",
"react-native-image-viewing": "^0.2.2",
"react-native-keyboard-aware-scroll-view": "^0.9.4",
"react-native-map-link": "^2.7.10",
"react-native-modal": "^13.0.1",
"react-native-modal-datetime-picker": "^14.0.1",
"react-native-paper": "^3.10.1",
"react-native-reanimated": "~3.6.2",
"react-native-render-html": "^6.3.4",
"react-native-safe-area-context": "4.8.2",
"react-native-sass-transformer": "^2.1.1",
"react-native-screens": "~3.29.0",
"react-native-svg": "14.1.0",
"react-native-vector-icons": "^9.1.0",
"react-native-webview": "13.6.4",
"react-pdf": "^6.2.2",
"react-redux": "^7.2.0",
"redux": "^4.0.5",
"redux-persist": "^6.0.0",
"rn-pdf-reader-js": "^4.1.1",
"sentry-expo": "~7.2.0",
"yarn": "^1.22.21"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/lodash": "^4.14.168",
"@types/moment": "^2.13.0",
"@types/qs": "^6.9.7",
"@types/react": "~18.2.14",
"@types/react-native-collapsible": "^0.11.0",
"@types/react-pdf": "^6.2.0",
"@types/react-redux": "^7.1.7",
"husky": "~3.0.8",
"jest": "^29.2.1",
"lint-staged": "~9.4.2",
"prettier": "~1.19.1",
"sass": "^1.71.1",
"tslint": "~5.20.1",
"tslint-config-prettier": "~1.18.0",
"typescript": "^5.1.3"
},
"lint-staged": {
"*.{ts,tsx}": [
"tslint --fix --project tsconfig.lint.json",
"prettier --write",
"git add"
],
"locales/*.json": [
"prettier --write",
"git add"
]
}
}```
Thanks! Yeah newest Expo version (50) is not supported yet. I'll need to have a look at fixing that.
Excuse me, have you solved it now?
@25juan sorry, not yet. I'll try to remember to have a look at it this weekend.
The fix itself is not that complicated, it's just that the transformer path that Expo uses is a custom one: https://github.com/kristerkari/react-native-svg-transformer/blob/master/index.js#L14
I wanted to follow up on whether this has been fixed.
I am experiencing the same issue - is there any fix yet?
my metro.config.js might by off though (tried both sassTransformerPath
and sassTransformer
):
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.transformer = {
...config.transformer,
babelTransformerPath: require.resolve('react-native-svg-transformer'),
sassTransformerPath: require.resolve('react-native-sass-transformer'),
};
config.resolver = {
...config.resolver,
assetExts: config.resolver.assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...config.resolver.sourceExts, 'scss', 'sass'],
};
module.exports = config;
Sorry, I know that there are many that have been waiting for the update, but I haven't had time to look at it yet.
I want to cleanup the code for the transformer at the same time when adding the Expo support, which needs me to do a bit of testing using a React Native app together with the transformer. I'll try to find some time soon to fixing this.
This should be fixed in the newest 3.0.0 version. Please let me know if you are still facing any problems after updating.
https://github.com/kristerkari/react-native-sass-transformer/releases/tag/v3.0.0
Hello, I haven't managed to get the latest 3.0.0 version working with Expo v50. No errors, scss styles are still an empty object.
I made a minimal demo and tested it on Android emulator: https://github.com/Jankku/expo-rnst
I also quickly tried the new version with Expo 50, and it just threw some weird internal error.
I have to try to figure out why it's failing. Thanks for the repro, I'll have a look at it too!
I had a bit deeper look into this problem, and the reason that Expo 50/51 is not working seems to be because they are doing some custom handling for CSS and Sass files for Web in their custom transformer: https://github.com/expo/expo/blob/main/packages/%40expo/metro-config/build/transform-worker/transform-worker.js#L173-L178
I have not yet found a fix, but at least I now know why it's happening.
@kristerkari still have
@kristerkari
I was able to come up with a tempoary solution for sdk 51 & 50
Creating a custom transformer worker
I removed all the css processing that was done and ended up with this
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const worker = __importStar(require("@expo/metro-config/build/transform-worker/metro-transform-worker"));
async function transform(config, projectRoot, filename, data, options) {
const environment = options.customTransformOptions?.environment;
const isClientEnvironment = environment !== 'node' && environment !== 'react-server';
if (isClientEnvironment &&
(filename.match(new RegExp(`^app/\\+html(\\.${options.platform})?\\.([tj]sx?|[cm]js)?$`)) ||
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/))) {
return worker.transform(config, projectRoot, filename, !options.minify
? Buffer.from('"> The server-only file was removed from the client JS bundle by Expo CLI."')
: Buffer.from(''), options);
}
if (isClientEnvironment &&
!filename.match(/\/node_modules\//) &&
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/)) {
return worker.transform(config, projectRoot, filename, Buffer.from(''), options);
}
return worker.transform(config, projectRoot, filename, data, options);
}
exports.transform = transform;
/**
* A custom Metro transformer that adds support for processing Expo-specific bundler features.
*/
module.exports = {
...worker,
transform,
};
//# sourceMappingURL=transform-worker.js.map
Update metro config
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname, {
isCSSEnabled: true,
});
config.transformerPath = require.resolve('./custom-transformer')
config.transformer.babelTransformerPath = require.resolve("react-native-sass-transformer")
config.transformer.assetPlugins = ['expo-asset/tools/hashAssetFiles'];
config.resolver.assetExts = [...config.resolver.assetExts, 'ttf'];
config.resolver.sourceExts = [...config.resolver.sourceExts, 'scss', 'sass'];
module.exports = config;
Thanks @iyosayi0x !
Here's a slightly cleaned up version of your workaround:
transform-worker.js
const worker = require("@expo/metro-config/build/transform-worker/metro-transform-worker.js");
async function transform(config, projectRoot, filename, data, options) {
const environment = options.customTransformOptions?.environment;
const isClientEnvironment =
environment !== "node" && environment !== "react-server";
if (
isClientEnvironment &&
(filename.match(
new RegExp(`^app/\\+html(\\.${options.platform})?\\.([tj]sx?|[cm]js)?$`)
) ||
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/))
) {
return worker.transform(
config,
projectRoot,
filename,
!options.minify
? Buffer.from(
'"> The server-only file was removed from the client JS bundle by Expo CLI."'
)
: Buffer.from(""),
options
);
}
if (
isClientEnvironment &&
!filename.match(/\/node_modules\//) &&
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/)
) {
return worker.transform(
config,
projectRoot,
filename,
Buffer.from(""),
options
);
}
return worker.transform(config, projectRoot, filename, data, options);
}
module.exports = transform;
module.exports = {
...worker,
transform,
};
metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
module.exports = (() => {
const config = getDefaultConfig(__dirname);
const { transformer } = config;
return {
...config,
transformerPath: require.resolve("./transform-worker.js"),
transformer: {
...transformer,
babelTransformerPath: require.resolve("react-native-sass-transformer"),
},
};
})();