Next-plugins: Making global Sass mixins available without manual imports

Created on 16 Mar 2019  路  8Comments  路  Source: vercel/next-plugins

Has anyone been able to use Sass mixins without importing them into every page or component? I would like to make them available using webpack or just import them once in app.tsx, and use them. Unfortunately importing it in app doesn't make the mixins available to child pages.

import React from "react";
import App, { Container } from "next/app";
import globalStyles from "./app.scss";
import "@/styles/index.scss";

/*
Next.js uses the App component to initialize pages. You can override it and control the page initialization. Which allows you to do amazing things like:
Persisting layout between page changes
Keeping state when navigating pages
Custom error handling using componentDidCatch
Inject additional data into pages (for example by processing GraphQL queries)
*/

export default class CustomApp extends App {
  static async getInitialProps({ Component, ctx }) {
    const pageProps = Component.getInitialProps
      ? await Component.getInitialProps(ctx)
      : {};
    return { pageProps };
  }

  render() {
    const { Component, pageProps } = this.props;

    return (
      <Container>
        <style dangerouslySetInnerHTML={{ __html: globalStyles as any }} />
        <Component {...pageProps} />
      </Container>
    );
  }
}

Has anyone been able to make their Sass helpers available without importing it into every component ?

Most helpful comment

I got to a solution using sass-resources-loader (https://github.com/shakacode/sass-resources-loader) and patching it into the webpack config rules provided by the next-sass plugin
Here's what my next.config.js looks like

const withSass = require("@zeit/next-sass");
const resourcesLoader = {
    loader: "sass-resources-loader",
    options: {
        resources: [
            "./sass/_breakpoint.scss",
            "./sass/_mediaqueries.scss",
            "./sass/_variables.scss"
        ]
    }
};
module.exports = withSass({
    cssModules: true,
    cssLoaderOptions: {
        importLoaders: 1,
        localIdentName: "[name]__[local]___[hash:base64:5]"
    },
    webpack: (config, options) => {
        config.module.rules.map(rule => {
            if (
                rule.test.source.includes("scss") ||
                rule.test.source.includes("sass")
            ) {
                rule.use.push(resourcesLoader);
            }
        });
        return config;
    }
});

All 8 comments

Any answers so far?

I'm having an issue with this as well

Same issue 鈽癸笍

I got to a solution using sass-resources-loader (https://github.com/shakacode/sass-resources-loader) and patching it into the webpack config rules provided by the next-sass plugin
Here's what my next.config.js looks like

const withSass = require("@zeit/next-sass");
const resourcesLoader = {
    loader: "sass-resources-loader",
    options: {
        resources: [
            "./sass/_breakpoint.scss",
            "./sass/_mediaqueries.scss",
            "./sass/_variables.scss"
        ]
    }
};
module.exports = withSass({
    cssModules: true,
    cssLoaderOptions: {
        importLoaders: 1,
        localIdentName: "[name]__[local]___[hash:base64:5]"
    },
    webpack: (config, options) => {
        config.module.rules.map(rule => {
            if (
                rule.test.source.includes("scss") ||
                rule.test.source.includes("sass")
            ) {
                rule.use.push(resourcesLoader);
            }
        });
        return config;
    }
});

@arseyg patching the webpack config rules on next-sass conflicts with next-typescript and gives me a parsing error:

Failed to compile.

./pages/_error.tsx 3:0
Module parse failed: The keyword 'interface' is reserved (3:0)
You may need an appropriate loader to handle this file t
ype.| import React from 'react'
| > interface Props {
|   res: string;|   err: string;

Not sure if it's the ordering of it because here's what my config looks like:

    [
      withTypescript,
      {
        webpack(config, options) {
          // only add plugin in development to client webpack config .
          if (env === 'development' && !options.isServer) {
            config.plugins.push(new ForkTsCheckerWebpackPlugin())
          }

          return config
        },
      },
    ],
    [
      withSass,
      {
        cssModules: true,
        cssLoaderOptions: {
          importLoaders: 1,
          localIdentName: '[local]___[hash:base64:5]',
        },
        sassLoaderOptions: {
          includePaths: [path.resolve(__dirname, './@'), 'node_modules'],
        },
        webpack: (config, options) => {
          config.module.rules.map((rule) => {
            if (rule.test.source.includes('scss')) {
              rule.use.push(resourcesLoader)
            }
          })
          return config
        },
      },
    ],

Having the sass config before the typescript config gives the reverse parsing error:

./@/components/Footer/Footer.scss 1:0
Module parse failed: Unexpected character '@' (1:0)You may need an appropriate loader to handle this file t
ype.> @import './@/styles/index.scss';

@fandy My setup is a bit different, I'm not using typescript so can't reproduce this, but you might need to wrap withSass inside withTypescript as seen in the docs https://nextjs.org/docs#customizing-webpack-config ?

module.exports = withTypescript(
  withSass({
    webpack(config, options) {
      // Further custom configuration here
      return config;
    }
  })
);

I'm using next-compose which is the equivalent of wrapping it inside 馃檨

Hi, thanks for creating an issue. We currently recommend using nextjs.org/docs/basic-features/built-in-css-support as the plugins have been deprecated in favor of the built-in support.

Was this page helpful?
0 / 5 - 0 ratings