Skip to content
This repository has been archived by the owner on Jul 6, 2021. It is now read-only.

SyntaxError on CSS file imported from node_modules. #266

Closed
trusktr opened this issue Sep 18, 2018 · 27 comments
Closed

SyntaxError on CSS file imported from node_modules. #266

trusktr opened this issue Sep 18, 2018 · 27 comments

Comments

@trusktr
Copy link

trusktr commented Sep 18, 2018

I've added @zeit/next-css and am using withCSS on my config, but the build complains about syntax errors when trying to import a CSS file (I presume the CSS file is being treated as a JS file).

How do we import CSS from node_modules?

@kachkaev
Copy link
Contributor

Hi @trusktr! Can you provide an example showing how and from where you refer to the css file?

@trusktr
Copy link
Author

trusktr commented Sep 18, 2018

Basically next.config.js is

const withCSS = require('@zeit/next-css')

module.exports = withCSS({
  cssModules: false,
})

and in my code I do

import "tiny-slider/dist/tiny-slider.css"

which yields the error

Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| .tns-outer{padding:0 !important}.tns-outer [hidden]{display:none !important} ... TRUNCATED ...

@trusktr
Copy link
Author

trusktr commented Sep 18, 2018

Do you have a Next.js CodeSandbox or StackBlitz I can fork to reproduce?

@kachkaev
Copy link
Contributor

kachkaev commented Sep 18, 2018

can you try require("tiny-slider/dist/tiny-slider.css")?

Here's an example project that uses next-css: https://github.com/zeit/next.js/tree/master/examples/with-next-css

@trusktr
Copy link
Author

trusktr commented Sep 18, 2018

Yep, looks like require instead of import works. That was unexpected though.

@kachkaev
Copy link
Contributor

A problem with import 'something.css' would certainly be the case if your file is a typescript one and you are not using babel to load it. There may be other cases as well, I'm not sure.

Feel free to close this issue if you think that this problem is resolved 😉

@trusktr
Copy link
Author

trusktr commented Sep 18, 2018

I'm using Next's default babel loader with @zeit/next-typescript. Should that work?

Here's my full config:

const path = require('path')
const withTypescript = require('@zeit/next-typescript')
const withCSS = require('@zeit/next-css')
const r = require('regexr')

const cssConfig = {
  cssModules: false,
}

const typescriptConfig = {}

const transpileModulesConfig = {
  transpileModules: [
    '@awaitbox/window-loaded',
    'tiny-slider',
  ],
}

const nextConfig = withTranspileModules(withTypescript(withCSS({
  ...cssConfig,
  ...typescriptConfig,
  ...transpileModulesConfig,

  // This is relative to src, because we run Next.js in the src folder (`next ./src`)
  distDir: '../.dist',

})))

// plugin to transpile specific node_modules packages
// See:
//  - https://github.com/zeit/next.js/pull/3732
function withTranspileModules(nextConfig) {

  const internalRegExps = nextConfig.transpileModules.map(m => {
    if (typeof m === 'string') return r`${r.escape(m)}(?!.*node_modules)`
    if (m instanceof RegExp) return m
    throw new TypeError('transpileModules should contain strings or RegExps only.')
  })

  const externalRegExps = nextConfig.transpileModules.map(m => {
    if (typeof m === 'string') return r`node_modules(?!\/${r.escape(m)}(?!.*node_modules))`
    return m
  })

  let jsRule

  function createJSRule(webpackConfig, nextOptions) {
    const {defaultLoaders} = nextOptions

    webpackConfig.module.rules.push(jsRule = {
      test: /\.+(js|jsx|ts|tsx)$/,
      loader: defaultLoaders.babel,
      include: []
    })
  }

  return {
    ...nextConfig,

    webpack(config, next) {
      config.resolve.symlinks = false

      // Next runs the dev config first, then the server config, so we reset rule
      // here when Next switches to the server config
      if (next.isServer) jsRule = null
      if (!jsRule) createJSRule(config, next)

      jsRule.include = internalRegExps

      config.externals = config.externals.map(external => {
        if (typeof external !== "function") return external
        return (ctx, req, cb) => internalRegExps.some(regex => regex.test(req)) ? cb() : external(ctx, req, cb)
      })

      if (typeof nextConfig.webpack === 'function')
        config = nextConfig.webpack(config, next)

      return config
    },

    webpackDevMiddleware(config) {
      const ignored = [...config.watchOptions.ignored, ...externalRegExps]
      config.watchOptions.ignored = ignored

      if (typeof nextConfig.webpackDevMiddleware === 'function')
        config = nextConfig.webpackDevMiddleware(config)

      return config
    },
  }
}

module.exports = nextConfig

You can see there I'm using the default loader:

    webpackConfig.module.rules.push(jsRule = {
      test: /\.+(js|jsx|ts|tsx)$/,
      loader: defaultLoaders.babel,
      include: []
    })

Did I mess it up?

@kachkaev
Copy link
Contributor

What’s the version of your loader and next?

@trusktr
Copy link
Author

trusktr commented Sep 18, 2018

I've got

❯ npm list next @zeit/next-css @zeit/next-typescript
[email protected] /Users/trusktr/public-website
├── @babel/[email protected]
├── @zeit/[email protected]
├── @zeit/[email protected]
└── [email protected]

and my babelrc looks like

