Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

not a function error Node 18.15 rollup 3.30.3 #72

Open
shaynababe opened this issue Apr 6, 2023 · 11 comments
Open

not a function error Node 18.15 rollup 3.30.3 #72

shaynababe opened this issue Apr 6, 2023 · 11 comments
Labels
bug Something isn't working

Comments

@shaynababe
Copy link

no mater how i do it the error message happens the array input to rollup via cli and api is not the way i wish to go with 1000 of files

I have no idea how to declare multiinput as a function is alway gives a error message
Debian 12 is my OS
I sure could use this ?

@shaynababe
Copy link
Author

I did get rollup gulp working
It did have some issues and function not found if you changed the input

import glob from 'glob';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

export default {
	input: Object.fromEntries(
		glob.sync('src/**/*.js').map(file => [
			// This remove `src/` as well as the file extension from each
			// file, so e.g. src/nested/foo.js becomes nested/foo
			path.relative(
				'src',
				file.slice(0, file.length - path.extname(file).length)
			),
			// This expands the relative paths to absolute paths, so e.g.
			// src/nested/foo becomes /project/src/nested/foo.js
			fileURLToPath(new URL(file, import.meta.url))
		])
	),
	output: {
		format: 'es',
		dir: 'dist'
	}
};

@alfredosalzillo
Copy link
Owner

Sorry, @shaynababe I did not get the problem well.

If the problem is multiInput is not a function the problem is not simple to solve, as is related on the way node solver cjs modules inside an mjs file.
You should try renamaning your rollup config to use the mjs extension instead of the js extension.

@shaynababe
Copy link
Author

hey do not worry Rollup is kinda working also, This is super powerful
I hope to work on this
the mjs or js files are the way node process them i have type modules defined in Package.json so all is well with .js I forgot the details of the methods used
Your tool likely did work at one time

The Vue plugin is the same does not work now

Yes i know multipoint will work Rollup has it working with Glob This is wonderful

Your idea is a very good one, i look at it today

@shaynababe
Copy link
Author

this is a start
└─┬ @rollup/plugin-json 4.1.0
├── ✕ unmet peer rollup@"^1.20.0 || ^2.0.0": found 3.20.2
└─┬ @rollup/pluginutils 3.1.0
└── ✕ unmet peer rollup@^1.20.0||^2.0.0: found 3.20.2

the idea is to get up to the current version , multipoint is 1,2 rollup rollup is 3.20.2
you may have a good idea to fix this

@shaynababe
Copy link
Author

shaynababe commented Apr 7, 2023

I have update the Package.json and the Plugin.js was .ts
Please have a look
zz.txt
package.json.txt

rolluppluginmpi.js.txt
have yet to build
how to you wish to write the files out same or transformed

@alfredosalzillo
Copy link
Owner

this is a start └─┬ @rollup/plugin-json 4.1.0 ├── ✕ unmet peer rollup@"^1.20.0 || ^2.0.0": found 3.20.2 └─┬ @rollup/pluginutils 3.1.0 └── ✕ unmet peer rollup@^1.20.0||^2.0.0: found 3.20.2

the idea is to get up to the current version , multipoint is 1,2 rollup rollup is 3.20.2 you may have a good idea to fix this

The last version of multi-input don't have rollup as peer dependecies

@shaynababe
Copy link
Author

ok this what im doing the rollup transform plugin using fg or fast-glob
the roll up template

/* eslint-disable no-param-reassign, no-shadow, no-underscore-dangle */
import { walk } from 'estree-walker';
import MagicString from 'magic-string';
import { attachScopes, extractAssignedNames, makeLegalIdentifier } from '@rollup/pluginutils';

import { flatten, isFalsy, isReference, isTruthy } from './ast-utils';
import { getProxyId, HELPERS_ID } from './helpers';
import { getName } from './utils';

const reserved = 'process location abstract arguments boolean break byte case catch char class const continue debugger default delete do double else enum eval export extends false final finally float for from function goto if implements import in instanceof int interface let long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var void volatile while with yield'.split(
  ' '
);
const blacklist = { __esModule: true };
reserved.forEach((word) => (blacklist[word] = true));

const exportsPattern = /^(?:module\.)?exports(?:\.([a-zA-Z_$][a-zA-Z_$0-9]*))?$/;

const firstpassGlobal = /\b(?:require|module|exports|global)\b/;
const firstpassNoGlobal = /\b(?:require|module|exports)\b/;
const importExportDeclaration = /^(?:Import|Export(?:Named|Default))Declaration/;
const functionType = /^(?:FunctionDeclaration|FunctionExpression|ArrowFunctionExpression)$/;

function deconflict(scope, globals, identifier) {
  let i = 1;
  let deconflicted = identifier;

  while (scope.contains(deconflicted) || globals.has(deconflicted) || deconflicted in blacklist) {
    deconflicted = `${identifier}_${i}`;
    i += 1;
  }
  scope.declarations[deconflicted] = true;

  return deconflicted;
}

function tryParse(parse, code, id) {
  try {
    return parse(code, { allowReturnOutsideFunction: true });
  } catch (err) {
    err.message += ` in ${id}`;
    throw err;
  }
}

export function hasCjsKeywords(code, ignoreGlobal) {
  const firstpass = ignoreGlobal ? firstpassNoGlobal : firstpassGlobal;
  return firstpass.test(code);
}

export function checkEsModule(parse, code, id) {
  const ast = tryParse(parse, code, id);

  let isEsModule = false;
  for (const node of ast.body) {
    if (node.type === 'ExportDefaultDeclaration')
      return { isEsModule: true, hasDefaultExport: true, ast };
    if (node.type === 'ExportNamedDeclaration') {
      isEsModule = true;
      for (const specifier of node.specifiers) {
        if (specifier.exported.name === 'default') {
          return { isEsModule: true, hasDefaultExport: true, ast };
        }
      }
    } else if (importExportDeclaration.test(node.type)) isEsModule = true;
  }

  return { isEsModule, hasDefaultExport: false, ast };
}

