Next-plugins: Multi plugins not working as result gets overwritten

Created on 21 Feb 2018  路  5Comments  路  Source: vercel/next-plugins

I need to use @zeit/next-css and @zeit/next-sass at the same time, but this is failing by just using module.exports = withCSS(withSass(...)) as only one type gets compiled.

I'm trying to provide a simple example including the result map to get the issue resolved. I'm referencing to the issues

https://github.com/zeit/next-plugins/issues/34
https://github.com/zeit/next-plugins/issues/69
https://github.com/zeit/next-plugins/issues/58
https://github.com/zeit/next.js/issues/3852

This is a simple example what I'm doing and what the result looks like.

static/styles/style.css

#content {
  font-size: 3rem
}

static/styles/style.sass

#title
  font-size: 1rem
````

**next.config.js**

```javascript
const withCSS = require('@zeit/next-css')
const withSass = require('@zeit/next-sass')

module.exports = withCSS(withSass({
  webpack: (config) => {
    return config
  }
}))

components/Header.js

import Head from 'next/head'
import '/static/styles/style.css'
import '/static/styles/style.sass'

export const Header = props => {
  return (
    <Head>
      <meta httpEquiv='content-type' content='text/html;charset=UTF-8' />
      <meta charSet='utf-8' />
      <title>Title</title>
      <link rel='stylesheet' href='/_next/static/style.css' />
    </Head>
  )
}

The result /.next/static/style.css content is only:

```css

content {

font-size: 1rem
}
/# sourceMappingURL=style.css.map/
````

I'm missing the compiled sass file.

If I switch next.config.js to withSass(withCSS({..})) the result is only:

```css

title {

font-size: 3rem; }
/# sourceMappingURL=style.css.map/
````

The map for the last one is:

{"version":3,"sources":["/Users/project/static/styles/style.sass"],"names":[],"mappings":"AAAA;EACE,gBAAgB,EAAE","file":"static/style.css","sourcesContent":["#title {\n  font-size: 3rem; }\n\n\n\n// WEBPACK FOOTER //\n// ./static/styles/style.sass"],"sourceRoot":""}

Most helpful comment

@jaqua

58 is just another pattern for combining plugins. It gives additional functionality (every plugin has his own config), but it will be useful if #55 will be merged. Then will be easy to create 2 or more style files (for example vendor.css and app.css). And it will not resolve your problem.

Your trouble can be fixed by recalling commonsChunkConfig with correct extensions:

const withCSS = require('@zeit/next-css')
const withSass = require('@zeit/next-sass')
const commonsChunkConfig = require('@zeit/next-css/commons-chunk-config')

module.exports = withCSS(withSass({
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config = commonsChunkConfig(config, /\.(sass|scss|css)$/)
    }
    return config
  }
}))

The reason of that bug is CommonChunkPlugin which is working just for one extension (withCSS pass undefined and it used /.css$/, sass pass /.(sass|scss)$/, etc). You can find it here and here

All 5 comments

@jaqua

58 is just another pattern for combining plugins. It gives additional functionality (every plugin has his own config), but it will be useful if #55 will be merged. Then will be easy to create 2 or more style files (for example vendor.css and app.css). And it will not resolve your problem.

Your trouble can be fixed by recalling commonsChunkConfig with correct extensions:

const withCSS = require('@zeit/next-css')
const withSass = require('@zeit/next-sass')
const commonsChunkConfig = require('@zeit/next-css/commons-chunk-config')

module.exports = withCSS(withSass({
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config = commonsChunkConfig(config, /\.(sass|scss|css)$/)
    }
    return config
  }
}))

The reason of that bug is CommonChunkPlugin which is working just for one extension (withCSS pass undefined and it used /.css$/, sass pass /.(sass|scss)$/, etc). You can find it here and here

Currently on next 5.1.0

This doesn't work for me in production, especially the SSR, and if I view the generated css files directly. I have a library used called namespace-ee/react-calendar-timeline on github, and by including the library it also requires the css file directly.

import Timeline from 'react-calendar-timeline/lib';

I'm using this method because nextjs doesn't support some typescript/flow thing in there by default.

And I notice in production, the css included by the timeline keeps overwriting my other default scss which I included later in the page.

None of the solutions above works for me. (e.g. next-compose, commonsChunkConfig)


Edit

Nvm, turns out one of my package was outdated (@zeit/next-css was v0.1.2), after upgraded to the latest (v0.1.5) it works working SSR now.

even with suggestions from @JerryCauser it doesn't work for me.
I have a project with antd (less) and my own sass stylesheets and the result is:
a) if I don't include my sass file - less get's compiled, but sass doesn't
b) if I do - less doesn't, sass does

I've come across two issues at the same time which are #21 and this one.
This is because, I use some third party libraries which required to include css (react-datepicker). And I prefer to develop component using SASS instead of styled jsx (I haven't use less)

In the end, I've create withSSSS to combine all css, sass, scss, less and it seem to solve my case (may be this case)

```javascript
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const cssLoaderConfig = require('@zeit/next-css/css-loader-config')
const commonsChunkConfig = require('@zeit/next-css/commons-chunk-config')
const MergeFilesPlugin = require('merge-files-webpack-plugin')