{
  "presets": [
    "next/babel",
    "@zeit/next-typescript/babel"
  ],
  "plugins": [
    ["@babel/plugin-proposal-decorators", {
      "legacy": true
    }]
  ]
}

The rest are dependencies of those packages (including Babel, which is on beta.42)

@kachkaev
Copy link
Contributor

Might be worth upgrading to canary - there’s stable babel 7 there

@mtree
Copy link

mtree commented Sep 19, 2018

@kachkaev i'm using canary and I have almost same problem #267

@kachkaev
Copy link
Contributor

kachkaev commented Sep 19, 2018

New plugin versions have just been released. Next.js itself is 7.0.0 now. Does upgrading help?

@phloe
Copy link

phloe commented Sep 19, 2018

With [email protected] and @zeit/[email protected] it makes no difference for me :(

@mtree
Copy link

mtree commented Sep 19, 2018

Same here. I also tried to ignore plugin/loader /\.css$/. No matter what, it always fails with SyntaxError inside one of node_modules CSS files.

@penx
Copy link

penx commented Dec 10, 2018

Try this in next.config.js:

const withTM = require('next-plugin-transpile-modules');

module.exports = withTM({
  transpileModules: ['tiny-slider'],
...

(swap out tiny-slider for whichever node module contains your css files)

@phloe
Copy link

phloe commented Dec 11, 2018

There's a bunch of issues related to this problem (if not pure duplicates) - some of them have already had posted a working (temporary?) solution: #267 (comment)

Worked great for me :)

@ecrofeg
Copy link

ecrofeg commented Feb 22, 2019

Same here. I also tried to ignore plugin/loader /\.css$/. No matter what, it always fails with SyntaxError inside one of node_modules CSS files.

Did you managed to get it work?

@Vrq
Copy link

Vrq commented Mar 20, 2019

If you are coming from Google search, especially if you still see the:

Module build failed: ModuleParseError: Module parse failed: Unexpected character '' (1:0) You may need an appropriate loader to handle this file type.

this might be the solution you are looking for.

3 simple steps:

  1. Install next-css plugin:
npm install --save @zeit/next-css
  1. Create in your root directory next.config.js with the following content:
// next.config.js 
const withCSS = require('@zeit/next-css')

module.exports = withCSS({
  cssLoaderOptions: {
    url: false
  }
})
  1. Now you should be able to import styleshets from node_modules like this:
import 'bootstrap-css-only/css/bootstrap.min.css';

Note: Using Next v 8+

Background:
I spent a few hours trying to simply import a CSS installed as a node_module and the various solutions are mostly hacky workarounds, but as shown above, there is a simple solution.
It was provided by one of the core team members: https://spectrum.chat/next-js/general/ignoring-folders-files-specifically-fonts~4f68cfd5-d576-46b8-adc8-86e9d7ea0b1f

@rap2hpoutre
Copy link

Thanks @Vrq. Since NextCSS has a non-resolved issue "very hard to resolve": #282 (comment) about Router and CSS, I think it's not a viable solution. I just rewrote my whole app with styled component because of this issue, and I think there should be a workaround for people who don't rely on next/css.

@rishacha
Copy link

I still face this :
image

Here's my next.config.js

/**
 * Next config for Next.js app
 *
 */


const withCSS = require('@zeit/next-css');
require('dotenv').config({ silent: true });
const path = require('path');
const Dotenv = require('dotenv-webpack');

module.export = withCSS({
  cssLoaderOptions: {
    url: false,
  },
  webpack: (config) => {
    // const config = {};

    config.plugins = config.plugins || [];

    config.plugins = [
      ...config.plugins,
      // Read the .env file
      new Dotenv({
        path: path.join(__dirname, '.env'),
        systemvars: true,
      }),
    ];

    return config;
  },
});

Here's how I'm importing.

...

// Top level import
import React, { Component } from 'react';
// Import Major components
import Head from 'next/head';
import 'bootstrap/dist/css/bootstrap.min.css';

...

markspanbroek added a commit to sustainablesource/sustainablesource that referenced this issue May 20, 2019
markspanbroek added a commit to sustainablesource/sustainablesource that referenced this issue May 20, 2019
markspanbroek added a commit to sustainablesource/sustainablesource that referenced this issue May 20, 2019
markspanbroek added a commit to sustainablesource/sustainablesource that referenced this issue May 20, 2019
markspanbroek added a commit to sustainablesource/sustainablesource that referenced this issue May 20, 2019
markspanbroek added a commit to sustainablesource/sustainablesource that referenced this issue May 27, 2019
@amirhoseinsalehi
Copy link

import your css file in _app.js,
Don't Import it in _document.js.

@haotangio
Copy link

@Vrq Your config could solve the problem. But it won't work if the css depends on local fonts (like font-awesome). As the font asset are not imported and expose by nextjs.

@balaf
Copy link

balaf commented Jul 9, 2019

This hasn't worked for me or I am doing it wrong. I want to import a component from npm which internally imports from "typeface-montserrat"
Next.js coplaints about @font-face on typeface-montserrat/invdex.css

@macalinao
Copy link

i have the same problem on next 9

@kenberkeley
Copy link

Sorry to see this issue lasts for over 1y

@mylastore
Copy link

This is still an issue if you use @zeit/next-css then next/css default css is disabled.

@timneutkens
Copy link
Member

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests