Meteor packages dynamic imports fail with templating as weak dependency - meteor

The Package
I have a shared library as Meteor package with the following structure:
ui
- componentA.html
- componentA.js
- loader.js
- ...
tools
- toolXY.js
- ...
and while tools are shared among many of my apps (and the ui), the ui part is only used by one app. Consider the template to be totally simple:
componentA.html
<template name="componentA">
<span>yea component A</span>
</template>
componentA.js
import { Template } from 'meteor/templating'
import { toolXY } from '../tools/toolXY'
import './componentA.html'
// ... template code
loader.js (little helper, think the package has 100 ui components)
export const loader = {
componentA: {
template: 'componentA',
load: async function () {
return import('./componentA')
}
}
}
Because the ui is used in one app only, I made the templating and dynamic-import a weak dependency:
Package.onUse(function (api) {
api.versionsFrom('1.6')
api.use('ecmascript')
api.use('dynamic-import', ['client'], { weak: true })
api.use('templating', ['client'], { weak: true })
})
The Problem
I add my package and the weak dependencies to a project via
$ meteor add dynamic-import templating me:mypackage
and import the ui on the client like the following:
client/main.js
import { loader } from 'meteor/me:mypackage/ui/loader'
Meteor.startup(() => {
loader.componentA.load()
.then(() => console.log('loaded'))
.catch(e => console.error(e))
})
It will result in the following error:
Error: "Cannot find module './componentA.html'"
makeMissingError http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:232
resolve http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:238
moduleLink http://localhost:5050/packages/modules.js?hash=88e9e724ccc8459066fbe9e3889ef37c7bb7067f:353
module /node_modules/meteor/me:mypackage/ui/componentA.js:16
makeModuleFunction http://localhost:5050/packages/dynamic-import.js?hash=cf582bcc349503492678c9fd3f7bba4a610f70e5:138
fileEvaluate http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:346
require http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:248
moduleLink http://localhost:5050/packages/modules.js?hash=88e9e724ccc8459066fbe9e3889ef37c7bb7067f:360
getNamespace http://localhost:5050/packages/dynamic-import.js?hash=cf582bcc349503492678c9fd3f7bba4a610f70e5:187
dynamicImport http://localhost:5050/packages/dynamic-import.js?hash=cf582bcc349503492678c9fd3f7bba4a610f70e5:40
Checking for Package.templating inside loader.js, as well as componentA.js resolves to Object { Template: Template(viewName, renderFunction) } (because it has been installed as package to the project).
The fix that isn't really a fix
If I turn off the weak dependency on templating it will work fine:
api.use('templating')
This, however, will cause all my applications to load templating, allthough they do not require it.
The question
Why is it behaving like this? Shouldn't this work with weak dependency when the dependency has been added to the project?

Related

Vue 3 components with slots in vendor folder

I have an issue where I want to extract all my components out into a separate repository but I want to load them in via composer instead of npm (business decision).
This was all working fine. Add it as a dependancy in the composer.json file and then add the following to the webpack.mix.js file;
mix.webpackConfig({
resolve: {
alias: {
'#ui' : path.resolve(__dirname, 'vendor/companyname/ui/src'),
}
}
});
And then use the following to import them in;
import PrimaryButton from "#ui/buttons/primary";
Which all worked fine!
Until I wanted to use slots. If I include a slot I get the following error;
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'nodeName')
at new create (svg.js?1929:3616)
at globalRef.SVG (svg.js?1929:31)
at Proxy.mounted (Editor.vue?721f:63)
at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:154)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?5c40:163)
at Array.hook.__weh.hook.__weh (runtime-core.esm-bundler.js?5c40:2909)
at flushPostFlushCbs (runtime-core.esm-bundler.js?5c40:357)
at flushJobs (runtime-core.esm-bundler.js?5c40:393)
In this example the component looks like this;
<template>
<button #click="click">
<slot></slot>
</button>
</template>
<script>
export default {
emits: ['click'],
methods: {
click() {
this.$emit('click')
}
}
}
</script>
Now, if I copy this component into the project repository and load it in that way, there is no error and works as intended!
Can anyone point me in the direction of where I am going wrong please.
Update
I have removed other components from view I'm rendering and now have a new error;
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'isCE')
at renderSlot (runtime-core.esm-bundler.js?c099:5832)
at Proxy.render (primary.vue?f782:3)
at renderComponentRoot (runtime-core.esm-bundler.js?5c40:1166)
at componentEffect (runtime-core.esm-bundler.js?5c40:5201)
at reactiveEffect (reactivity.esm-bundler.js?a1e9:42)
at effect (reactivity.esm-bundler.js?a1e9:17)
at setupRenderEffect (runtime-core.esm-bundler.js?5c40:5154)
at mountComponent (runtime-core.esm-bundler.js?5c40:5113)
at processComponent (runtime-core.esm-bundler.js?5c40:5071)
at patch (runtime-core.esm-bundler.js?5c40:4673)
Update
This is not the answer but the reason for this, from what I can tell is that there were two instances of Vue in play, one from the library and one in my application. I have no idea how to stop this but if I push the contents up to a repo and pull it in via npm then it works normally. Still would like to know how to get this running locally without using npm.

TypeError: Cannot read property <template name> of undefined when creating package

I am trying to create a package for Meteor, unsuccessfully unfortunately. I'm on Meteor 1.8.1. My goal is to make a template for a button that I can use in my application like this {{> testButton}} (I am just trying it out atm).
package.js
Package.describe({
name: 'button-test',
version: '0.0.1',
summary: '',
git: '',
documentation: 'README.md'
});
Package.onUse(function (api) {
api.use(['ecmascript']);
api.use(['session', 'templating'], ['client', 'server']);
api.mainModule('button-test.js');
});
Package.onTest(function (api) {
api.use('ecmascript');
api.use('tinytest');
api.use('button-test');
api.mainModule('button-test-tests.js');
});
button-test.js
// Variables exported by this module can be imported by other packages and
// applications. See button-test-tests.js for an example of importing.
import './testButton.js';
testButton.js
import { Template } from 'meteor/templating';
Template.testButton.events({
'click #buttonT': () =>
console.log('Clicked the button')
});
testButton.html
<template name="testButton"><button id="buttonT">TEST</button></template>
I have some problems with this;
Running the code like this returns the error TypeError: Cannot read property 'testButton' of undefined. So there is a problem with Template, but I don't know what it is, since I have added it with api.use
When I try to add import ./testButton.html to testButton.js I get the error Error: Cannot find module './testButton.html'
I looked at the source code for accounts-ui-unstyled, but this is written on an older meteor version.
Does anybody have an idea as to what I am doing wrong?
The problem was with the api.mainModule, I solved it by having my Package.onUse like this:
Package.onUse(function (api) {
api.use(['templating', 'blaze'], 'client');
api.use('ecmascript');
api.addFiles(['button-test.js'], 'client');
});
After using the addFiles instead of mainModule, I could import the html and the Template problem disappeared. I have no idea why this works and mainModule does not, but hey, it does.

Can't access Meteor.user() property

I've installed a Meteor phone authentication package mys:accounts-phone, which should add a phone.number subfield into users collection. I try to access this field as follows:
Meteor.user().phone.number
but typescript shows error
Property 'phone' does not exist on type 'User'.
On the other hand, I have custom props in users.profile, and can easily access them in this way.
Insecure is not yet removed. Autopublish is ON.
this happens sometime when our angular component is initialized but our meteor data is not reached from server.
try to use user injection in place of Meteor.user()
import {Component} from "#angular/core";
import { InjectUser } from 'angular2-meteor-accounts-ui';//<--**** import this****
#Component({
selector: "login-buttons",
template
})
#InjectUser('user') //<--*** add this***
export class LoginButtonsComponent {
user: Meteor.User; //<--*** add this ***
constructor(private router: Router) {}
}
now in user variable you will have all values of Meteor.User
if you want to print in html part use this
<div *ngIf="user">
{{user.phone.number}}
</div>
don't forget to install
meteor add accounts-password
meteor npm install --save angular2-meteor-accounts-ui
and in app.module.ts file
import { AccountsModule } from 'angular2-meteor-accounts-ui';
#NgModule({
imports: [
... other modules here
AccountsModule
],
hope this will work. if this not work let me know i will tell you one other solution
Got probable answer from Meteor docs.
It explains why username property appears. By default, Meteor publish only a number of fields considered to be public. To exposure any additional fields they must be published explicitly.
Not yet have time to test, but think it should work.
The other reason, with the same sympthoms, when publication code do not executed at server side. Try to put
Meteor.startup(() => {
// code to run on server at startup
Meteor.publish('userData', function() {
if(!this.userId) return null;
return Meteor.users.find(this.userId
//, {fields: {lastname: 1,}}
);
});
});
in a file within /server folder of your application.

meteor publish composite does not

I have problems when I try use meteor-publish-composite. I see this page https://github.com/englue/meteor-publish-composite and I execute the following code in my meteor project:
meteor add reywood:publish-composite
I create publish-composite function like this:
import { Meteor } from 'meteor/meteor';
import { Categories } from '../../../../both/collections/administration/category.collection';
import { Structures } from '../../../../both/collections/administration/structure.collection';
//Meteor.publish('categories', () => Categories.find());
Meteor.publishComposite('categoriesWithStructures', {
find: () => {
return Categories.collection.find();
},
children: [{
find:(category) => {
console.log(category);
return Structures.collection.find({_id: category.structure});
}
}]
});
But when I initialize the project, in the console I see the message:
Property 'publishComposite' does not exist on type 'typeof Meteor'
In the .meteor/packages file the meteor module is added
angular2-compilers
accounts-password
msavin:mongol
reywood:publish-composite
My meteor project use Angular2.
I will appreciate any help. Regards.
I have the same problem.
My solution looks like
Meteor["publishComposite"] (...)
instead of
Meteor.publishComposite (...)
I'm also using typescript for meteor, and I think that its not bet combo (yet).

Meteor 1.3 - lazy loading or evaluation of files

I am very excited with ES2015 modules in Meteor 1.3. We have written an app with medium complexity with Meteor 1.2. As we have very large number of templates and files, it is taking a bit of time to download the content on client side. so I am interested in the lazy loading feature using import. From the meteor night talk, they say that the Blaze templates are still global and cannot be imported (or lazy loaded), I have tried using React inside Blaze.
Added react-template-helper package using meteor add react-template-helper
Create imports folder and added testComponent.jsx file which exports 'TestComponent'
//testComponent.jsx
import React from 'react';
export default class TestComponent extends React.Component {
render() {
return (
<div>
<h1>TestComponent</h1>
<div>This is from Test Component</div>
</div>
);
}
}
After in the Blaze template outside imports folder,
<!-- homeReact template html-->
<template name="homeReact">
<div>
{{> React component=TestComponent}}
</div>
</template>
In the template's js file which is also outside of imports folder
// homeReact template js
import { Template } from 'meteor/templating';
import TestComponent from '/imports/testComponent.jsx`;
Template.homeReact.helpers({
TestComponent() {
return TestComponent;
}
});
This worked but the imports/testComponent.jsx is downloaded on the client (checked using chrome dev tools - sources tab), even if the current route doesn't require homeReact template.
Then I have used require instead of import like this,
// homeReact template js
import { Template } from 'meteor/templating';
Template.homeReact.onCreated(function () {
this.TestComponent = require('/imports/testComponent.jsx').TestComponent;
});
Template.homeReact.helpers({
TestComponent() {
return Template.instance().TestComponent;
}
});
This code also downloads the imports/testComponent.jsx file but in addition I also got an error
In template "homeReact", call to {{> React ... }} missing component argument.
So, my question is, is it possible to lazy load (download) files only when required?

Resources