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 sure if bug with Octane, or if I'm doing something wrong #10

Closed
NullVoxPopuli opened this issue Feb 21, 2019 · 16 comments
Closed

Not sure if bug with Octane, or if I'm doing something wrong #10

NullVoxPopuli opened this issue Feb 21, 2019 · 16 comments

Comments

@NullVoxPopuli
Copy link

I have this template:

{{import Intro from 'emberconf-2019/src/ui/routes/application/-components/section-01-intro'}}

<Slides as |actions|>
  <Intro @openPresenterView={{actions.togglePresenterView}} />
...

and get this error:

Error: Assertion Failed: Could not find component named "emberconf-2019/src/ui/routes/application/-components/section-01-intro" (no component or template with that name was found) index.js:163

But, in the console:

> Object.keys(window.requirejs.entries).filter(p => p.includes('section-01'))
Array [ "emberconf-2019/src/ui/routes/application/-components/section-01-intro/component", "emberconf-2019/src/ui/routes/application/-components/section-01-intro/template" ]
@davewasmer
Copy link
Contributor

@NullVoxPopuli under the hood, this addon just takes the import path and passes it directly to the {{component helper (except for relative imports - we do some path manipulation there, but it still ultimately is passed to {{component). So my guess is that you'll need to drop the emberconf-2019 prefix?

@NullVoxPopuli
Copy link
Author

NullVoxPopuli commented Feb 21, 2019

dropping the app name:

{{import Intro from 'src/ui/routes/application/-components/section-01-intro'}}
Error: Assertion Failed: Could not find component named "src/ui/routes/application/-components/section-01-intro" (no component or template with that name was found)

with a relative import, I get this error:

{{import Intro from './-components/section-01-intro'}}
Error: Assertion Failed: Could not find component named "../emberconf-2019/src/ui/routes/application/-components/section-01-intro" (no component or template with that name was found)

I guess what's strange is that these paths in the errors seem correct.
-> for the relative import, I'm lead to believe the "working directory" is the src folder, but I think I'd expect src/ui/components if using the component helper.

I wonder if something broke in ember-cli w/r/t private collections recently (using master of 2 hours ago)

idk:

@davewasmer
Copy link
Contributor

I looks like you're using this in an MU app? If so, I haven't tested the relative path stuff against MU structure at all. I'd be happy to take a PR that corrects any bugs there, but likely won't have time to tackle that myself for a bit (also - hopefully this addon will be obsoleted in MU apps by actual template imports soon).

You can check if it's this addon vs. ember-cli by simply replacing your absolute import statements with {{component $ABSOLUTE_PATH}}. If you get the same error - it's not this addon. If you don't, then it's us.

@NullVoxPopuli
Copy link
Author

gotchya, yeah, it's def an issue with component/ember-cli then.

I'm using a fresh octane app:

npx ember-cli new my-app -b ember-octane-app-blueprint

@lifeart
Copy link
Contributor

lifeart commented Feb 21, 2019

Looks like I have an idea how to solve this issue.
we need to alias component path somehow (using helper, js injection or <script> inline);

define.alias('emberclear/src/ui/routes/index/-components/compatibility/feature/template', 'emberclear/src/ui/components/${template-hash}/compatibility/feature/template');
define.alias('emberclear/src/ui/routes/index/-components/compatibility/feature/component', 'emberclear/src/ui/components/${template-hash}/compatibility/feature/component');
define.alias('emberclear/src/ui/routes/index/-components/compatibility/feature', 'emberclear/src/ui/components/${template-hash}/compatibility/feature');

example:

function generateHash(module, testName) {
  	var str = module + "\x1C" + testName;
  	var hash = 0;

  	for (var i = 0; i < str.length; i++) {
  		hash = (hash << 5) - hash + str.charCodeAt(i);
  		hash |= 0;
  	}

  	// Convert the possibly negative integer hash code into an 8 character hex string, which isn't
  	// strictly necessary but increases user understanding that the id is a SHA-like hash
  	var hex = (0x100000000 + hash).toString(16);
  	if (hex.length < 8) {
  		hex = "0000000" + hex;
  	}

  	return hex.slice(-8);
}



function registerAbsoluteImport(templateFileName, originalImport) {
	
	const templateId = generateHash(templateFileName, originalImport).slice(0, 5); // f34f3
	const appName = getOwner(this).application.name;
	const splitter = originalImport.includes('/-components') ? '/-components/' : '/components/';
	const componentName = originalImport.split(splitter)[1];
	const localPrefix = `${appName}/src/ui/components/${templateId}/`;
	const absoluteComponentPath =  localPrefix + componentName;

	if (!require.has(absoluteComponentPath)) {
		
		
		define.alias(originalImport,  absoluteComponentPath);
		define.alias(originalImport + '/template',  absoluteComponentPath + '/template');
		define.alias(originalImport + '/component',  absoluteComponentPath + '/component');

	}

	return absoluteComponentPath;
}
{{#let (component (registerAbsoluteImport "current-file-name.hbs" "src/ui/routes/application/-components/section-01-intro")) as |Intro|}}
    <Intro />
{{/let}}

--->>

{{#let (component 'f34f3/section-01-intro') as |Intro|}}
   <Intro />
{{/let}}

@lifeart
Copy link
Contributor

lifeart commented Feb 21, 2019

also, we can do handy transform in runtime

import { Foo, Bar } from 'src/ui/components'

--- hbs ---
function dasherizeName(name = '') {
	const result = [];
	const nameSize = name.length;
	if (!nameSize) {
		return '';
	}
	result.push(name.charAt(0));
	for (let i = 1; i < nameSize; i++) {
		let char = name.charAt(i);
		if (char === char.toUpperCase()) {
			if (char !== '-' && char !== '/' && char !== '_') {
				if (result[result.length - 1] !== '-' && result[result.length - 1] !== '/') {
					result.push('-');
				}
			}
		}
		result.push(char);
	}
	return result.join('');
}

function toLegacyImport(line) {
  var cleanImports = line.split('import').map((item) => item.trim()).filter((text) => text.length).map(i => i.split(' from '));
  const components = [];
  cleanImports.map(([left, right]) => {
    let importSt = right.replace(/[^a-zA-Z0-9-]+/g, " ").trim().split(' ').join('/');
    if (!importSt.endsWith('/')) {
      importSt = importSt + '/';
    }

    if (left.includes('{')) {
	  let normalizedLeft = left.replace(/[{}]+/g, " ").trim();
      const statements = normalizedLeft.trim().split(',').map(name => name && name.trim()).filter(name => name.length);
      statements.forEach((name) => {
		const parts = name.split(' as ');
		if (parts.length === 2) {
			components.push([parts[1].trim(), importSt + dasherizeName(parts[0].trim()).toLowerCase()]);
		} else {
			components.push([name.trim(), importSt + dasherizeName(name.trim()).toLowerCase()]);
		}
      });
    } else {
      components.push([left.trim(), importSt + dasherizeName(left.trim()).toLowerCase()]);
    }

  });
  let results = [];
  components.forEach(([head, tail]) => {
    results.push(`{{import ${head} from "${tail}"}}`);
  });

  return results.join('\n');
}

const templateParts = templateStr.split('--- hbs ---');
if (templateParts.length === 2) {
        // toLegacyImport can be replased to `babel` parsing and anylize
	templateStr = [ toLegacyImport(templateParts[0]), templateParts[1] ].join('/n');
}

@todo -> basic workflow
templateStr

to

{{import Foo from 'src/ui/components/foo'}}
{{import Bar from 'src/ui/components/bar'}}

@lifeart
Copy link
Contributor

lifeart commented Feb 21, 2019

TLDR:

import { Foo }  from 'src/ui/routes/boo/-components/'
	
--- hbs ---

will be transformed to

{{import Foo from "src/ui/routes/boo/-components/foo"}}

this will be transformed to

{{#let (component (registerAbsoluteImport "current-file-name.hbs" "src/ui/routes/boo/-components/foo")) as |Foo|}}
	...
{{/let}}

registerAbsoluteImport will return sdfdf/foo, and it can be rewrited like

{{#let (component "sdfdf/foo") as |Foo|}}
	... 
{{/let}}

@davewasmer
Copy link
Contributor

@lifeart is the goal here simply to get the named import syntax? I.e the import { Foo } part?

Also, why the --- hbs ---?

I'm hesitant to introduce this much complexity if this is just to get import { Foo }, especially since that might confuse some folks (since it looks like ES6 named imports, but doesn't really share the semantics at all).

@lifeart
Copy link
Contributor

lifeart commented Feb 21, 2019

@lifeart
Copy link
Contributor

lifeart commented Feb 21, 2019

@davewasmer, this is Octane feature (named imports and JS syntax on the top of the template), and other hbs stuff should go after --- hbs --- line.

@NullVoxPopuli
Copy link
Author

caveat though: there isn't yet an RFC for this -- just want to keep that in mind :)

@knownasilya
Copy link
Owner

@lifeart
Copy link
Contributor

lifeart commented Feb 21, 2019

lol, my --- hbs --- from https://github.com/wycats/ember-next-experiments#proposed-9, can be simply replaced to something more agreed

@lifeart
Copy link
Contributor

lifeart commented Feb 21, 2019

@knownasilya
Copy link
Owner

MU support will not be coming, since that was dropped. Otherwise the new syntax is in v1.2.0

@NullVoxPopuli
Copy link
Author

👍

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

4 participants