I'm trying to update my application to utilise Meteors suggested file structure and I'm having trouble separating the publish function from the schema file. the file structure I'm trying to use is
imports/
api/
profile/
server/
publications.js
Profile.js
When I combine the publish function into the Profile.js schema file the publish function works and the data flows through to the client however when I separate them I'm unable to get it to publish. Can someone please show me how to separate the publish function and schema correctly.
Path: imports/api/profile/Profile.js
import { Mongo } from 'meteor/mongo';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { AddressSchema } from '../../api/profile/AddressSchema.js';
import { ContactNumberSchema } from '../../api/profile/ContactNumberSchema.js';
export const Profile = new Mongo.Collection("profile");
Profile.allow({
insert: function(userId, doc) {
return !!userId;
},
update: function(userId, doc) {
return !!userId;
},
remove: function(userId, doc) {
return !!userId;
}
});
var Schemas = {};
Schemas.Profile = new SimpleSchema({
userId: {
type: String,
optional: true
},
firstName: {
type: String,
optional: false,
},
familyName: {
type: String,
optional: false
}
});
Profile.attachSchema(Schemas.Profile);
if (Meteor.isServer) {
Meteor.publish('private.profile', function() {
return Profile.find({});
});
}
Path: client/main.js
Template.main.onCreated(function() {
this.autorun(() => {
this.subscribe('private.profile');
});
});
This should work if you import the collection & make sure your publications are being imported to your server:
Path: /imports/api/profile/server/publications.js
import { Profile } from '/imports/api/profile/profile';
Meteor.publish('private.profile', function() {
return Profile.find({});
});
You need to make sure you are importing your publications file to the server too. No files in the /imports directory are loaded unless they are imported to the server. The way we do this is import all of our publications and methods etc to a file in our /imports/startup/server directory and then we import that file to the actual meteor server.
So you need to import the publications in your /imports/startup/server/index.js file
Path: /imports/startup/server/index.js
import '/imports/api/profile/server/publications';
And finally you need to make sure your startup/server/index.js is being imported to the server
Path: /server/main.js
import '/imports/startup/server';
If this is confusing you I recommend you read TheMeteorChef's awesome article about the imports directory here: https://themeteorchef.com/tutorials/understanding-the-imports-directory
Also, this may seem complicated but stick with it and you'll understand it soon!
Related
Placing a humans.txt file into nextjs' /public folder works fine for a static file.
However I'd like to annotate the file with the date of the latest page build (when next build is called). So I created pages/humans.txt.tsx which renders a string that also contains the build time static date:
export default function Test({ buildTime }) {
return `Hello ${buildTime}`
}
export async function getStaticProps() {
return {
props: {
buildTime: new Date().toISOString()
}
}
}
I tried to customize pages/_document.js but even with everything stripped down (for testing) it still renders the doctype and one div with my text in it.
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
ctx.renderPage = (props) => {
return {
html: "text",
head: null,
}
}
// Run the parent `getInitialProps`, it now includes the custom `renderPage`
const initialProps = await Document.getInitialProps(ctx)
return initialProps
}
render() {
return <Main/>
}
}
Output:
<!DOCTYPE html><div id="__next">text</div>
Returning just string from my documents render instead of <Main/> still renders the doctype and also causes a warning, since render should return an Element.
So I am out of ideas and might resort to using a prebuild script in package.json prebuild: sed ./pages/humans.txt... to replace a marker in the file with the system date and pipe it to public/humans.txt.
Here is an interesting runtime alternative:
Rewriting /humans.txt to /api/humans
You can use the following rule:
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/humans.txt',
destination: '/api/humans',
},
]
},
}
Check the Rewrites docs here
Writing /api/humans
Now you can use any response in your API. However, make sure you are caching it:
// /pages/api/humans.js
export default function handler(req, res) {
res.setHeader('Cache-control', 's-maxage=6000, stale-while-revalidate=30')
res.setHeader('Content-type', 'text/plain')
res.status(200).end('example')
}
Check the API routes docs here
I have quite a lot of routes defined and one of the routes is dedicated to user profiles.
Each user has a public profile accessible from HTTP://example.com/#username.
I have tried creating file pages/#[username].js but it doesn't seem to work.
Is there a way to have this behavior without passing # sign with the username because this would greatly complicate index.js handling homepage and I would like to have that code separated.
You can now do this like so in next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/#:username',
destination: '/users/:username'
}
]
}
}
This will make any link to /#username go to the /users/[username] file, even though the address bar will show /#username.
Then, in your /pages/[username].tsx file:
import { useRouter } from 'next/router'
export default function UserPage() {
const { query = {} } = useRouter()
return <div>User name is {query.username || 'missing'}</div>
}
Next.js does not support this yet.
You should watch this issue.
Created a next.js full stack application. After production build when I run next start it returns 500 : internal server. I'm using environment varibles for hitting api.
env.development file
BASE_URL=http://localhost:3000
It was working fine in development
service.ts
import axios from 'axios';
const axiosDefaultConfig = {
baseURL: process.env.BASE_URL, // is this line reason for error?
headers: {
'Access-Control-Allow-Origin': '*'
}
};
const axio = axios.create(axiosDefaultConfig);
export class Steam {
static getGames = async () => {
return await axio.get('/api/getAppList');
};
}
Do you have a next.config.js file?
To add runtime configuration to your app open next.config.js and add the publicRuntimeConfig and serverRuntimeConfig configs:
module.exports = {
serverRuntimeConfig: {
// Will only be available on the server side
mySecret: 'secret',
secondSecret: process.env.SECOND_SECRET, // Pass through env variables
},
publicRuntimeConfig: {
// Will be available on both server and client
staticFolder: '/static',
},
}
To get access to the runtime configs in your app use next/config, like so:
import getConfig from 'next/config'
// Only holds serverRuntimeConfig and publicRuntimeConfig
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
// Will only be available on the server-side
console.log(serverRuntimeConfig.mySecret)
// Will be available on both server-side and client-side
console.log(publicRuntimeConfig.staticFolder)
function MyImage() {
return (
<div>
<img src={`${publicRuntimeConfig.staticFolder}/logo.png`} alt="logo" />
</div>
)
}
export default MyImage
I hope this helps.
I dont think you have setup env.
You need to configure it for it to work. Try it without it and it should work fine!
i'm trying to test an extension validator using Karma and Jasmine with latest Angular version. I have a service that receives a File and checks its extension and MIME type, this is the method signature:
public validateFileType(file: File, validTypes: string[]): Observable<boolean>
As you can see the method receives a File, so i want to either load some files i have in a /testing folder or create a file with '.doc'/'.xls'/'.pdf' extension (i would like to use the first approach, already tried creating a .doc, .xls file and the signature numbers does not match any real file).
But its impossible to load any File as the HttpClient can not be instantiated in a Karma test, i have tried everything i know and searched a lot, any help is really appreciated.
Example
import { TestBed } from '#angular/core/testing';
import { FileValidatorService } from './file-validator.service';
describe('FileValidatorService', () => {
let service: FileValidatorService;
beforeEach(() => {
TestBed.configureTestingModule({ providers: [FileValidatorService] });
service = TestBed.get(FileValidatorService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe('Types', () => {
it('should be false', () => {
const content = 'Hello test';
const data = new Blob([content], { type: 'application/zip' });
const arrayOfBlob = new Array<Blob>();
arrayOfBlob.push(data);
const applicationZip = new File(arrayOfBlob, 'Mock.zip', { type: 'application/zip' });
service.validateFileType(applicationZip, ['.doc', '.xls']).subscribe((result: boolean) => {
expect(result).toBeFalsy();
});
});
});
});
This test only works because the file i created generates some random signature code that i don't use so its not recognized and it doesn't match the expected types so is not working as it should.
I'm doing an app that use netanelgilad:excel to export json to excel files.
I follow its example (http://meteorpad.com/pad/2hjNqmwHjDvkxvLC5/Leaderboard) and use vsivsi:file-collection to store temporary files. Plus, I'm using irou:router for my other routes.
The app works fine on my local machine but iron:router does not work on the production server. Below is the code that relates to vsivsi:file-collection and its routing. Does it conflict with Iron:Router? If so, why the app works fine locally?
temporaryFiles = new FileCollection('temporaryFiles', {
resumable: false, // Enable built-in resumable.js upload support
http: [
{
method: 'get',
path: '/:_id', // this will be at route "/gridfs/temporaryFiles/:_id"
lookup: function (params) { // uses express style url params
return { _id: params._id}; // a query mapping url to myFiles
}
},
{
method: 'post',
path: '/:_id',
lookup: function (params) {
return {
_id: params._id
}
}
}
]
});
temporaryFiles.allow({
insert: function (userId, file) {
return true;
},
remove: function (userId, file) {
return true;
},
read: function (userId, file) {
return true;
},
write: function (userId, file, fields) {
return true;
}
});