Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Styles are imported as empty object with RN 73 #106

Open
vivtung opened this issue Mar 7, 2024 · 13 comments · Fixed by #112
Open

Styles are imported as empty object with RN 73 #106

vivtung opened this issue Mar 7, 2024 · 13 comments · Fixed by #112

Comments

@vivtung
Copy link

vivtung commented Mar 7, 2024

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"
    ]
  }
}```
@vivtung vivtung changed the title Styles are imported as empty object with Expo 50 Styles are imported as empty object with RN 73 Mar 7, 2024
@kristerkari
Copy link
Owner

Thanks! Yeah newest Expo version (50) is not supported yet. I'll need to have a look at fixing that.

@25juan
Copy link

25juan commented Mar 24, 2024

Excuse me, have you solved it now?

@kristerkari
Copy link
Owner

@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

@carlos-lao
Copy link

I wanted to follow up on whether this has been fixed.

@chRohowski
Copy link

chRohowski commented May 14, 2024

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;

@kristerkari
Copy link
Owner

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.

@kristerkari
Copy link
Owner

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

@Jankku
Copy link

Jankku commented May 21, 2024

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

@kristerkari
Copy link
Owner

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!

@kristerkari kristerkari reopened this May 21, 2024
@kristerkari
Copy link
Owner

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.

@ryskin
Copy link

ryskin commented Jun 24, 2024

@kristerkari still have

@iyosayi0x
Copy link

@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;

@kristerkari
Copy link
Owner

kristerkari commented Jul 6, 2024

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"),
    },
  };
})();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
8 participants