The curious case of /public/assets/ in a Meteor project - meteor

In my Meteor 1.10.2 project, I have created a folder called assets inside the /public/ folder. When the Meteor application is built, I find this assets folder has been copied to these locations, as a direct child of the web.browser... folders:
/.meteor/local/build/programs/web.browser/assets/
/.meteor/local/build/programs/web.browser.legacy/assets
However, if I rename the folder to Assets (or if I give it any other name), when the application is built, I find it deeper in, inside the app folder at:
/.meteor/local/build/programs/web.browser/app/Assets/
/.meteor/local/build/programs/web.browser.legacy/app/Assets/
What is the logic behind this? What is the intention? What are the best practices for working with a folder at /public/assets/? Are there any other words that are given special treatment when used as names for folders inside the /public/ folder?

FWIW, this behaviour is specifically due to meteor tools bundler:
https://github.com/meteor/meteor/blob/release/METEOR%401.10.2/tools/isobuild/bundler.js#L719-L725
setTargetPathFromRelPath(relPath) {
// XXX hack
if (relPath.match(/^(packages|assets|dynamic)\//)) {
this.targetPath = relPath;
} else {
this.targetPath = files.pathJoin('app', relPath);
}
Therefore we can see that there are 3 special directory names that exhibit this special behaviour:
packages
assets
dynamic
Example with public assets:
These assets bundled in build:
For "packages", while we can understand that this is how Meteor ships the static assets of packages (i.e. when they call api.addAssets(), we can also see that there is a potential for collision, in the (however unlikely) case we use a pathname like "public/packages/my-package-name".
As for "assets", the initial name was "static", but I do not think it was publicly documented either.
And for "dynamic", I do not know yet what is its exact purpose, but we can see that it serves its content as "javascript" type (at least SVG files), whereas the first 2 serve them as "text/plain".

What Meteor does is build your project multiple times. Once for legacy web browsers, and again for a modern browser, and also for other platforms such as IOS or Android. It does all this inside the .meteor/local folder as you have observed.
Meteor has the concept of a /private folder, which is similar to /public, except that Meteor thinks of them as assets. This might explain why your folder appears in different locations, depending on the name.
Personally I wouldn't worry too much about how Meteor handles files, unless you want to become a contributor, in which case you are welcome to poke around :)

Related

Silverstripe 4 - CSS and JS Requirements. How/what populates the /resources directory?

I have a SS3.x module that I have forked, pulled down from it's fork via composer, and started porting to SS4. So far so good, except when it comes to Requirements.
I'm using the Requirements format found in existing code in another module, which has a colon-separated format as follows:
Requirements::javascript('company/mymodule:javascript/SortableUploadField.js');
This file exists in the module at /vendor/company/mymodule/javascript/SortableUploadField.js. However on page load, I have a 404 in console as SS is looking for this file at /resources/company/mymodule/css/SortableUploadField.css. And this does not exist.
I added the following to my composer.json file for the module as I saw other modules doing this:
"extra": {
"installer-name": "sortableuploadfield",
"expose": [
"css",
"javascript"
]
},
And ran a composer update. But the /resources directory does not appear for this module (other modules are there). And I can't find any information online on how this is supposed to work.
Edit: As a sidenote, I wonder if the documentation for Requirements is misleading? It omits this caveat with modules and mention of the resources directory at all. If that documentation is meant only to convey the process for working with JS/CSS in normal mysite development, then it is just a bit confusing because the code samples us everywhere. Which wouldn't be a direct url to something in /vendor, surely.
Found this after tracing code that basically used the /resources directory. Short answer to my query is simply running
composer vendor-expose
This calls the VendorExposeTask that does this copying. The only other place I found this task being used is on VendorPlugin install method. So I assume that other than the above command, the only way SS actually does this on your behalf is on initial install of a module.

Where to place non-app assets in a Meteor project to avoid bundling?

Per the Meteor docs, I'm trying to determine which special folder to place non-app assets (ex. Photoshop design PSDs) in, so that they still get checked into source control but don't get wrapped into the eventual client or server payloads.
It feels 'wrong' to use tests/ for this purpose but the docs suggest it has the desired behavior. Can private/ be used similarly, or will its contents always get added to the server bundle regardless of whether your app code registers any Assets? (Or is there a better place altogether to put such files?)
Consider a project structure like this:
/YourMeteorProject
/YourPSDFiles
file1.psd
file2.psd
...
/YourMeteorApp
/.meteor
/client
/server
...
You can launch your meteor app from within /YourMeteorApp. Files that are not part of your application, such as your PSD files, are kept outside of the application.

Where do I properly put my constants in Meteor

I usually follow the unofficial Meteor FAQ on how to structure my codebase, but I can't figure out where I should put my global constants.
To give an example: I have some database entries with a constant GUID that I need to reference in many points of my app. So far I just attached the constants to the relevant collection, such that in collections/myCollectionWithGuids.coffee it would say:
#MyCollectionWithGuids = new Meteor.Collection "myCollectionWithGuids"
#MyCollectionWithGuids.CONSTANT_ID = "8e7c2fe3-6644-42ea-b114-df8c5211b842"
This approach worked fine, until I need to use it in the following snippet, located in client/views/myCollectionWithGuidsView.coffee, where it says:
Session.setDefault "selectedOption", MyCollectionWithGuids.CONSTANT_ID
...which is unavailable because the file is being loaded before the Collections are created.
So where should I put my constants then, such that they are always loaded first without hacking in a bunch of subdirectories?
You could rely on the fact that a directory names lib is always treated first when it comes to load order.
So I would probably advise you to organize your code as follow :
lib/collections/collection.js
client/views/view.js
In your particular use case this is going to be okay, but you might find cases when you have to use lib in your client directory as well and as the load order rules stack (subdirectories being loaded first), it will be loaded BEFORE the lib folder residing in your project root.
For the moment, the only way to have full control over the load order is to rely on the package API, so you would have to make your piece of code a local package of your app (living in the packages directory of your project root).
It makes sense because you seem to have a collection and a view somehow related, plus splicing your project into a bunch of collaborative local packages tends to be an elegant design pattern after all.
Creating a local package is really easy now that Meteor 0.9 provide documentation for the package.js API.
http://docs.meteor.com/#packagejs
I would put your collection definitions in a lib directory. File structure documentation explains that all files under the lib directory get loaded before any other files, which means your variable would be defined when you attempt to access it in your client-side code.
Generally speaking, you always want your collections to be defined before anything else in your application is loaded or executed, since your application will most likely heavily depend upon the use of the collection's cursor.

How can I implement multi-tenant translations in Symfony2

I am developing a multi-tenant capable Symfony2 solution and was wondering if there was a way to use different translations files for each tenant, as the default translations files at present contain e.g. references to the initial tenant's company name, etc.
I am using the Liip Theme Bundle (https://github.com/liip/LiipThemeBundle) to allow tenants to use our codebase, layering their own design on top, but cannot work out a simple and scalable way to allow them to use their own translations files.
There was talk on the theme bundle git repo about this, but I don't believe anything was ever implemented (https://github.com/liip/LiipThemeBundle/issues/12). Ideally I'd like to follow the directory structure they suggested in that thread, e.g.
root
- app
- Resources
- themes
- <theme name>
- public
- translations (this would be new)
- views
as this would allow us to continue the practice of themes being self-contained git submodules that a tenant can maintain themselves.
I ended up using the directory structure I outlined above, and had a console command which symlinked the translations override file in app/Resources/translations. This command ran during my deploy script, and I then created my own "trans" twig function which checked if an override file should be used.
Not the cleanest, but definitely works the way I wanted.

The workspace with the iOS project and related a static library project

I am fighting with Xcode 4 workspaces. Currently Xcode 4 wins. Thus, my situation:
I have the workspace with the iOS app project. There is also static library project iOS app depends on in the this workspace.
Solution #1
I try to configure like this:
the app project:
add to target's Build Phases > Link Binary With Library a product (libmystaticlib.a);
set USER_HEADER_SEARCH_PATHS to $(TARGET_BUILD_DIR)/usr/local/include $(DSTROOT)/usr/local/include;
the static library project:
add some header files to target's Build Phases > Copy Headers > Public;
set SKIP_INSTALL to YES.
And important thing: both projects must have configurations named the same. Otherwise, if I have, e.g., configuration named Distribution (Ad Hoc) for the app and Release for the static library, Xcode can't link the app with the library.
With this configuration archiving results to an archive with the application and public headers from static library projects. Of course, I am not able to share *.ipa in this case. :(
Solution #2
I have also tried another configuration:
Xcode preferences:
set source tree for the static library, e.g, ADDITIONS_PROJECT;
the app project:
add to target's Build Phases > Link Binary With Library a product (libmystaticlib.a);
set USER_HEADER_SEARCH_PATHS to $(ADDITIONS_PROJECT)/**;
the static library project:
don't add any header files to Public!;
set SKIP_INSTALL to YES.
I still need to care about configuration names for both projects. But in result I can build and archive successfully. In the result I get archive and I can share *.ipa.
I don't like the second solutions, because in this case I don't get any real advantage of the Xcode 4 workspace. The same effect I can add get, if I add the static lib project inside the app project. Therefore, I think something is wrong with my solution.
Any suggestion how better to link a static libraries?
I also found a solution that works with build and with archive.
In your static library set the Public Headers Folder Path to ../../Headers/YourLib
In your app config set the Header Search Paths to $(BUILT_PRODUCTS_DIR)/../../Headers
In your app you will be able to code #import <YourLib/YourFile.h>
Don't forget the Skip Install = YES option in your static lib.
We've found an answer, finally. Well, kind of. The problem occurred because Xcode 4 places public headers into InstallationBuildProductsLocation folder during build for archive. Apparently, when archiving it sees the headers and tries to put them into archive as well. Changing Public Headers Folder Path of the lib to somewhere outside of InstallationBuildProductsLocation, for example, to $(DSTROOT)/../public_folders and adding this path to Header Search Path solve the problem.
This solution doesn't look very elegant, but for us it seems to be the only option. May be you'll find this useful.
Here is a solution a get from Apple DTS. I don't like it, because it is suggests to use absolute path. But I still publish it here, maybe someone feels it is right for him.
How to set up the static library:
Add a build configuration named "Archive" by copying the Release Configuration.
Move your headers to the Project group of the Copy Headers build phase.
Set the Per-configuration Build Products Path of the "Archive" configuration to $(BUILD_DIR)/MyLibBuildDir. Xcode will create the MyLibBuildDir folder inside the BuildProductsPath, then add your static library into that folder. You can use "MyLibBuildDir" or provide another name for the above folder.
Set Skip Install to YES for all configurations.
Set Installation Directory of "Archive" to $(TARGET_TEMP_DIR)/UninstalledProducts.
Edit its scheme, set the Build Configuration of its Archive action to "Archive."
How to set up the project linking against the library:
Add a build configuration named "Archive" by copying the Release Configuration.
Set the Library Search Paths of "Archive" to $(BUILD_DIR)/MyLibBuildDir.
Set the User Header Search Paths to the recursive absolute path of your root of your workspace directory for all configurations.
Set Always Search User Paths of "Archive" to YES.
Set Skip_Install to NO for all configurations.
Edit its scheme, set the Build Configuration of its Archive action to "Archive."
I was not real happy with any of the other solutions that were provided, so I found another solution that I prefer. Rather than having to use relevant paths to put the /usr/local/include folder outside of the installation directory, I added a pre-action to the Archive step in my scheme. In the pre-action I provided a script that removed the usr directory prior to archiving.
rm -r "$OBJROOT/ArchiveIntermediates/MyAppName/InstallationBuildProductsLocation/usr"
This removes the usr directory before archiving so that it does not end up in the bundle and cause Xcode to think it has multiple modules.
so far I also struggled with the same problem, but did come to a solution with a minimal tradeoff:
This requires Dervied Data to be your Build Location.
I set the Public Headers Folder path to ../usr/local/include
This will ensure, that the headers will not be placed into the archive.
For the app, I set the Header Search Path to:
$(OBJROOT)/usr/local/include
$(SYMROOT)/usr/local/include
There are 2 entries necessary since the paths slightly change when building an archive and I haven't figured out how to describe it with only one variable.
The nice thing here is, that it doesn't break code sense. So except for having 2 entries rather than one, this works perfectly fine.
I'm struggling with the same problem at the moment. I didn't progress much farther than you. I can only add that in the second solution you can drag headers you need to use from the library to the app project, instead of setting ADDITIONS_PROJECT and USER_HEADER_SEARCH_PATH. This will make them visible in app project. Value of SKIP_INSTALL flag doesn't matter in this case.
Still, this solution isn't going to work for me, because I'm moving rather big project, with dozens of libraries, from Xcode 3 to Xcode 4, and it means really a lot of drag and drop to make my project build and archive correctly. Please let us know if you find any better way out of this situation.
I could use Core Plot as a static library and workspace sibling, with two build configurations:
Release:
in project, Header Search Path: "$(BUILT_PRODUCTS_DIR)"
in CorePlot-CocoaTouch, Public Headers Folder Path: /usr/local/include
AdHoc (build configuration for "Archive" step in Scheme, produces a shareable .ipa):
in project, Header Search Path: "$(BUILT_PRODUCTS_DIR)"/../../public_folders/**
in CorePlot-CocoaTouch, Public Headers Folder Path: ../../public_folders
Hope it will help someone to not waste a day on this.

Resources