I am working on what will end up being a very large application, which means my asssets/whatever folders are going to contain possibly a few hundred files (SCSS, js etc).
Obviously this will make managing them a little tricky, so I would like to arrange them into subfolders for each module of my application.
e.g. The SAP part of my application would have its style and js stored like the following:
resources/assets/js/SAP/myjs.js
resources/assets/sass/SAP/mysass.scss
It looks like in laravel-elixars config that you can only specify one assetsDir path:
var config = {
production: !! util.env.production,
srcDir: 'app',
assetsDir: 'resources/assets/',
cssOutput: 'public/css/_raw',
jsOutput: 'public/js/_raw',
bowerDir: 'vendor/bower_components',
tasks: [],
watchers: { default: {} },
duplicate: [],
concatenate: { css: [], js: [] }
};
It would be good if you could at least do the following:
...
assetsDir: ['resources/assets/SAP', 'resources/assets/Diary', ...],
...
Or even better, have it automatically map the paths for output based on the directories in the assets directory.
Found a solution to my question.
For the css part of it I can use SASS's #import in a master.scss file which just #imports all the scss files for various bits of my project.
I guess for the JS I would do something similar with requirejs(?).
Related
On the documentation for Slim Framework, it says
In this example application, all the routes are in index.php but in
practice this can make for a rather long and unwieldy file! It’s fine
to refactor your application to put routes into a different file or
files, or just register a set of routes with callbacks that are
actually declared elsewhere.
It doesn't say how to actually do this though. My only thought is that you could split code into multiple PHP files and then use include or require in index.php to reference these.
I'm also not sure what it means by "register a set of routes with callbacks that are actually declared elsewhere"
Does anyone have any thoughts on this, since the application I'm wanting to build might have quite a few routes?
Being a micro-framework, Slim does not enforce any specific method. You can either find a ready-to-use structure (Slim Skeleton Application comes to my mind) or write your own; unlike other frameworks, Slim does not try to protect you from PHP.
Route definitions can be something as simple as an array of strings:
<?php // routes.php
return [
'/' => ['Foo\\Home', 'index'],
'/about' => ['Foo\\Home', 'about'],
'/contact' => ['Foo\\Contact', 'form' ],
];
... which you then load and process in your index.php entry point:
$routes = require('/path/to/routes.php');
foreach ($routes as list($path, $handler)) {
$app->get($route, $handler);
}
And you can leverage the existing Composer set up to auto-load your classes by adding the appropriate directories to composer.json:
{
"require": {
"slim/slim": "^3.3",
"monolog/monolog": "^1.19"
},
"autoload": {
"psr-4": {"Foo\\": "./Foo/"}
}
}
From here, it can get as complex as required: define routes in a YAML file, auto-load from defined classes, etc.
(Code samples are shown for illustration purposes and might not even be valid.)
There're some thoughts on it in Slim documentation
Instead of require's you can use composer autoloading
"register a set of routes with callbacks that are actually declared elsewhere"
From docs:
Each routing method described above accepts a callback routine as its final argument. This argument can be any PHP callable...
So you can do:
$routeHandler = function ($request, $response) { echo 'My very cool handler'; };
$app->get('/my-very-cool-path', $routeHandler);
But usually people use classes instead of functions:
http://www.slimframework.com/docs/objects/router.html#container-resolution
I think you almost get the basic idea right. I recommend reading chapter on routing a couple of times. It covers everything pretty good.
Happy coding and let me know if you need any other help!
I have a view helper that needs jquery, jqueryui, knockout and few other js files to work. Some pages already references all the js files needed by view helper, some pages don't.
Right now, I am using the url to figure out if a js file should be referenced or not inside the view helper.
Is there a better way to do this?
Thanks.
I'm not 100% sure I understand your question in the right way, but I'm 100% sure you need to manage your javascript dependencies in a better way.
I usually use require.js module loader to manage javascript files included into a template.
In order to use it, you need to download require.js file and place it somewhere in your project. I believe you would like to place it in ./public/js/vendors directory not to keep it alongside with your own code. Also, you need to create config file for it, where you decide what javascript modules are needed.
So, the concept is pretty clear: if you have javascript files, that are related to some part of your project, for example admin panel, you should create a config that will load those files. I usually have one config for admin panel part of my web application, and another one for user side of it.
This config with require.js itself are included into template like this:
<script data-main="./js/config-admin.js" src="./js/vendor/require.js"></script>
You need to keep in mind, that on every template you should have only one inclusion of javascript - the inclusion of require.js and it's config.
The config usually looks like this:
require.config({
baseUrl: '/public/js',
paths: {
'bootstrap': './vendor/bootstrap',
'jquery': './vendor/jquery'
},
shim: {
'bootstrap': ['jquery']
}
});
require(['./app'], function (app) {
console.log(app); //Here is smth that required module 'public/js/app.js' returns
//Do some coding here if you wish, for example to start js application.
});
If you need more examples of usage, you can visit my github profile, there are a couple of repositories where I use it (symfony and zend2 applications).
If you are not managing your assets via other means, the HeadScript view helper is designed to act as a collection of the scripts that should be rendered in the view.
Considering the helper depends on the JS files, placing these in the helper's factory class would be a logical place.
class MyViewHelperFactory
{
public function __invoke(ViewPluginManager $viewHelperManager, $name, $requestedName)
{
$headScriptHelper = $viewHelperManager->get('HeadScript');
$headScriptHelper->appendFile('/js/file.js');
return new MyViewHelper();
}
}
There are of course better ways of doing these things; personally I like Assetic.
Here i was i have :
A RESTful Symfony API that i created with few bundles
A front AngularJS that i have in the web repository
Now here is a sample of my routing file :
$routeProvider.
when('/liste-produits', {
templateUrl: '../templates/list-products.html',
controller: 'ProductListCtrl'
}).
otherwise({
redirectTo: '/'
});
The fact that i have to use "../". Because otherwise it won't work in dev environnement (app_dev.php). And of course by the time i will post it in production (app.php) i won't need to add this "../"
Do you guys understand my problem ?
Since i can get assetic from Symfony work in the routing file.
How can i solve this ?
There is an approach, where you define a global variable in your base twig file:
Symfony 2:image paths in javascript file with assetic which you can in turn use in e.g. AngularJS.
There is also a bundle called FOSJsRoutingBundle, it sort of exposes your routes to the client and thus javascript. That might be interesting for you.
However there is another option; - I have personally used the approach posted by Rein Baarsma with the twig file and then cached the resulting javascript.
It's fairly simple to write a request listener that renders the twig file to a javascript file once a day or whenever the javascript file is deleted.
I used the same approach with the stylesheets for a project with daily changing colors.
If you do not cache it, the browser will revisit the route returning the javascript on each page and rerender the javascript file, which adds a lot of overhead.
You could simply make a Symfony Controller with a view on a js file. That way you can use the twig (or php) template functions (like twig's path() function) to avoid any strange urls.
In your controller:
public function routingAction(Request $request) {
$this->render('angular/routing.twig.js');
}
And in your routing
$routeProvider.
when('/liste-produits', {
templateUrl: {{ path('product_list') }},
controller: 'ProductListCtrl'
}).
otherwise({
redirectTo: '/'
});
My website is divided into separate modules. Every module has it's own specific css or js files.
Yii's assetManager creates a folder when I first open a page that uses my assets.
Unfortunately if I change something in my files Yii 1.x does not reload my css or js files.
I have to manually delete the web/assets folder. It is really annoying when you are developing the app.
This works when I add a module to the backend folder, but not when I'm creating a module in the vendor folder with my own namespace.
In Yii2 you can append a timestamp to the URLs of assets like this...
return [
// ...
'components' => [
'assetManager' => [
'appendTimestamp' => true,
],
],
];
This won't force the assets to reload on every request but whenever an asset file is changed the URL will change because of the timestamp & that will force the asset to be re-published.
You can set forceCopy = true.
class Assets extends AssetBundle{
public function init()
{
parent::init();
$this->publishOptions['forceCopy'] = true;
}
}
With respect to Yii1.x With assetManager you can do this by setting 'forceCopy' attribute to true in your config file
... copy the asset files and directories even if they already published
before. This property is used only during development stage
See forceCopy documentation here for more info.
Alternatively you can use linkAssets which will not copy the files but create an soft link between your asset files and yours assets directory. You cannot of course use both.
For the second part of the question I am assuming this is in Yii 2.x, you are supposed to use AssetBundles, you can register any namespace bundle from anywhere, you simply register it in the view with some like this
use vendor\myVendorName\myPackageName\assets\AppAsset;
AppAsset::register($this);
My website is divided into separate modules. Every module has it's own specific css or js files in /protected/modules/my_module/assets/css or js for js files. Yiis assets manager creates folder when I first use page that uses my assets.
Unfortunately if I change sth in my files - Yii does not reload my css or js file. I have to manually delete /projects/assets folder. It is really annoying when you are developing the app.
Is there a way to force Yii to reload assets every request?
In components/Controller.php add the following (or adjust an existing beforeAction):
protected function beforeAction($action){
if(defined('YII_DEBUG') && YII_DEBUG){
Yii::app()->assetManager->forceCopy = true;
}
return parent::beforeAction($action);
}
What this does it that before any actions are started, the application will check to see if you are in debug mode, and if so, will set the asset manager to forcibly recopy all the assets on every page load.
See: http://www.yiiframework.com/doc/api/1.1/CAssetManager#forceCopy-detail
I have not tested this, but based on the documentation I believe it should work fine.
Note: The placement of this code within beforeAction is just an example of where to put it. You simply need to set the forceCopy property to true before any calls to publish(), and placing it in beforeAction should accomplish that goal.
If you're using Yii2 there is a much simpler solution through configuration.
Add the following to your 'config/web.php':
if (YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
// ...
$config['components']['assetManager']['forceCopy'] = true;
}
This forces the AssetManager to copy all folders on each run.
An alternatively solution is to publish your module assets like this:
Yii::app()->assetManager->publish($path, false, -1, YII_DEBUG);
The fourth parameter enforces a copy of your assets, even if they where already published.
See the manual on publish() for details.
Re-publishing assets on every request potentially takes a lot of resources and is unnessecary for development.
For development, it's much easier to use the linkAssets feature of
CClientScript. Assets are published as symbolic link directories, and
never have to be regenerated. See:
http://www.yiiframework.com/doc/api/1.1/CAssetManager#linkAssets-detail
For staging/production, you should make clearing the assets/ folder
part of your update routine/script.
Only fall back to one of the other solutions if for some reason you cannot use symbolic links on your development machine (not very likely).
In YII 1 in config we have:
'components'=> [
...
'assetManager' => array(
'forceCopy' => YII_DEBUG,
...
)
...
]