1

I'm trying to create my libary with React and to use it locally (with my company git repository).

I can test my app while developping with npm run start. My app is running.

But when I want to use it in an other project, I got this error :

ERROR in ./node_modules/mylib/src/views/calendar.jsx Module parse failed: Unexpected token (10:53) You may need an appropriate loader to handle this file type.

The line involved is :

const Calendar = ({ month = moment(), dayCellTitle = <DayCellTitle />, header = <CalendarHeader/>, children }) => {

The package is imported like that :

"mylib": "git+ssh://git@gitlab.mycompany.ch:mylib/mylib.git"

I try this, but I got worst :

Plugin/Preset files are not allowed to export objects, only functions. In /home/xxxxx/Documents/workspaces/react-calendar/node_modules/babel-preset-stage-0/lib/index.js

Here the files of my package :

webpack.config.js

const path = require('path');
const pkg = require('./package.json');
const libraryName= pkg.name;
module.exports = {
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'react-calendar.js',
    library: libraryName,
    libraryTarget: 'umd',
    publicPath: '/dist/',
    umdNamedDefine: true
  },
  module: {
    rules: [
      { test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      }
    ]
  },
  resolve: {
    alias: {
      'react': path.resolve(__dirname, './node_modules/react'),
      'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
    }
  },
  externals: {
    // Don't bundle react or react-dom
    react: {
      commonjs: "react",
      commonjs2: "react",
      amd: "React",
      root: "React"
    },
    "react-dom": {
      commonjs: "react-dom",
      commonjs2: "react-dom",
      amd: "ReactDOM",
      root: "ReactDOM"
    }
  }
};

package.json

{
  "name": "react-calendar",
  "version": "0.0.1",
  "description": "React Calendar UI by",
  "main": "./dist/lib/index.js",
  "scripts": {
    "start": "./node_modules/.bin/parcel docs/index.html",
    "build": "./node_modules/.bin/webpack --mode=production",
    "build:docs": "./node_modules/.bin/parcel build docs/index.js -d ./dist/docs && cp docs/index.html dist/docs/index.html",
    "test": "jest",
    "tdd": "jest --watch"
  },
  "author": "Xero",
  "license": "MIT",
  "dependencies": {
    "lodash": "^4.17.11",
    "mobx": "^5.9.0",
    "mobx-react": "^5.4.3",
    "moment": "^2.24.0",
    "moment-range": "^4.0.1",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "semantic-ui-css": "^2.4.1",
    "semantic-ui-react": "^0.85.0",
    "settings": "^0.1.1"
  },
  "peerDependencies": {
    "lodash": "^4.17.11",
    "mobx": "^5.9.0",
    "mobx-react": "^5.4.3",
    "moment": "^2.24.0",
    "moment-range": "^4.0.1",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "semantic-ui-css": "^2.4.1",
    "semantic-ui-react": "^0.85.0",
    "settings": "^0.1.1"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0-0",
    "@babel/plugin-proposal-class-properties": "^7.3.0",
    "@babel/plugin-proposal-decorators": "^7.3.0",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.5",
    "babel-plugin-module-resolver": "^3.1.3",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "enzyme": "^3.8.0",
    "enzyme-adapter-react-16": "^1.9.1",
    "jest": "^24.1.0",
    "parcel-bundler": "^1.6.2",
    "react-test-renderer": "^16.8.0",
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.12",
    "webpack-node-externals": "^1.6.0"
  },
  "jest": {
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/spec/javascript/__mocks__/fileMock.js",
      "\\.(css|scss|less)$": "<rootDir>/spec/javascript/__mocks__/styleMock.js"
    },
    "roots": [
      "src",
      "tests"
    ],
    "moduleFileExtensions": [
      "js",
      "jsx"
    ],
    "moduleDirectories": [
      "node_modules",
      "src"
    ],
    "setupFiles": [
      "<rootDir>/tests/setup.js"
    ]
  }
}

.babelrc

{
  "presets": ["@babel/preset-env", "@babel/preset-react",],
  "plugins":  [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }]
  ]
}

Side question :

Is there a way to know if the library will be imported without error BEFORE doing the importation in an other project

Edit

I have added yarn run build to my package.json, and launching it do not raise any errors :

Entrypoint main [big] = react-calendar.js
 [45] (webpack)/buildin/module.js 497 bytes {0} [built]
 [48] (webpack)/buildin/global.js 472 bytes {0} [built]
