Nuxt.js: CommonJS module (using `module.exports`) + string.split() ==> Cannot assign to read only property 'exports' of object '#<;Object>'

Created on 8 Feb 2019  路  3Comments  路  Source: nuxt/nuxt.js

Version

v2.4.0

Reproduction link

https://codesandbox.io/s/ml66336kp

Steps to reproduce

Open the dev console to see the Error

What is expected ?

No error

What is actually happening?

This is really weird, if I comment out this line in

api-backend-folder/utils/common.js:13

which is just return filename.split(".").pop(); no error,
really, if I just remove the split() call, I __don't__ see an error

Screen Shot 2019-02-08 at 7.23.52 PM.png

Additional comments?

I know it's related to using a CommonJS module, as you can notice, api-backend-folder/utils/common.js is one, but I need to use this on the server as well, also, this works fine if i just comment out one line? doesn't make a lot of sense to me.

This bug report is available on Nuxt community (#c8627)
bug-report

Most helpful comment

Further read: https://github.com/webpack/webpack/issues/4039, https://twitter.com/adamwathan/status/968652732167995392

Possible solutions:

  • Use node -r esm for your server to support ESM syntax and change the module exports
    or
  • Rewrite the file to ESM syntax (import) and transpile it with babel to CJS syntax (require) (similar to https://github.com/nuxt/nuxt.js/issues/874#issuecomment-308086772)

There is no better way out of that I suppose :slightly_frowning_face:

All 3 comments

it also happens in [email protected] - i really don't think this is a nuxt issue per se, but I have no other way to reproduce it differently, maybe someone in here can figure it out, this is driving me crazy

I also tried any variation of these

// import common from "~/api-backend-folder/utils/common";
// import * as common from "~/api-backend-folder/utils/common";
// const common = require("~/api-backend-folder/utils/common");

Also, for what it's worth, I simplified the api-backend-folder/utils/common.js as much as I can for the reproduction demo, but in reality, __all these functions below (with the exception of urlToLocation)__, which I filtered one by one (commenting all, then commenting in/out each function to see if it triggers the error, so these 8 did it) cause this issue, I just chose a one liner to be in the demo, I am sure it's probably a single issue here for all

As you can see, one of them does actually reference JSON, and other references String, but even if you remove those and leave the simplest function, like the example i shared above in the reproduction link, the issue still occurs, I even got rid of the all the dependencies and it still happens.

common.js

const _ = require("lodash")
const moment = require("moment")
require("moment-timezone")
const diff = require("diff")

// https://github.com/nuxt/nuxt.js/issues/4989
// https://cmty.app/nuxt/nuxt.js/issues/c8627
let helpers = {}

// now this one doesn't cause an issue, we just need it in here
const URL = require("url")
helpers.urlToLocation = function (url) {
  let a
  if (!url) {
    return a
  }
  if (typeof document === "undefined") {
    a = URL.parse(url)
  } else {
    a = document.createElement("a")
    a.href = url
  }
  // now this has a host, hostname, pathname, just like like window.location
  return a
}

helpers.filenameToExtension = function (filename) {
  return (filename || "").split(".").pop()
}

helpers.fileGroup = function (file) {
  let ext = file.ext || file.fileExtension || helpers.filenameToExtension(file.originalname || file.title || file.originalFilename || file.name)
  let mimetype = file.mimetype || file.mimeType || ""

  if (/^(xls|csv)/i.test(ext)) {
    return "excel"
  }
  if (/^doc/i.test(ext)) {
    return "word"
  }
  if (/^ppt/i.test(ext)) {
    return "powerpoint"
  }
  if (/^pdf/i.test(ext)) {
    return "pdf"
  }
  if (/(zip|rar|gz|tar)/i.test(ext)) {
    return "archive"
  }
  if (/(txt|text)/i.test(ext)) {
    return "alt"
  }
  if (/^audio\/.*/.test(mimetype) || /(mp3|wave|aac)/i.test(ext)) {
    return "audio"
  }
  if (/^video\/.*/.test(mimetype) || /(mp4|avi|mov|mkv|m3u8)/i.test(ext)) {
    return "video"
  }
  if (/^image\/.*/.test(mimetype) || /^(jpeg|jpg|png|gif|bmp|tiff)/i.test(ext)) {
    return "image"
  }
  return ext
}

// https://github.com/moment/moment-timezone/issues/651#issuecomment-434092633
helpers.offsetToTimeZone = function (offset) {
  return _.find(moment.tz.names(), (timeZone) => {
    return offset === moment.tz(timeZone).format("Z")
  })
}

// http://dense13.com/blog/2009/05/03/converting-string-to-slug-javascript
helpers.slugify = function (str) {
  str = str.replace(/^\s+|\s+$/g, "")
  str = str.toLowerCase()
  if (/^[\w]+$/.test(str)) {
    str = str.replace(/[^\w\s\d\-_]/g, "-")
  }
  str = str.replace(/\s+/g, "-")
  str = str.replace(/-+/g, "-")
  str = str.replace(/-$/g, "")
  str = str.replace(/^-/g, "")
  str = str.replace(/,/g, "")
  str = str.replace(/\./g, "")
  return str
}

helpers.urlToPathname = function (url) {
  let pathname = helpers.urlToLocation(url).pathname
  // ie bug: https://stackoverflow.com/a/956376/493756
  return "/" + (pathname || "").replace(/^\//, "")
}

helpers.urlToAbsolute = function (url, base, forceReplace) {
  if (helpers.isAbsolute(url) && !forceReplace) {
    return url
  }
  let u = helpers.urlToLocation(url)
  let b = helpers.urlToLocation(base)
  if (!u || !b) {
    return url
  }
  return `${b.protocol}//${b.host}${u.pathname || ""}${u.search || ""}${u.hash || ""}`
}

helpers.diffWordsWithSpaceHTML = function (previous, current) {
  // eslint-disable-next-line
  let d = diff.diffWordsWithSpace((new String(previous)).toString(), (new String(current)).toString());
  return `<span>${d.map((part) => {
    let tagName = part.removed ? "s" : "span"
    return `<${tagName} style="color:${part.added ? "green" : part.removed ? "red" : "grey"};">${part.value}</${tagName}>`
  }).join(" ")}
    </span>`
}

helpers.camelCase = function (str) {
  return str.replace(/[\s_-]+([A-Za-z0-9])?([A-Za-z0-9]*)/g, function (str, p1, p2) {
    return p1.toUpperCase() + p2.toLowerCase()
  })
}

module.exports = helpers

Further read: https://github.com/webpack/webpack/issues/4039, https://twitter.com/adamwathan/status/968652732167995392

Possible solutions:

  • Use node -r esm for your server to support ESM syntax and change the module exports
    or
  • Rewrite the file to ESM syntax (import) and transpile it with babel to CJS syntax (require) (similar to https://github.com/nuxt/nuxt.js/issues/874#issuecomment-308086772)

There is no better way out of that I suppose :slightly_frowning_face:

@manniL thanks, node -r esm def saved the day. I've read through both those links you shared before i filed this ticket, what didn't make sense to me is that i was able to mix import and require sometimes, but others i can't, depending on some specific lines of code.

Ideally, I was hoping to get to the bottom of this, but node -r esm is a quick remedy for now

Was this page helpful?
0 / 5 - 0 ratings

Related issues

msudgh picture msudgh  路  3Comments

pehbehbeh picture pehbehbeh  路  3Comments

mikekidder picture mikekidder  路  3Comments

vadimsg picture vadimsg  路  3Comments

bimohxh picture bimohxh  路  3Comments