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

Failed to alias "app/index.jsx", it does not exist #1

Closed
necolas opened this issue Jan 8, 2014 · 11 comments
Closed

Failed to alias "app/index.jsx", it does not exist #1

necolas opened this issue Jan 8, 2014 · 11 comments

Comments

@necolas
Copy link

necolas commented Jan 8, 2014

I'm getting the following error in the resulting build:

Uncaught Error: Failed to alias "app/index.jsx", it does not exist

Example directory structure of the app:

├── README.md
├── build
│   ├── build.js
│   ├── react.js
│   └── react.min.js
├── component.json
├── components-local
│   ├── app
│   └── container
├── index.html
├── node_modules
│   ├── component
│   └── component-react
└── package.json

Root component.json:

{
  "name": "react-test",
  "paths": [
    "components",
    "components-local"
  ],
  "local": [
    "app"
  ]
}

App component's json:

{
  "name": "app",
  "scripts": [
    "index.jsx"
  ]
}

Run a build with:

component build --use component-react

It generates the following build:

/**
 * Require the given path.
 *
 * @param {String} path
 * @return {Object} exports
 * @api public
 */

function require(path, parent, orig) {
  var resolved = require.resolve(path);

  // lookup failed
  if (null == resolved) {
    orig = orig || path;
    parent = parent || 'root';
    var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
    err.path = orig;
    err.parent = parent;
    err.require = true;
    throw err;
  }

  var module = require.modules[resolved];

  // perform real require()
  // by invoking the module's
  // registered function
  if (!module._resolving && !module.exports) {
    var mod = {};
    mod.exports = {};
    mod.client = mod.component = true;
    module._resolving = true;
    module.call(this, mod.exports, require.relative(resolved), mod);
    delete module._resolving;
    module.exports = mod.exports;
  }

  return module.exports;
}

/**
 * Registered modules.
 */

require.modules = {};

/**
 * Registered aliases.
 */

require.aliases = {};

/**
 * Resolve `path`.
 *
 * Lookup:
 *
 *   - PATH/index.js
 *   - PATH.js
 *   - PATH
 *
 * @param {String} path
 * @return {String} path or null
 * @api private
 */

require.resolve = function(path) {
  if (path.charAt(0) === '/') path = path.slice(1);

  var paths = [
    path,
    path + '.js',
    path + '.json',
    path + '/index.js',
    path + '/index.json'
  ];

  for (var i = 0; i < paths.length; i++) {
    var path = paths[i];
    if (require.modules.hasOwnProperty(path)) return path;
    if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
  }
};

/**
 * Normalize `path` relative to the current path.
 *
 * @param {String} curr
 * @param {String} path
 * @return {String}
 * @api private
 */

require.normalize = function(curr, path) {
  var segs = [];

  if ('.' != path.charAt(0)) return path;

  curr = curr.split('/');
  path = path.split('/');

  for (var i = 0; i < path.length; ++i) {
    if ('..' == path[i]) {
      curr.pop();
    } else if ('.' != path[i] && '' != path[i]) {
      segs.push(path[i]);
    }
  }

  return curr.concat(segs).join('/');
};

/**
 * Register module at `path` with callback `definition`.
 *
 * @param {String} path
 * @param {Function} definition
 * @api private
 */

require.register = function(path, definition) {
  require.modules[path] = definition;
};

/**
 * Alias a module definition.
 *
 * @param {String} from
 * @param {String} to
 * @api private
 */

require.alias = function(from, to) {
  if (!require.modules.hasOwnProperty(from)) {
    throw new Error('Failed to alias "' + from + '", it does not exist');
  }
  require.aliases[to] = from;
};

/**
 * Return a require function relative to the `parent` path.
 *
 * @param {String} parent
 * @return {Function}
 * @api private
 */

require.relative = function(parent) {
  var p = require.normalize(parent, '..');

  /**
   * lastIndexOf helper.
   */

  function lastIndexOf(arr, obj) {
    var i = arr.length;
    while (i--) {
      if (arr[i] === obj) return i;
    }
    return -1;
  }

  /**
   * The relative require() itself.
   */

  function localRequire(path) {
    var resolved = localRequire.resolve(path);
    return require(resolved, parent, path);
  }

  /**
   * Resolve relative to the parent.
   */

  localRequire.resolve = function(path) {
    var c = path.charAt(0);
    if ('/' == c) return path.slice(1);
    if ('.' == c) return require.normalize(p, path);

    // resolve deps by returning
    // the dep in the nearest "deps"
    // directory
    var segs = parent.split('/');
    var i = lastIndexOf(segs, 'deps') + 1;
    if (!i) i = 0;
    path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
    return path;
  };

  /**
   * Check if module is defined at `path`.
   */

  localRequire.exists = function(path) {
    return require.modules.hasOwnProperty(localRequire.resolve(path));
  };

  return localRequire;
};
require.register("app/index.js", function(exports, require, module){
/** @jsx React.DOM */
var Container = require('container');

var App = React.createClass({displayName: 'App',
  render: function() {
    return (
      Container(null, 
         this.props.children 
      )
    );
  }
});

React.renderComponent(
  App(null, "Hello, world!"),
  document.getElementById('example')
);

});
require.alias("app/index.jsx", "react-test/deps/app/index.jsx");
require.alias("app/index.js", "app/index.js");
@njpatel
Copy link
Owner

njpatel commented Jan 9, 2014

Hi, thanks for reporting this. I can confirm this happening with the component-build command but it doesn't seem to happen with custom build scripts (using component/builder.js manually like the example in the readme.md). I'm taking a look to see what's going on in builder that's making it ignore the request to remove the .jsx files from the build.

@njpatel
Copy link
Owner

njpatel commented Jan 9, 2014

componentjs/builder.js#125 is the issue that's causing it (with the fix, but it's been open for 4 months).

I'm going to see if I can get someone on #components to review that PR and get it merged today, if not, will move component-react to look for { "react": [ "foo.jsx", ... ] } in the config files (instead of "scripts" key as it does now for convenience), as that fixes the issue. I might do the change to 'react' key anyway as it'll protect against any regressions in script replacing in component/builder in the future.

Either way, I'll make sure it works for component build -use component-react by tonight (GMT).

@necolas
Copy link
Author

necolas commented Jan 9, 2014

Thanks!

BTW, the JSX transformer will just skip any .js files without the @jsx comment at the top. Like most of the React projects out there, my files are name.js not name.jsx. Perhaps the plugin could be run on every .js file?

@njpatel njpatel closed this as completed in 8a5e0d3 Jan 9, 2014
@njpatel
Copy link
Owner

njpatel commented Jan 9, 2014

Not much traction from upstream component/builder, and looking more deeply into this, I realised it was probably safer for the long-run to have our own array for React files, in case there are any regressions etc (it's a tricky bit of code in builder).

So, for the latest published version (1.0.0), you can put the JSX files into a react array in the component.json and that seems to work fine in my tests for both component build --use component-react and manual building. In fact, you can put all your js files into the react because the React transpiler only works on those with the special comment at the top. This way you can keep them named .js too (that's me anticipating a potential issue #2! :).

Let me know if you have any issues, thanks again for reporting, I was using manual building so would never have come across it!

P.S. I also published njpatel/react and njpatel/react-with-addons if you'd like to have the react.js available as a component dependancy (just looking at your project layout). Adding in component-minify as the last stage should give you minified (& uglified if you'd like) output as well (as most of the JS in Components isn't ready for production afaict).

@necolas
Copy link
Author

necolas commented Jan 9, 2014

Thanks! Using the latest version, and your react component, I can't get my app rendering. The build is created and there are no errors, but nothing seems to get run. Any idea what the problem is? Simplified example files below.

npm install && component install && npm run build
.
├── component.json
├── index.html
├── index.js
└── package.json

component.json

{
  "dependencies": {
    "njpatel/react": "*"
  },
  "main": "index.js",
  "react": [
    "index.js"
  ],
  "remotes": []
}

package.json

{
  "private": true,
  "dependencies": {},
  "devDependencies": {
    "component": "~0.19.3",
    "component-react": "~1.0.0"
  },
  "scripts": {
    "build": "component build --use component-react"
  }
}

index.js

/** @jsx React.DOM */
var React = require('react');

var App = React.createClass({
  render: function () {
    return (
      <div className="App">
        hi
      </div>
    )
  }
});

React.renderComponent(
  <App />,
  document.getElementById('example')
)

index.html

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <div id="example"></div>
    <script src="build/build.js"></script>
  </body>
</html>

@njpatel
Copy link
Owner

njpatel commented Jan 9, 2014

Yep. Your build.js will be wrapping your index.js in a require module, so you'll want to add a small script portion to your HTML to be able to call 'require("your-module-name")'. This is a Component thing and hence it's always good to have a 'name' key in your component.json, as that is your module name (you'll see it in the require registry in your build.js). Component is really nice but needs better docs!

I hope that helps.

@necolas
Copy link
Author

necolas commented Jan 9, 2014

Ah, thanks!

@necolas
Copy link
Author

necolas commented Jan 10, 2014

Using the react prop isn't ideal when using local components, because you have to duplicate it as scripts too in order for the build to be error free (AFAICT).

For example, in a local component dir that you let component know about with paths and depend on with local:

{
  "name": "header",
  "dependencies": {
    "njpatel/react": "*"
  },
  "main": "header.js",
  "react": [
    "header.js"
  ],
  "scripts": [
    "header.js"
  ]
}

Without doubling up on react and scripts, the main project file will say it can't require the header component.

@njpatel
Copy link
Owner

njpatel commented Jan 10, 2014

Yep, unfortunately the 'main' file does need to be included in scripts otherwise builder get's confused (this would partially be fixed with the branch I mentioned earlier). However it's only necessary for the main file, not every file needs to be added there. I pushed a more complete example just now that uses local components (in multiple files).

I thought about just parsing anything that is in scripts through react, but the problem is that they could be read from disk multiple times by the builder for itself and also by other plugins, so it could get messy. Having 'react' gives a sanitised space to work from (should there be more options etc in the future from the React team for compiling).

@necolas
Copy link
Author

necolas commented Jan 10, 2014

I see. But if you have each component in its own directory (multiple local components), then you have to do it for every component.json.

@njpatel
Copy link
Owner

njpatel commented Jan 12, 2014

Yep, it's a pain for sure, just not a lot I can do about it from the plugin side. I've tried a few things, but for one thing they fix, they introduce other weirdness or errors. Sorry :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants