basics / nuxt-booster

nuxt-booster will help you to improve the lighthouse performance score (100/100) of your website. 🚀
https://basics.github.io/nuxt-booster/
MIT License
652 stars 32 forks source link

Module parse failed: Unexpected character '#' (2:2) #660

Closed elons-cat closed 2 years ago

elons-cat commented 2 years ago

Describe the bug I get a loader error when trying to setup nuxt-speedkit.

To Reproduce Steps to reproduce the behavior:

  1. Installed following instructions.

Following error occurs

 ERROR  in ../node_modules/nuxt-speedkit/plugins/vFont/head.js                                                                                                                                                      friendly-errors 14:34:21

Module parse failed: Unexpected token (36:36)                                                                                                                                                                       friendly-errors 14:34:21
File was processed with these loaders:
 * ../node_modules/cache-loader/dist/cjs.js
 * ../node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|
|
>   const nuxtStateData = (this.$nuxt?.context || this.context)?.nuxtState?.data;
|
|   if (nuxtStateData && nuxtStateData.length) {
                                                                                                                                                                                                                    friendly-errors 14:34:21
 @ ./.nuxt/nuxt-speedkit/plugin.js 8:0-56 78:12-16
 @ ./.nuxt/index.js
 @ ./.nuxt/client.js
 @ ./.nuxt/nuxt-speedkit/entry.js
 @ multi ../node_modules/eventsource-polyfill/dist/browserify-eventsource.js ../node_modules/webpack-hot-middleware/client.js?reload=true&timeout=30000&ansiColors=&overlayStyles=&path=%2F__webpack_hmr%2Fclient&overlay=false&name=client ./.nuxt/nuxt-speedkit/entry.js
                                                                                                                                                                                                                    friendly-errors 14:34:21

Additional context This happens for all the speed-kit plugins.

ThornWalli commented 2 years ago

Hello 🙂

which Node version are you using?

elons-cat commented 2 years ago

Hi :)

Node v16.16.0

ThornWalli commented 2 years ago

Mmhh Could I see your nuxt.config maybe? 🙂

Did you make any customizations at babel? Suspect it's at https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/Optional_chaining

elons-cat commented 2 years ago

I think that you may be unto something!

import fs from 'fs';
import EventEmitter from 'events';

import { DefinePlugin, IgnorePlugin, NormalModuleReplacementPlugin } from 'webpack';
import merge from 'lodash/merge';

import { resolveFlavouredRequest, logWebpackConfig, root, rootUrl, getMappedSourceIntake, redisSentinelArray } from './config/helpers';
import makeAliases from './config/aliases';
import { argv } from './config/yargs';
import loadEnv from './config/env';
import antdTheme from './config/antd.theme.js';

// prevent MaxListenersExceededWarning, memory leak error
EventEmitter.defaultMaxListeners = 30;

process.env.TZ = 'Europe/Amsterdam';

const env = loadEnv({
  flavour: argv.flavour,
});

const VUE_SRC = '../vue/src';

const ROOT_URL = rootUrl(env);

env.PORT = env.PORT || 3901;

const secureServer = (env.NODE_ENV === 'development' || env.NUXT_FORCE_SECURE_SERVER === 'true')
  && fs.existsSync(root('config/certs-dev/server.key'));