module.exports = (nextConfig = {}) => {
return Object.assign({}, nextConfig, {
webpack(config, options) {
if (!options.defaultLoaders) {
throw new Error(
'This plugin is not compatible with Next.js versions below 5.0.0 https://err.sh/next-plugins/upgrade'
)
}

  const { dev, isServer } = options
  const { 
    cssModules, 
    cssLoaderOptions, 
    postcssLoaderOptions, 
    sassLoaderOptions = {},
    lessLoaderOptions = {},
  } = nextConfig

  // Support the user providing their own instance of ExtractTextPlugin.
  // If extractCSSPlugin is not defined we pass the same instance of ExtractTextPlugin to all css related modules
  // So that they compile to the same file in production
  let extractCSSPlugin =
    nextConfig.extractCSSPlugin || options.extractCSSPlugin

  //the ORIGINAL from next-css
  if (!extractCSSPlugin) {
    extractCSSPlugin = new ExtractTextPlugin({
      filename: 'static/style.css'
    })
    config.plugins.push(extractCSSPlugin)
    options.extractCSSPlugin = extractCSSPlugin
    if (!isServer) {
      config = commonsChunkConfig(config, /\.(sass|scss|less|css)$/)
    }
  }

  //the OVERWRITTEN
  //using MergeFilesPlugin to combile all css files into one file
  //ref: https://github.com/zeit/next-plugins/issues/21 
  if (!isServer && !dev) {
    // Override next-css configuration
    options.extractCSSPlugin.filename = 'static/[name].css';
    // Merge all CSS in one file
    config.plugins.push(
      new MergeFilesPlugin({
        filename: 'static/style.css',
        test: /\.css/,
        deleteSourceFiles: true,
      })
    )
  }

  options.defaultLoaders.css = cssLoaderConfig(config, extractCSSPlugin, {
    cssModules,
    cssLoaderOptions,
    postcssLoaderOptions,
    dev,
    isServer
  })

  options.defaultLoaders.sass = cssLoaderConfig(config, extractCSSPlugin, {
    cssModules,
    cssLoaderOptions,
    postcssLoaderOptions,
    dev,
    isServer,
    loaders: [
      {
        loader: 'sass-loader',
        options: sassLoaderOptions
      }
    ]
  })

  options.defaultLoaders.less = cssLoaderConfig(config, extractCSSPlugin, {
    cssModules,
    cssLoaderOptions,
    postcssLoaderOptions,
    dev,
    isServer,
    loaders: [
      {
        loader: 'less-loader',
        options: lessLoaderOptions
      }
    ]
  })

  config.module.rules.push({
    test: /\.css$/,
    use: options.defaultLoaders.css
  })

  config.module.rules.push({
    test: /\.scss$/,
    use: options.defaultLoaders.sass
  },{
    test: /\.sass$/,
    use: options.defaultLoaders.sass
  })

  config.module.rules.push({
    test: /\.less$/,
    use: options.defaultLoaders.less
  })

  if (typeof nextConfig.webpack === 'function') {
    return nextConfig.webpack(config, options)
  }

  return config
}

})
}
````

@supadits Have you considered creating an NPM package for withSSSS?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

popuguytheparrot picture popuguytheparrot  路  4Comments

pencilcheck picture pencilcheck  路  4Comments

suppayami picture suppayami  路  3Comments

sebas-deedee picture sebas-deedee  路  3Comments

harrysolovay picture harrysolovay  路  4Comments