alexjoverm / typescript-library-starter

Starter kit with zero-config for building a library in TypeScript, featuring RollupJS, Jest, Prettier, TSLint, Semantic Release, and more!
MIT License
4.37k stars 492 forks source link

Trouble building with 'Cannot call a namespace ('Knex')' #58

Closed hassankhan closed 7 years ago

hassankhan commented 7 years ago

Hi there, apologies in advance if these are silly questions but I'm new to Rollup and I'm not quite sure to do this.

I'm writing a lib that uses Moment and Knex. In the source, I've imported them as import * as moment from "moment". Typescript compiles fine, but this causes Rollup to throw the following errors:

Cannot call a namespace ('Knex')
Cannot call a namespace ('moment')

If I change the imports to import moment from "moment", then Rollup manages to complete, but if I try to use the compiled code I get Module <project_path>/node_modules/moment/moment has no default export. I also tried setting "allowSyntheticDefaultImports": true on both the library itself and the consuming project, but then I get Cannot find module 'moment'.

I've also tried changing the imports to requires but that didn't do anything either 😕 .

Any help would be hugely appreciated.

rollup.config.js ```js import includePaths from 'rollup-plugin-includepaths'; import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; const pkg = require('./package.json'); const { camelCase } = require('lodash'); const libraryName = 'argo-serverless-common'; const externals = [ 'aws-sdk/clients/cognitoidentityserviceprovider', 'aws-sdk/clients/dynamodb', 'isomorphic-fetch', 'knex', 'lodash', 'memcached', 'moment', 'pg', 'validatorjs', ]; export default { entry: `compiled/${libraryName}.js`, targets: [ { dest: pkg.main, moduleName: camelCase(libraryName), format: 'cjs' }, // { dest: pkg.main, moduleName: camelCase(libraryName), format: 'umd' }, { dest: pkg.module, format: 'es' } ], format: 'iife', sourceMap: true, // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash') external: externals, plugins: [ // Allow relative path resolving includePaths({ include: {}, paths: ['compiled'], external: externals, extensions: ['.js', '.json', '.html'] }), // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs) commonjs({ include: [ 'node_modules/knex/**', 'node_modules/moment/**', // 'node_modules/moment/**', ] }), // Allow node_modules resolution, so you can use 'external' to control // which external modules to include in the bundle // https://github.com/rollup/rollup-plugin-node-resolve#usage resolve({ modulesOnly: true, }), ] } ```
alexjoverm commented 7 years ago

Hi @hassankhan, beforehand, it is necessary the "allowSyntheticDefaultImports": true line, so I've just added it to 4a2376d119360f8a72747eaa7ed90ecf196f02f0. This is the case where the typings export a namespace instead of a default export.

That said, everything works correct. I think there are unnecessary things in your rollup.config.js.

This is what I did, let's say we have cool-lib and consuming-project:

// ../cool-lib/src/cool-lib.ts
import moment from 'moment'

export default function() {
  return moment().format('MMMM Do YYYY, h:mm:ss a')
}

// ../consuming-project/src/consuming-project.ts
import cool from 'cool-lib'
console.log(cool())

Then run in consuming-project npm run build && node dist/consuming-project.umd.js (assuming consuming-project is created as well with this starter). That will work, of course, keep in mind this is bundling moment, but this is not what we want.

When building a library, you must decide which dependencies are part of the library and which not. In this case, moment seems like a good candidate to keep it as a peerDependency, thus the user must install it in consuming-project.

So, if we wanna exclude it from the bundle:

...
external: ['moment']
...
"peerDependencies": {
    "moment": "^2.18.1" // whatever version
}

This should be work out!

t-palmer commented 6 years ago

For moment you can use moment-es6. Please see this issue in stackoverflow for details: https://stackoverflow.com/questions/39519823/using-rollup-for-angular-2s-aot-compiler-and-importing-moment-js

I did the following: npm install moment-es6 Then in my component I used: import moment as 'moment-es6'