export default {
  server: {
    port: env.PORT,
    host: '0.0.0.0',
    ...secureServer
      ? {
        https: {
          key: fs.readFileSync(root('config/certs-dev/server.key')),
          cert: fs.readFileSync(root('config/certs-dev/server.crt')),
        },
      } : {},
  },

  router: {
    middleware: [
      'clearCaches',
      'redirection',
      'redirectionYoast',
      'redirectTrailingSlash',
      'redirectLogout',
      'redirectAmp',
      'headers',
    ],
},

  plugins: [
    '~/plugins/redis',
    '~/plugins/flavours',
    '~/plugins/sentry',
    '~/plugins/i18n',
    '~/plugins/vue-async-computed',
    '~/plugins/log-axios-requests',
    '~/plugins/axios',
    '~/plugins/event-bus',
    '~/plugins/nuxt-server-api',
    '~/plugins/font-awesome',
    '~/plugins/antd.js',
    '~/plugins/scroll-spy.client',
    '~/plugins/third-party',
    '~/plugins/mixpanel-listeners.client',
    '~/plugins/god-mode',
    '~/plugins/vue-scroll-to',
    '~/plugins/vue-clipboard',
    '~/plugins/hubspot.client',
    { src: '~/plugins/polyfills.js', mode: 'client' },
  ],

  modules: [
    env.PROMETHEUS_EXPORTER_PORT && [
      '@/modules/prometheus-module',
      {
        port: env.PROMETHEUS_EXPORTER_PORT,
      },
    ],
    'nuxt-i18n',
    '@/modules/axiosCache',
    '@/modules/redis',
    '@nuxtjs/sentry',
    '@nuxtjs/apollo',
    '@nuxtjs/axios',
    '@nuxtjs/proxy',
    '@nuxtjs/gtm',
    '@nuxtjs/robots',
    'nuxt-speedkit',
    '@/modules/sitemap-generator',
    '@nuxtjs/sitemap',
  ].filter(Boolean),

  ignore: [
    '**/*.test.*',
    '**/*.spec.*',
  ],

  build: {
    extractCSS: env.NODE_ENV === 'production',

    splitChunks: {
      layouts: false,
      pages: true,
      commons: true,
    },

    optimization: {
      minimize: true,
      runtimeChunk: 'single',
      splitChunks: {
        maxInitialRequests: Infinity,
        // Will be overwritten in extend () => {}
        minSize: 1000,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name(module) {
              // get the node_module name
              const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

              // some servers don't like @ symbols
              return `npm.${packageName.replace('@', '')}`;
            },
            priority: 5,
          },
        },
      },
    },

    filenames: {
      chunk: ({ isDev, isModern }) => {
        return isDev
          ? `[name]${isModern ? '.modern' : ''}.js`
          : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`;
      },
    },

    extend(config, ctx) {
      const aliases = makeAliases(VUE_SRC);

      config.resolve.alias = {
        ...config.resolve.alias,
        ...aliases,
      };

      // force use of common vue package with template compiler
      config.resolve.alias['vue$'] = root('../node_modules/vue/dist/vue.esm.js');

      // force to use nuxt node_modules
      config.resolve.alias['moment'] = root('../node_modules/moment');
      config.resolve.alias['axios'] = root('../node_modules/axios');
      config.resolve.alias['@fortawesome'] = root('../node_modules/@fortawesome');
      config.resolve.alias['lodash'] = root('../node_modules/lodash');
      config.resolve.alias['apollo-client'] = root('../node_modules/apollo-client');
      config.resolve.alias['apollo-cache-inmemory'] = root('../node_modules/apollo-cache-inmemory');
      config.resolve.alias['@sentry'] = root('../node_modules/@sentry');
      config.resolve.alias['ant-design-vue'] = root('../node_modules/ant-design-vue');
      config.resolve.alias['tinycolor2'] = root('../node_modules/tinycolor2');
      config.resolve.alias['nuxt-speedkit'] = root('../node_modules/nuxt-speedkit');

      // Run ESLint on save
      if (env.TEST !== 'unit' && ctx.isDev && ctx.isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/,
          options: {
            parserOptions: {
              requireConfigFile: false,
            },
          },
        });
      }

      if (ctx.isDev) {
        // Small tweak for debugging in vscode
        // https://medium.com/js-dojo/debugging-nuxt-js-with-vs-code-60a1a9e75cf6
        config.devtool = ctx.isClient ? 'source-map' : 'inline-source-map';

        // skip sourcemaps for performance
        config.devtool = false;
      } else if (ctx.isClient) {
        config.devtool = 'source-map';
      }

      // adjust webpack for unit tests
      if (env.TEST === 'unit') {
        // Do not compile scss during unit test, speeds up testing and workaround for:
        // https://github.com/vuejs/vue-cli/issues/4053
        config.module.rules = config.module.rules.filter(rule => !rule.test.source.includes('.scss'));

        config.module.rules.unshift({
          test: /\.scss$/i,
          use: 'null-loader',
        });

        // disable vue loader optimizeSSR
        // https://github.com/vuejs/vue-loader/issues/885
        // otherwise throws errors like "_ssrNode in not a function" and _ssrEscape
        const vueLoaderRuleIndex = config.module.rules.findIndex(rule => rule.loader && rule.loader.includes('vue-loader'));
        config.module.rules[vueLoaderRuleIndex] = merge(
          config.module.rules[vueLoaderRuleIndex],
          {
            options: {
              extractCSS: false,
              optimizeSSR: false,
            },
          },
        );
      }

      // Adjust max. chunk size for client build
      if (env.NODE_ENV === 'production' && ctx.isClient) {
        config.optimization.splitChunks.minSize = 200000;
        config.optimization.splitChunks.maxSize = 300000;
      }

      logWebpackConfig(config, ctx.isClient);
    },

    loaders: {
      imgUrl: {
        esModule: false,
      },
      less: {
        javascriptEnabled: true,
        modifyVars: antdTheme,
      },
    },

    transpile: [
      ({ isServer }) => isServer && 'ant-design-vue',
    ],

    plugins: [
      // Flavoured files
      new NormalModuleReplacementPlugin(/\.FLAVOUR(\.|$)/, (resource) => {
        resource.request = resolveFlavouredRequest(resource.request);
      }),

      // Replace frequency list file in password strength package with custom file to cut down chunk size by 95%
      new NormalModuleReplacementPlugin(
        /node_modules\/zxcvbn\/lib\/frequency_lists\.js/,
        root('domains/common/lib/passwordFrequencyLists.js'),
      ),

      // Ignore Moment locales to decrease build size.
      new IgnorePlugin(/^\.\/locale$/, /moment$/),

      // Replace Ant-index.less with custom version to prevent global styles
      new NormalModuleReplacementPlugin(
        /node_modules\/ant-design-vue\/es\/style\/index\.less/,
        root('styles/antd/index.less'),
      ),
    ],

    babel: {
      presets({ envName }) {
        const envTargets = {
          client: {
            browsers: [
              'last 2 versions',
              'not ie 11',
              'not op_mini all',
            ],
          },
          server: { node: '16' },
        };

        return [
          ['@nuxt/babel-preset-app', {
            // Set to true for babel-preset-env debug logs.
            // Prints browser versions targeted for polyfills.
            debug: false,
            corejs: { version: 3 },
            targets: envTargets[envName],
          }],
        ];
      },

      plugins:
        env.TEST !== 'unit'
          ? [
            '@babel/plugin-proposal-optional-chaining',
            '@babel/plugin-proposal-nullish-coalescing-operator',
            ['import',
              {
                libraryName: 'ant-design-vue',
                libraryDirectory: 'es',
                style: true,
              },
              'import-ant-design-vue',
            ],
          ]
          : [],

      exclude: /node_modules\/(?!(ant-design-vue|@nuxt\/image)\/).*/,
    },

    hotMiddleware: {
      client: {
        // turn off client overlay when errors are present
        overlay: false,
      },
    },

    postcss: {
      plugins: {
        'postcss-custom-properties': false,
      },
    },
  },

  buildModules: [
    '@nuxt/postcss8',
    'nuxt-build-optimisations',
    '@nuxtjs/eslint-module',
    '@nuxtjs/pwa',
    '@nuxtjs/tailwindcss',
    '@nuxtjs/google-fonts',
    '@nuxtjs/moment',
    '@nuxt/image',
  ].filter(Boolean),

  render: {
    bundleRenderer: {
      // manually preload fonts from css
      shouldPreload: (file, type) => {
        return type === 'font' && file.includes('woff2');
      },
    },
  },

  head: {
    htmlAttrs: {
      lang: 'nl',
    },
  },

  publicRuntimeConfig: {
    apollo: {
      // Temporary flag for apollo client.query cache issue
      clientQueryCache: false,
    },
  },

  serverMiddleware: [
    '~/server_middleware/logRequests.js',
    { path: '/nuxt-server-api', handler: '~/server_middleware/nuxt_api/index.js' },
  ],

  buildOptimisations: {
    profile: 'experimental',
    features: {
      esbuildLoader: false,
      esbuildMinifier: false,
      imageFileLoader: true,
      webpackOptimisations: true,
      postcssNoPolyfills: false,
      cacheLoader: env.NODE_ENV === 'development',
      hardSourcePlugin: false,
    },
  },

  image: {
    // The screen sizes predefined by `@nuxt/image`:
    screens: {
      'default': 320,
      'xxs': 480,
      'xs': 576,
      'sm': 768,
      'md': 996,
      'lg': 1200,
      'xl': 1367,
      'xxl': 1600,
      '4k': 1921,
    },
    domains: ['https://img.youtube.com', 'https://i.vimeocdn.com'],
    alias: {
      youtube: 'https://img.youtube.com',
      vimeo: 'https://i.vimeocdn.com',
    },
  },

  speedkit: {
    detection: {
      performance: true,
      browserSupport: false,
    },
    performanceMetrics: {
      device: {
        hardwareConcurrency: { min: 2, max: 48 },
        deviceMemory: { min: 2 },
      },
      timing: {
        fcp: 800,
        dcl: 1200, // fallback if fcp is not available (safari)
      },
    },
    fonts: [{
      family: 'Buenos Aires',
      locals: ['Buenos Aires'],
      fallback: ['sans-serif'],
      variances: [
        {
          style: 'normal',
          weight: 300,
          sources: [
            { src: '@/assets/fonts/buenos-aires/BuenosAires-Regular.woff2', type: 'woff2' }],
        },
      ],
    }, {
      family: 'Aeonik',
      locals: ['Aeonik'],
      fallback: ['sans-serif'],
      variances: [
        {
          style: 'normal',
          weight: 300,
          sources: [
            { src: '@/assets/fonts/aeonik/Aeonik-Regular.woff2', type: 'woff2' },
          ],
        },
      ],
    }],

    loader: {
      dataUri: undefined,
      size: '100px',
      backgroundColor: 'transparent',
    },
  },

  sentry: {
    dsn: env.SENTRY_DSN,
    config: {
      environment: env.SENTRY_ENV_NAME,
      release: env.VERSION,
      // this looks convoluted, but it's necessary to keep env.SENTRY_DELIVERY outside the function
      // since beforeSend is serialized in build
      // https://github.com/nuxt-community/sentry-module/issues/266
      beforeSend: env.SENTRY_DELIVERY === 'false' ?
        (event, hint) => {
          console.error(hint.originalException || hint.syntheticException || event.exception);

          return null;
        } : (event, hint) => {
          console.error(hint.originalException || hint.syntheticException || event.exception);

          return event;
        },
    },
    tracing: true,
  },

  tailwindcss: {
    configPath: 'tailwind.config.js',
    viewer: false,
    jit: true,
  },

  moment: {
    defaultLocale: 'nl',
    locales: ['nl'],
  },

  // https://axios.nuxtjs.org/options/
  axios: {
    proxyHeadersIgnore: ['cookie'],
  },

  sitemap: [],

  robots: {
    Sitemap: () => `${ROOT_URL}/sitemap_index.xml`,
    UserAgent: '*',
    Disallow: '/wp/',
  },

  css: [
    'normalize.css/normalize.css',
    '@fortawesome/fontawesome-svg-core/styles.css',
  ],

  loading: {
    color: '#4BFF7D',
    throttle: 0,
  },
};
ThornWalli commented 2 years ago

Thanks for the configuration.

I think we have a problem with the Babel configuration.

Could you try to remove the additional plugins @babel/plugin-proposal-optional-chaining and @babel/plugin-proposal-nullish-coalescing-operator.

Generally they should already be in there, according to Babel docs:

NOTE: This plugin is included in @babel/preset-env, in ES2020

You can also have a look at our nuxt.config, maybe you will find something useful here.

https://github.com/GrabarzUndPartner/nuxt-speedkit/blob/6e580acb5e5658446a2ad34831e144c8427c5781/example/nuxt.config.js#L55-L77

Feels like a small problem.

arvinreynoso commented 2 years ago

We need to transpile the module during build if we import it in our Nuxt modules as stated in this issue. Hope it would help.

ThornWalli commented 2 years ago

The transpile from the module is set automatically. https://github.com/GrabarzUndPartner/nuxt-speedkit/blob/ea48c0bb5266b936351fcc100aace9609910723b/lib/module.js#L29

Transpile is related to the imports from the module (e.g. import('nuxt-speedkit/...')).

Here it is a plugin, these are generated during the build in the .nuxt.

As mentioned above, the Babel configuration should be looked at.