export function transformCommonjs(
  parse,
  code,
  id,
  isEntry,
  ignoreGlobal,
  ignoreRequire,
  customNamedExports,
  sourceMap,
  allowDynamicRequire,
  astCache
) {
  const ast = astCache || tryParse(parse, code, id);

  const magicString = new MagicString(code);

  const required = {};
  // Because objects have no guaranteed ordering, yet we need it,
  // we need to keep track of the order in a array
  const sources = [];

  let uid = 0;

  let scope = attachScopes(ast, 'scope');
  const uses = { module: false, exports: false, global: false, require: false };

  let lexicalDepth = 0;
  let programDepth = 0;

  const globals = new Set();

  // TODO technically wrong since globals isn't populated yet, but ¯\_(ツ)_/¯
  const HELPERS_NAME = deconflict(scope, globals, 'commonjsHelpers');

  const namedExports = {};

  // TODO handle transpiled modules
  let shouldWrap = /__esModule/.test(code);

  function isRequireStatement(node) {
    if (!node) return false;
    if (node.type !== 'CallExpression') return false;
    if (node.callee.name !== 'require' || scope.contains('require')) return false;
    // Weird case of require() without arguments
    if (node.arguments.length === 0) return false;
    return true;
  }

  function hasDynamicArguments(node) {
    return (
      node.arguments.length > 1 ||
      (node.arguments[0].type !== 'Literal' &&
        (node.arguments[0].type !== 'TemplateLiteral' || node.arguments[0].expressions.length > 0))
    );
  }

  function isStaticRequireStatement(node) {
    if (!isRequireStatement(node)) return false;
    if (hasDynamicArguments(node)) return false;
    if (ignoreRequire(node.arguments[0].value)) return false;
    return true;
  }

  function getRequireStringArg(node) {
    return node.arguments[0].type === 'Literal'
      ? node.arguments[0].value
      : node.arguments[0].quasis[0].value.cooked;
  }

  function getRequired(node, name) {
    const sourceId = getRequireStringArg(node);
    const existing = required[sourceId];
    // eslint-disable-next-line no-undefined
    if (existing === undefined) {
      if (!name) {
        do {
          name = `require$$${uid}`;
          uid += 1;
        } while (scope.contains(name));
      }

      sources.push(sourceId);
      required[sourceId] = { source: sourceId, name, importsDefault: false };
    }

    return required[sourceId];
  }

  // do a first pass, see which names are assigned to. This is necessary to prevent
  // illegally replacing `var foo = require('foo')` with `import foo from 'foo'`,
  // where `foo` is later reassigned. (This happens in the wild. CommonJS, sigh)
  const assignedTo = new Set();
  walk(ast, {
    enter(node) {
      if (node.type !== 'AssignmentExpression') return;
      if (node.left.type === 'MemberExpression') return;

      extractAssignedNames(node.left).forEach((name) => {
        assignedTo.add(name);
      });
    }
  });

  walk(ast, {
    enter(node, parent) {
      if (sourceMap) {
        magicString.addSourcemapLocation(node.start);
        magicString.addSourcemapLocation(node.end);
      }

      // skip dead branches
      if (parent && (parent.type === 'IfStatement' || parent.type === 'ConditionalExpression')) {
        if (node === parent.consequent && isFalsy(parent.test)) {
          this.skip();
          return;
        }
        if (node === parent.alternate && isTruthy(parent.test)) {
          this.skip();
          return;
        }
      }

      if (node._skip) {
        this.skip();
        return;
      }

      programDepth += 1;

      if (node.scope) ({ scope } = node);
      if (functionType.test(node.type)) lexicalDepth += 1;

      // if toplevel return, we need to wrap it
      if (node.type === 'ReturnStatement' && lexicalDepth === 0) {
        shouldWrap = true;
      }

      // rewrite `this` as `commonjsHelpers.commonjsGlobal`
      if (node.type === 'ThisExpression' && lexicalDepth === 0) {
        uses.global = true;
        if (!ignoreGlobal)
          magicString.overwrite(node.start, node.end, `${HELPERS_NAME}.commonjsGlobal`, {
            storeName: true
          });
        return;
      }

      // rewrite `typeof module`, `typeof module.exports` and `typeof exports` (https://github.com/rollup/rollup-plugin-commonjs/issues/151)
      if (node.type === 'UnaryExpression' && node.operator === 'typeof') {
        const flattened = flatten(node.argument);
        if (!flattened) return;

        if (scope.contains(flattened.name)) return;

        if (
          flattened.keypath === 'module.exports' ||
          flattened.keypath === 'module' ||
          flattened.keypath === 'exports'
        ) {
          magicString.overwrite(node.start, node.end, `'object'`, { storeName: false });
        }
      }

      // rewrite `require` (if not already handled) `global` and `define`, and handle free references to
      // `module` and `exports` as these mean we need to wrap the module in commonjsHelpers.createCommonjsModule
      if (node.type === 'Identifier') {
        if (isReference(node, parent) && !scope.contains(node.name)) {
          if (node.name in uses) {
            if (node.name === 'require') {
              if (allowDynamicRequire) return;
              magicString.overwrite(node.start, node.end, `${HELPERS_NAME}.commonjsRequire`, {
                storeName: true
              });
            }

            uses[node.name] = true;
            if (node.name === 'global' && !ignoreGlobal) {
              magicString.overwrite(node.start, node.end, `${HELPERS_NAME}.commonjsGlobal`, {
                storeName: true
              });
            }

            // if module or exports are used outside the context of an assignment
            // expression, we need to wrap the module
            if (node.name === 'module' || node.name === 'exports') {
              shouldWrap = true;
            }
          }

          if (node.name === 'define') {
            magicString.overwrite(node.start, node.end, 'undefined', { storeName: true });
          }

          globals.add(node.name);
        }

        return;
      }

      // Is this an assignment to exports or module.exports?
      if (node.type === 'AssignmentExpression') {
        if (node.left.type !== 'MemberExpression') return;

        const flattened = flatten(node.left);
        if (!flattened) return;

        if (scope.contains(flattened.name)) return;

        const match = exportsPattern.exec(flattened.keypath);
        if (!match || flattened.keypath === 'exports') return;

        uses[flattened.name] = true;

        // we're dealing with `module.exports = ...` or `[module.]exports.foo = ...` –
        // if this isn't top-level, we'll need to wrap the module
        if (programDepth > 3) shouldWrap = true;

        node.left._skip = true;

        if (flattened.keypath === 'module.exports' && node.right.type === 'ObjectExpression') {
          node.right.properties.forEach((prop) => {
            if (prop.computed || !('key' in prop) || prop.key.type !== 'Identifier') return;
            const { name } = prop.key;
            if (name === makeLegalIdentifier(name)) namedExports[name] = true;
          });
          return;
        }

        if (match[1]) namedExports[match[1]] = true;
        return;
      }

      // if this is `var x = require('x')`, we can do `import x from 'x'`
      if (
        node.type === 'VariableDeclarator' &&
        node.id.type === 'Identifier' &&
        isStaticRequireStatement(node.init)
      ) {
        // for now, only do this for top-level requires. maybe fix this in future
        if (scope.parent) return;

        // edge case — CJS allows you to assign to imports. ES doesn't
        if (assignedTo.has(node.id.name)) return;

        const required = getRequired(node.init, node.id.name);
        required.importsDefault = true;

        if (required.name === node.id.name) {
          node._shouldRemove = true;
        }
      }

      if (!isStaticRequireStatement(node)) return;

      const required = getRequired(node);

      if (parent.type === 'ExpressionStatement') {
        // is a bare import, e.g. `require('foo');`
        magicString.remove(parent.start, parent.end);
      } else {
        required.importsDefault = true;
        magicString.overwrite(node.start, node.end, required.name);
      }

      node.callee._skip = true;
    },

    leave(node) {
      programDepth -= 1;
      if (node.scope) scope = scope.parent;
      if (functionType.test(node.type)) lexicalDepth -= 1;

      if (node.type === 'VariableDeclaration') {
        let keepDeclaration = false;
        let c = node.declarations[0].start;

        for (let i = 0; i < node.declarations.length; i += 1) {
          const declarator = node.declarations[i];

          if (declarator._shouldRemove) {
            magicString.remove(c, declarator.end);
          } else {
            if (!keepDeclaration) {
              magicString.remove(c, declarator.start);
              keepDeclaration = true;
            }

            c = declarator.end;
          }
        }

        if (!keepDeclaration) {
          magicString.remove(node.start, node.end);
        }
      }
    }
  });

  if (
    !sources.length &&
    !uses.module &&
    !uses.exports &&
    !uses.require &&
    (ignoreGlobal || !uses.global)
  ) {
    if (Object.keys(namedExports).length) {
      throw new Error(
        `Custom named exports were specified for ${id} but it does not appear to be a CommonJS module`
      );
    }
    // not a CommonJS module
    return null;
  }

  const includeHelpers = shouldWrap || uses.global || uses.require;
  const importBlock = `${(includeHelpers
    ? [`import * as ${HELPERS_NAME} from '${HELPERS_ID}';`]
    : []
  )
    .concat(
      sources.map(
        (source) =>
          // import the actual module before the proxy, so that we know
          // what kind of proxy to build
          `import '${source}';`
      ),
      sources.map((source) => {
        const { name, importsDefault } = required[source];
        return `import ${importsDefault ? `${name} from ` : ``}'${getProxyId(source)}';`;
      })
    )
    .join('\n')}\n\n`;

  const namedExportDeclarations = [];
  let wrapperStart = '';
  let wrapperEnd = '';

  const moduleName = deconflict(scope, globals, getName(id));
  if (!isEntry) {
    const exportModuleExports = {
      str: `export { ${moduleName} as __moduleExports };`,
      name: '__moduleExports'
    };

    namedExportDeclarations.push(exportModuleExports);
  }

  const name = getName(id);

  function addExport(x) {
    const deconflicted = deconflict(scope, globals, name);

    const declaration =
      deconflicted === name
        ? `export var ${x} = ${moduleName}.${x};`
        : `var ${deconflicted} = ${moduleName}.${x};\nexport { ${deconflicted} as ${x} };`;

    namedExportDeclarations.push({
      str: declaration,
      name: x
    });
  }

  if (customNamedExports) customNamedExports.forEach(addExport);

  const defaultExportPropertyAssignments = [];
  let hasDefaultExport = false;

  if (shouldWrap) {
    const args = `module${uses.exports ? ', exports' : ''}`;

    wrapperStart = `var ${moduleName} = ${HELPERS_NAME}.createCommonjsModule(function (${args}) {\n`;
    wrapperEnd = `\n});`;
  } else {
    const names = [];

    ast.body.forEach((node) => {
      if (node.type === 'ExpressionStatement' && node.expression.type === 'AssignmentExpression') {
        const { left } = node.expression;
        const flattened = flatten(left);

        if (!flattened) return;

        const match = exportsPattern.exec(flattened.keypath);
        if (!match) return;

        if (flattened.keypath === 'module.exports') {
          hasDefaultExport = true;
          magicString.overwrite(left.start, left.end, `var ${moduleName}`);
        } else {
          const [, name] = match;
          const deconflicted = deconflict(scope, globals, name);

          names.push({ name, deconflicted });

          magicString.overwrite(node.start, left.end, `var ${deconflicted}`);

          const declaration =
            name === deconflicted
              ? `export { ${name} };`
              : `export { ${deconflicted} as ${name} };`;

          if (name !== 'default') {
            namedExportDeclarations.push({
              str: declaration,
              name
            });
            delete namedExports[name];
          }

          defaultExportPropertyAssignments.push(`${moduleName}.${name} = ${deconflicted};`);
        }
      }
    });

    if (!hasDefaultExport && (names.length || !isEntry)) {
      wrapperEnd = `\n\nvar ${moduleName} = {\n${names
        .map(({ name, deconflicted }) => `\t${name}: ${deconflicted}`)
        .join(',\n')}\n};`;
    }
  }
  Object.keys(namedExports)
    .filter((key) => !blacklist[key])
    .forEach(addExport);

  const defaultExport = /__esModule/.test(code)
    ? `export default ${HELPERS_NAME}.unwrapExports(${moduleName});`
    : `export default ${moduleName};`;

  const named = namedExportDeclarations
    .filter((x) => x.name !== 'default' || !hasDefaultExport)
    .map((x) => x.str);

  const exportBlock = `\n\n${[defaultExport]
    .concat(named)
    .concat(hasDefaultExport ? defaultExportPropertyAssignments : [])
    .join('\n')}`;

  magicString
    .trim()
    .prepend(importBlock + wrapperStart)
    .trim()
    .append(wrapperEnd);

  if (hasDefaultExport || named.length > 0 || shouldWrap || !isEntry) {
    magicString.append(exportBlock);
  }

  code = magicString.toString();
  const map = sourceMap ? magicString.generateMap() : null;

  return { code, map };
}

@shaynababe
Copy link
Author

shaynababe commented Apr 7, 2023

@jaschaephraim
Copy link

When importing and calling like this:

import multiInput from 'rollup-plugin-multi-input';

multiInput();

I received the error multiInput is not a function. I was able to work around it by calling:

import multiInput from 'rollup-plugin-multi-input';

multiInput.default();

@alfredosalzillo
Copy link
Owner

@jaschaephraim This is a problem in the way node 18 imports commonjs modules inside the es6 modules file.
This library cannot be compiled as an es6 module until also the fast-glob library solves the problem.

if you rename the rollup.config.js file to rollup.config.mjs file it should work without the default.

@alfredosalzillo alfredosalzillo added the bug Something isn't working label Apr 15, 2023
@bertutron
Copy link

i have the same problem. using default config. changing the file to .mjs yields the same result

@abernier abernier mentioned this issue Jun 24, 2023
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants