Razzle: Usage with untranspiled module in node_modules?

Created on 1 Jul 2018  ·  6Comments  ·  Source: jaredpalmer/razzle

Hi!

I'm trying to use a lib that ships untranspiled to NPM, and thus needs transpiling locally in the Razzle-project. I modified my razzle-config to include the module for transpilation in the js loader, and that seems to work fine for the client build as it no longer errors. However, I get the "unexpected token import"-error in what I assume is the server build.

Any ideas about this? I guess the problem is that I'd somehow need the module to be transpiled for the server as well?

Thanks in advance!

Most helpful comment

Ok, I figured it out. You need to extend the includes of the babel-loader. Also you have to set the babelOptions explicitly unless they are specified in a .babelrc inside the untranspiled package, having a /babelrc in your apps package is not enough.

Here's a complete example config:

'use strict';
const nodeExternals = require('webpack-node-externals');
const fs = require('fs');

module.exports = {
  modifyBabelOptions() {
    return {
      presets: ['razzle/babel'],
      plugins: ['transform-flow-strip-types'],
    };
  },
  modify(config, { target, dev }, webpack) {
    // package un-transpiled packages
    const babelRuleIndex = config.module.rules.findIndex(
      (rule) => rule.use && rule.use[0].loader && rule.use[0].loader.includes('babel-loader')
    );
    config.module.rules[babelRuleIndex] = Object.assign(config.module.rules[babelRuleIndex], {
      include: [
        ...config.module.rules[babelRuleIndex].include,
        fs.realpathSync('./node_modules/untranspiled-package')
      ],
    });
    config.externals =
      target === 'node'
        ? [
            nodeExternals({
              whitelist: [
                dev ? 'webpack/hot/poll?300' : null,
                /\.(eot|woff|woff2|ttf|otf)$/,
                /\.(svg|png|jpg|jpeg|gif|ico)$/,
                /\.(mp4|mp3|ogg|swf|webp)$/,
                /\.(css|scss|sass|sss|less)$/,
                /^untranspiled-package/,
              ].filter(Boolean),
            }),
          ]
        : [];
    // return
    return config;
  },
};

All 6 comments

Managed to solve it. For future reference:

Turns out webpack-node-externals is applied and used during SSR, meaning no modules from node_modules are included for bundling and thus transpiling. I solved it by doing something along these lines in my razzle.config.js:

config.externals = target === 'node' ? [
      nodeExternals({
        whitelist: [
          dev ? 'webpack/hot/poll?300' : null,
          /\.(eot|woff|woff2|ttf|otf)$/,
          /\.(svg|png|jpg|jpeg|gif|ico)$/,
          /\.(mp4|mp3|ogg|swf|webp)$/,
          /\.(css|scss|sass|sss|less)$/,
          /^my-untranspiled-package/
        ].filter(Boolean),
      }),
    ] : [];

...where a majority of that code is copied right from createConfig.js in this repo.

@zth thank you!!

@zth how did you get it to work on the client side in the first place? could you share your config?

Ok, I figured it out. You need to extend the includes of the babel-loader. Also you have to set the babelOptions explicitly unless they are specified in a .babelrc inside the untranspiled package, having a /babelrc in your apps package is not enough.

Here's a complete example config:

'use strict';
const nodeExternals = require('webpack-node-externals');
const fs = require('fs');

module.exports = {
  modifyBabelOptions() {
    return {
      presets: ['razzle/babel'],
      plugins: ['transform-flow-strip-types'],
    };
  },
  modify(config, { target, dev }, webpack) {
    // package un-transpiled packages
    const babelRuleIndex = config.module.rules.findIndex(
      (rule) => rule.use && rule.use[0].loader && rule.use[0].loader.includes('babel-loader')
    );
    config.module.rules[babelRuleIndex] = Object.assign(config.module.rules[babelRuleIndex], {
      include: [
        ...config.module.rules[babelRuleIndex].include,
        fs.realpathSync('./node_modules/untranspiled-package')
      ],
    });
    config.externals =
      target === 'node'
        ? [
            nodeExternals({
              whitelist: [
                dev ? 'webpack/hot/poll?300' : null,
                /\.(eot|woff|woff2|ttf|otf)$/,
                /\.(svg|png|jpg|jpeg|gif|ico)$/,
                /\.(mp4|mp3|ogg|swf|webp)$/,
                /\.(css|scss|sass|sss|less)$/,
                /^untranspiled-package/,
              ].filter(Boolean),
            }),
          ]
        : [];
    // return
    return config;
  },
};

I managed to do the same trick as @MrLoh also for Typescript ts-loader. Check allowedPackages, you can insert your package name there. I also took into account an idea that it seems that it is enough for current version of Razzle to be without custom config.externals, but you might be interested also in original @MrLoh solution (see about config.externals deletion: https://github.com/jaredpalmer/razzle/issues/842#issuecomment-475722036)

  const allowedPackages = ['my-component']

  const allowedPackagePaths = allowedPackages.map(packageName =>
    fs.realpathSync('./node_modules/' + packageName)
  )

  const tsRuleIndex = config.module.rules.findIndex(
    rule =>
      rule.use && rule.use[0].loader && rule.use[0].loader.includes('ts-loader')
  )

  if (tsRuleIndex === -1) {
    throw Error(
      'This component assumes that you are using ts-loader. If you are not using it, then you might need to check and test code for how would it work with other loaders'
    )
  }

  config.module.rules[tsRuleIndex] = {
    ...config.module.rules[tsRuleIndex],

    include: [
      ...config.module.rules[tsRuleIndex].include,
      ...allowedPackagePaths,
    ],
  }

  delete config.externals

This worked with me. My question is, The libraries are being duplicated in the client and server bundle. Any way to chunk this common this into a new file using razzle.config.js ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

krazyjakee picture krazyjakee  ·  3Comments

pseudo-su picture pseudo-su  ·  3Comments

GouthamKD picture GouthamKD  ·  3Comments

knipferrc picture knipferrc  ·  5Comments

corydeppen picture corydeppen  ·  3Comments