Amplify-js: Next.js project fails to build, Unexpected token : at dist/style.css

Created on 15 Aug 2019  路  26Comments  路  Source: aws-amplify/amplify-js

Description
I have Next.js project and have added aws-amplify. During the build, I get the following error:

> Build error occurred
{ /Users/imyjimmy/_tea/react-frontend/node_modules/@aws-amplify/ui/dist/style.css:13
:root {
^

SyntaxError: Unexpected token :
    at new Script (vm.js:79:7)
    at createScript (vm.js:251:10)
    at Object.runInThisContext (vm.js:303:10)
    at Module._compile (internal/modules/cjs/loader.js:656:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Module.require (internal/modules/cjs/loader.js:636:17)
    at require (internal/modules/cjs/helpers.js:20:18) type: 'SyntaxError', '$error': '$error' }
error Command failed with exit code 1.

I have looked at the solution described in https://github.com/aws-amplify/amplify-js/issues/1934 and my next.config.js has been set up accordingly:

if (typeof require !== 'undefined') {
  require.extensions['.less'] = () => {}
  require.extensions['.css'] = file => {}
}

module.exports = {
  webpack: (config, options) => {
    config.module.rules.push({
      test: /\.png$/,
      loader: require.resolve('url-loader'),
    })
    config.module.rules.push({
      test: /\.css$/,
      loader: [
        require.resolve('style-loader'),
        require.resolve('css-loader'),
        require.resolve('postcss-loader'),
      ],
    })
    return config
  },
  distDir: 'build',
}

However, the build still fails.

To Reproduce
I will create a minimum github project that shows this issue. For now, clone my repo:
I've created a minimum repo that shows this issue:

  1. [email protected]:imyjimmy/nextjs-aws-amplify.git
  2. yarn
  3. yarn build

Or, if you prefer to recreate from npx:

  1. npx create-next-app
  2. add the following: url-loader, css-loader, style-loader, postcss-loader, autoprefixer, aws-amplify, aws-amplify-react
  3. next.config.js
if (typeof require !== 'undefined') {
  require.extensions['.less'] = () => {}
  require.extensions['.css'] = file => {}
}

module.exports = {
  webpack: (config, options) => {
    config.module.rules.push({
      test: /\.png$/,
      loader: require.resolve('url-loader'),
    })
    config.module.rules.push({
      test: /\.css$/,
      loader: [
        require.resolve('style-loader'),
        require.resolve('css-loader'),
        require.resolve('postcss-loader'),
      ],
    })
    return config
  },
  distDir: 'build',
}
  1. pages/index.js
import { Authenticator } from 'aws-amplify-react'
...
<Nav />
<Authenticator hideDefault={true}>
  <div className='hero'>
  ...
</Authenticator>
  1. yarn build

Expected behavior
I expect the build to complete.

Desktop (please complete the following information):

  • OS: macOS 10.14.5
  • node v10.12.0
  • aws-amplify ^1.1.36
  • aws-amplify-react ^2.3.12
React SSR feature-request

Most helpful comment

Bump

All 26 comments

Can confirm I experience this as well. App builds fine with npm run dev, but crashes with the unexpected token error on npm run build. I know that #3279 is planned to fix this problem, but in the interest of finding a temporary workaround in the meanwhile, here's some more info.

Not sure if this is useful info, but: the solution from #1934 _is_ helping, but in npm run dev only. If you remove this fix:

if (typeof require !== 'undefined') {
  require.extensions['.less'] = () => {}
  require.extensions['.css'] = file => {}
}

...you will then find that npm run dev and npm run build now both fail with the same error.

Been surveying related issues, and what's interesting is that it appears this fix used to work in both dev and build, prior to around July 2019! But since July it has failed to work on build. This coincides with some other, similar issues popping up with unexpected token errors in css imports from node_modules with next (see, for example, zeit/next-plugins#266, zeit/next-plugins#498). This coincides with the release of Next 9. and in fact, according to JJ Kasper's reply this is because of a change in build in Next 9!

Now that we know exactly what's causing it, I think all we need for a hacky workaround is to do some Webpack magic to exclude those imports. I expect to have this working within a day or two and will post my fix when I do.

Have you tried using @zeit/next-css ?

Hmm, 2 days of tweaking the Webpack config, and I'm still stumped. I've tried the following

  1. Tried the approach from the Next with-ant-design example, which is to regex match the specific problem files (in our case, @aws-amplify/ui/dist/style.css), and then both externalize them and add a rule to use null-loader for them. No effect, Same error message as before, on both dev and build.

  2. Tried a scorched-earth approach of excluding every single CSS file with the above method. No effect. Same error message as before, on both dev and build.

  3. Tried approach 1, but removing the isServer check, so that @aws-amplify/ui/dist/style.css gets excluded from both the server it client bundles. No effect. Same error message as before, on both dev and build.

  4. Tried approach 2, but removing the isServer check, so that all CSS gets excluded from both the server and client bundles. No effect. Same error message as before, on both dev and build.

5-8. Tried each of the above, but now with next-css. Identical results in each case.

As best I can tell, regardless of what we do in the Webpack config is next.config.js, something is still pulling in @aws-amplify/ui/dist/style.css. I can't seem to get verbose enough output from next or webpack to figure out why this occurs.

  1. Skipped all this Webpack sorcery, and simply did the old require.extensions hack from above:
if (typeof require !== 'undefined') {
  require.extensions['.less'] = () => {}
  require.extensions['.css'] = file => {}
}

_This one is the only one that's made a difference_. When I do this, I can at least get dev working. But build fails, same error message as before. Curiously, it fails _after_ it reaches Compiled successfully. I've poked around in the next source, and it looks like the automatic prerendering (that ijjk said causes this issue) occurs after this message prints. This is as far as I've gotten.

Only thing I've found that gets build working is the horrible, horrible hack of going into @aws-amplify/ui/dist/style.css in a text editor and deleting its contents. That makes everything load just fine, as long as you don't actually want that CSS, and also don't care about breaking npm forever!

Have you tried using @zeit/next-css ?

@rakannimer Ah, just saw that @imyjimmy 's example wasn't using next-css. I was using next-css, but have tried it without also.

Have you tried starting from the next.js provided examples?

Go to either with-aws-amplify or with-aws-amplify-typescript
https://github.com/zeit/next.js/tree/canary/examples

Next and amplify can be made to behave with each other but it can be quite painful, mostly from Amplify's end.

Have you tried starting from the next.js provided examples?

Go to either with-aws-amplify or with-aws-amplify-typescript
https://github.com/zeit/next.js/tree/canary/examples

Next and amplify can be made to behave with each other but it can be quite painful, mostly from Amplify's end.

Yup, those examples which use only the aws-amplify package work perfectly. It's the React bindings (aws-amplify-react package) that make everything fall apart. Unfortunately this ties into #3365. Due to non-modularized code, it's tough to import anything from aws-amplify-react without pulling every bit of aws-related code into our app along with it. We're not actually using any of the presentational components, but we still get the CSS for them.

Going forward we'll probably go ahead with Next 9, and just remove aws-amplify-react and write our own bindings for aws-amplify. It'll be a bit of a pain, but will neatly solve this CSS issue and probably slim our bundle size too.

Okay, yeah, that's the same experience that I had. Sorry I didn't realize that those examples didn't use the react bindings. I ejected from aws-amplify-react, too, and it has been nice to get away from.

There are still various issues but they can usually be resolved by making sure that everything runs on the client with componentDidMount or useEffect. Sometimes I would use dynamic imports to make sure the package wasn't imported on the server

I have the same issue.
I have a package that builds react components using rollup. Let's call it components package. Components depends on another package called assets that has a bunch of svgs.

In my components rollup config, I marked assets as external so that the require/import are left in the bundle. This allows nextjs webpack to bundle the svg and choose the static path, instead of using data urls or embedding the path in the rollup bundle.

Components outputs two bundles, main (using require) and module (using es6 modules) in package.json.

So if I inspect the components bundle, I see require('assets/image.svg') in index.js and import ... from 'assets/image.svg' in index.es.js.

Similar to above, I only get the error for next build and not dev mode. It seems to be breaking on the require() in index.js and not the import in index.es.js. Deleting the require() allows it to build. I think this is because it is breaking on the server build but now the browser build. I tried adding require.extensions['.svg'] = () => {} in next.config.js but it doesn't help.

Going forward we'll probably go ahead with Next 9, and just remove aws-amplify-react and write our own bindings for aws-amplify

@vivshaw will this effort be open sourced anywhere?

Any updates on this?

I'm curious about this too. Anyone got this working?

As a temporary stopgap I published my own package, https://www.npmjs.com/package/aws-amplify-react-jz, which is a fork of aws-amplify-react minus the offending line, and it seems to work. It reflects their version 2.3.12

@imyjimmy thanks for that. Using it as - hopefully - a temporary solution.

Any update on this , Already spend couple of hours on this ,
I wondering why
:root <---- is not picked up ..its just normal css file . I looked at all the css selectors here ,
According to Mozilla https://developer.mozilla.org/en-US/docs/Web/CSS/:root

The :root CSS pseudo-class matches the root element of a tree representing the document. In HTML, :root represents the element and is identical to the selector html, except that its specificity is higher.

@sachinrajgire you have a couple options:

either delete everything in @aws-amplify/ui/dist/style.css or delete the import statement in the corresponding file (can't remember which file off the top of my head but you can search for it in your favorite code editor) or use my own custom package: https://www.npmjs.com/package/aws-amplify-react-jz

edit: get rid of the line import "@aws-amplify/ui/dist/style.css"; at packages/aws-amplify-react/src/Amplify-UI/Amplify-UI-Components-React.jsx

Thanks @imyjimmy

To get past the > :root { issue and render the Authenticator in Next.js you need to include @zeit/next-css package npm i --save @zeit/next-css. So your root ./next.config.js file should look like this:

const withCSS = require('@zeit/next-css')
global.navigator = () => null
if (typeof require !== 'undefined') {
    require.extensions['.less'] = () => {}
    require.extensions['.css'] = file => {}
}
module.exports = withCSS({
});

This will render the full withAuthenticator with styles and also polyfill the navigator for analytics so everything works for dev. Seems like some of this can be solved with a postcss config file as outlined in the next docs, example here: https://stackoverflow.com/questions/46592310/postcss-modules-and-next-js

Seems like in general there is an issue loading css from node_modules discussed here (this still fails on production build):
https://github.com/zeit/next-plugins/issues/266

And RFC for css support in next.js here:
https://github.com/zeit/next.js/issues/8626

Updated next.config.js that works for both dev and build (be sure to install amplify with npm i --save aws-amplify@next)

const withCSS = require('@zeit/next-css')
const resolve = require('resolve')
global.navigator = () => null
module.exports = withCSS({
    webpack (config, options) {
        const { dir, isServer } = options
        config.externals = []
        if (isServer) {
          config.externals.push((context, request, callback) => {
            resolve(request, { basedir: dir, preserveSymlinks: true }, (err, res) => {
              if (err) {
                return callback()
              }
              if (
                res.match(/node_modules[/\\].*\.css/)
                && !res.match(/node_modules[/\\]webpack/)
                && !res.match(/node_modules[/\\]@aws-amplify/)
              ) {
                return callback(null, `commonjs ${request}`)
              }
              callback()
            })
          })
        }
        return config
      }
});

@mlabieniec This works super well allowing me to remove all of the resolutions from my previous comment. Thanks a ton!!!! I am still experiencing build errors. However it is not related to navigator now.
This is the error
Error occurred prerendering page "/shop/[slugId]": Error: Minified React error #321;

I don't believe this pertains to this issue though, I think this is a separate config issue that I am having with my project.

I had the same issue using react-flexbox-grid. Managed to solve it using the module next-transpile-modules, like so:

const withSass = require('@zeit/next-sass');
const withCSS = require('@zeit/next-css');
const withTM = require('next-transpile-modules');

module.exports = withCSS(withSass(withTM({
  transpileModules: ['react-flexbox-grid']
})));

OK here is my current next.config.js and everything is working ok

```global.navigator = () => null;

if (typeof require !== 'undefined') {
require.extensions['.less'] = () => {}
require.extensions['.css'] = file => {}
}

module.exports = withPlugins([withCSS, withSass, withTM], {
transpileModules: ['bs-platform', 'bs-css', 'reason-apollo-hooks', 're-formality'],
pageExtensions: ['jsx', 'js', 'bs.js'],
resolve: {
modules: ['sass_loader'],
cssModules: true,
},
webpack (config, options) {
config.module.rules.push({
test: /.css$/,
loader: [
require.resolve('postcss-loader'),
],
});

// Fixes npm packages that depend on `fs` module
config.node = {
  fs: 'empty'
};
return config

},
})

@mlabieniec Thanks for your solution. Unfortunately it doesn't work when using React hooks due to config.externals = []

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Bump

@jskrt can you describe what's still broken for you? I've transitioned away from using AWS Amplify and haven't had time to look at this thread, but I think it's still relevant to lots of people.

@mlabieniec Thanks for your solution. Unfortunately it doesn't work when using React hooks due to config.externals = []

As quoted, hooks don't work with this solution. Has anybody found a solution that doesn't break hooks?

Edit: the solution by @eastuto appears to be working.

Edit2: wrote a gist that implements this solution more granularly and without using deprecated features of node.js.

With the latest release of aws-amplify-react, #5138 resolves this by moving the CSS to a separate import:

import '@aws-amplify/ui/dist/style.css';

https://aws-amplify.github.io/docs/js/react

Please open a new issue if your experience differs!

Was this page helpful?
0 / 5 - 0 ratings