[244] ./node_modules/moment/locale sync ^\.\/.*$ 3 KiB {0} [optional] [built]
[368] ./src/index.js + 52 modules 182 KiB {0} [built]
      | ./src/index.js 65 bytes [built]
      | ./src/views/calendar.jsx 1.17 KiB [built]
      | ./src/views/day_cell_title.jsx 358 bytes [built]
      | ./src/views/calendar_header.jsx 1.15 KiB [built]
      | ./src/store/calendar_store.js 3.85 KiB [built]
      | ./src/views/calendar_grid.jsx 1.49 KiB [built]
      | ./src/views/calendar_navigation_button.jsx 928 bytes [built]
      | ./src/views/calendar_title.jsx 290 bytes [built]
      | ./src/generators/month_generator.js 556 bytes [built]
      | ./src/painters/day_cell_color.js 593 bytes [built]
      | ./src/views/day_cell_content.jsx 547 bytes [built]
      | ./src/settings.js 332 bytes [built]
      | ./src/painters/event_color.js 374 bytes [built]
      | ./src/painters/range_color.js 591 bytes [built]
      | ./src/views/empty_day_cell_content.jsx 340 bytes [built]
      |     + 38 hidden modules
    + 743 hidden modules
Xero
  • 3,951
  • 4
  • 41
  • 73

3 Answers3

4

You're redistributing your sources that contain JSX syntax. Usually, before publishing, you'll need to transform these. If not, then your dependents will need to configure their babel-loader with React support and ensure that they're not excluding your package modules.

So your configuration looks alright, except for the exclusion match:

 module: {
  rules: [
    { test: /\.(js|jsx)$/,
      exclude: /node_modules/,
      use: ['babel-loader']
    }
  ]
 }

I would recommend that you use { include } and list out the paths that should explicitly match. To find the path at which your package sources are located, use path.dirname(require.resolve('@yours/package-name')).

Filip Dupanović
  • 32,650
  • 13
  • 84
  • 114
  • `before publishing, you'll need to transform these` how ? – Xero Feb 08 '19 at 18:26
  • @Xero for a good example I would recommend looking at some of your favorite published packages from the React ecosystem. If you start in `package.json` and observe the `{ scripts: { publish, prepublish } }`, in most cases you should see invocations to some build tool that will have Babel configured to transform JSX syntax to `createElement()` calls for distribution. I would also like to point out that you do not need to do this or make this exclusive--it is just something done as common practice to help dependents use your package to avoid syntax errors and not have to introduce build tooling. – Filip Dupanović Feb 09 '19 at 12:06
  • I would offer you a more complete example from `react-virtualized`. The published package for distribution contains several different kinds of builds, each suitable for a different audience with specific tooling. See https://github.com/bvaughn/react-virtualized/blob/a07be36d4ba09e1d5a120a9cfe90a2f0542b3b83/package.json#L14 and you can inspect the different builds distributed here https://unpkg.com/react-virtualized@9.21.0/dist/. – Filip Dupanović Feb 09 '19 at 12:08
  • 1
    Thank for your help, I figured out the issue, see my answer (a noob issue BTW) – Xero Feb 09 '19 at 12:17
  • 1
    @Xero congrats and happy package publishing !!! I think getting things right for the first package is always the hardest, but before you know it there will be dozens of your packages in the registry and we will all benefit from your hard work ! – Filip Dupanović Feb 09 '19 at 12:42
2

The issue was 2 things :

1. Build forgotten and not commited

I was not building my project (with yarn run build), and most of all, I was not commiting the compiled file (dist/main.js)

2. The import was wrong

Given the point 1., my import were wrong.

I was doing :

import {Calendar} from "project-react-calendar/src/views/calendar";

instead of :

import {Calendar} from "project-react-calendar";

That can be available, with this index.js :

import { Calendar } from './views/calendar'

export {
    Calendar
}
Xero
  • 3,951
  • 4
  • 41
  • 73
1

Your npm run start script seems to use parcel, not webpack I guess webpack.config.js simply doesn't affect it? Maybe you should make sure that proper loader is indeed launched by parcel.

"start": "./node_modules/.bin/parcel docs/index.html", // <- invokes parcel bundler
"build": "./node_modules/.bin/webpack --mode=production",

Try npm run build and if it succeeds, that will be exactly the case.

jayarjo
  • 16,124
  • 24
  • 94
  • 138
  • thx for your answer. see my edit. launching webpack do not raise error – Xero Feb 08 '19 at 16:00
  • Then you got to fix your parcel config. – jayarjo Feb 08 '19 at 16:01
  • The Module parse failed issue is still there – Xero Feb 08 '19 at 16:09
  • Yes it did, but when I try to add my lib to an other project, I got the Module parse issue, this is so weird – Xero Feb 08 '19 at 16:21
  • Are you saying that the project that will include my lib, will call the lib `yarn run start` and that's because it failed ? – Xero Feb 08 '19 at 16:24
  • Your lib has nothing to do with it. The project where you use it should be able to parse it. That's what `webpack` and other bundlers (like `parcel`) do using various loader plugins. In your case it fails because that project is not configured properly. If `npm run build` succeeds then `webpack` does the job nicely and properly parses your lib for production. But your development setup (`npm run start`) is based on `parcel` and has separate config. You need to find it and fix it to properly parse your lib for development. – jayarjo Feb 08 '19 at 16:28
  • I tried in multiple project. The error still there... Maybe it's not project related. – Xero Feb 08 '19 at 17:06
  • I figured out, this was a noob issue. (see answer) I was not push the result of the build to the repository. Thank you for your help – Xero Feb 08 '19 at 21:11