How to handle assets in Symfony 4 - symfony

I am building an application with Symfony 4 and I'd like to follow the best practices for web assets. I use Encore/Webpack for SCSS and JS and it works well; the resulting JS+CSS are nicely stored in /public/build folder. I'm stuck at how to store and use static assets like images, movies, sounds.
Should images be stored in 'public/images' folder or in 'assets/images'?
And some followup questions:
If the images are stored in public/images, will I get any benefit if I pollute the templates with asset('...') calls?
If the images are stored in assets/images, then:
How are they moved into public/images to be served via http? ./bin/console assets:install did nothing, saying: '[OK] No assets were provided by any bundle.'.
How do I use them in SCSS? Via relative paths?
Regards,

Should images be stored in 'public/images' folder or in 'assets/images'?
Everything in public/ is available through the browser. In here, only production ready and build things should be put.
As your images don't need any processing (I assume), you can (should) indeed put the images there.
Now, assume you're needing to do some processing (e.g. ugly JPEG compression), you would put the images in assets/, do some processing and then put only the processed images in public/.
If the images are stored in public/images, will I get any benefit if I pollute the templates with asset('...') calls?
Yes, asset() doesn't have anything to do with Encore or asset build management. The only thing it does is fixing your URLs. This means that if you move your app to sub directories on your server (example.com/app/), the URLs will automatically adapt. Read more about it in the Asset component documentation.

Another good way to reference images with asset() method in Symfony 4 is copying images in public/build when building assets with Encore.
Use copyFiles() in Webpack Encore
Webpack Encore provides a function to copy your images on the public directory to allow asset() to access those files : copyFiles().
In your webpack.config.js
Encore.
...
.copyFiles({
from: './assets/images',
to: 'images/[path][name].[ext]',
pattern: /\.(png|jpg|jpeg)$/
})
Error: Encore.copyFiles is not a recognized property or method.
Please by sure that you are actualy using symfony/webpack-encore-bundle and not
symfony/webpack-encore-pack as described here.
composer require symfony/webpack-encore-bundle
composer remove symfony/webpack-encore-pack
yarn install
yarn upgrade
yarn run watch
My package.json
{
"devDependencies": {
"#symfony/webpack-encore": "^0.22.0",
"bootstrap": "^4.1.3",
"node-sass": "^4.10.0",
"sass-loader": "^7.0.1",
"url-loader": "^1.0.1",
"webpack-notifier": "^1.6.0"
},
"license": "UNLICENSED",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
}
}

Edit webpack.config.js after
Encore
.setOutputPath('../build/')
Add the following lines. You can also do more configuration by uncommenting the lines
.enableVersioning()
.copyFiles({
from: './assets/images',
// optional target path, relative to the output dir
to: 'images/[path][name].[ext]',
// if versioning is enabled, add the file hash too
//to: 'images/[path][name].[hash:8].[ext]',
// only copy files matching this pattern
//pattern: /\.(png|jpg|jpeg)$/
})
Now you can use image by
Source: https://symfony.com/doc/current/frontend/encore/copy-files.html
Details: http://toihid.com/?p=332

Related

how to build nextjs with fallback: true enable

I'm unable to find any examples of what needs to be done to deploy nextjs with fallback: true enabled.
using export it throws an error that it can't be exported this way if fallback: true is enabled.
And if I use npm run build it doesn't seem to generate the out folder.
How can I run a build and generate the out folder with fallback: true enabled in my app
netlify.toml
[build]
command = "npm run build && npm run export"
publish = "out"
package.json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next export"
},
You can't use use npm run build to generate static 'out' folder (i.e. static html-files). Thats becouse with fallback enabled, your site became 'non-static'. So it can be deployed only on servers thats run NodeJS. You may start server with node start or implement your own NodeJS server. This is a most misunderstanding point about SSG\SSR. More info at https://nextjs.org/docs/advanced-features/static-html-export
The other posts didn't explain why it doesn't work.
If you have fallback as true that means you have pages with dynamic routes (path/[pid].js) and you DON'T want to pre-render all the pages. You want some pages to load without data, maybe because you want to load data manually.
When you use NextJS's export, it creates a static app with no supporting backend so that the app can be served on a static host.
For each pre-rendered path, NextJS will generate a directory structure to match the prerendered path.
If you have:
product/1, product/2, product/3 then NextJS will create those directories.
But if you have routes that are not prerendered like product/4 then NextJS will not create that directory, then when the user opens their browser to exmample.com/product/4 it will 404!
As stated here you can't use next export if you use fallBack: true, if you have a lot of dynamic pages, better host your application on any node.js server and use next start instead. Static HTML Export (out folder) is only useful when the new pages are not added often

Use absolute imports in Next.js app deployed with ZEIT Now

In the Next.js 9 tutorial the suggested way to import shared components is by relative paths, like
import Header from '../components/Header';
I want to use absolute imports, like
import Header from 'components/Header';
How do I make this work both locally and when I deploy using the Now CLI?
Using the suggested setup from the tutorial, my project structure is:
my-project
├── components
├── pages
└── package.json
Next.js 9.4 and later
If you're using Next.js 9.4 or later, see Black's answer.
Next.js 9.3 and earlier
There are different ways of achieving this, but one way – that requires no additional dependencies and not too much config – is to set the environment variable NODE_PATH to the current directory, i.e. NODE_PATH=..
1. Make it work locally
I think the easiest way to set NODE_PATH=. when running the dev/build scripts in your package.json locally (e.g. $ npm run dev or $ yarn dev), is to add it to each script in package.json:
"scripts": {
"dev": "NODE_PATH=. next",
"build": "NODE_PATH=. next build",
"start": "next start"
},
2. Make it work when you deploy
When you deploy to ZEIT Now, NODE_PATH must be set in a different way.
You can add a Deployment Configuration by adding a now.json file (it should be in the same directory as your package.json). If you don't have a now.json file already, create it and add the following contents:
{
"version": 2,
"build": {
"env": {
"NODE_PATH": "."
}
}
}
This tells Now to use NODE_PATH=. when buildnig your app (see build.env).
(It also tells Now that we use Now platform version 2 which is currently the newest version (see version). Omitting the version will give you a warning when you deploy using $ now.)
In Next.js 9.4 it is possible to do it by adding the baseUrl config to jsconfig.json (JS projects) or tsconfig.json (TS projects).
// jsconfig.json or tsconfig.json
{
"compilerOptions": {
"baseUrl": "."
}
}
This will allow imports from the root directory. It also integrates well with IDE such as VS Code. See documentation for more information.
Change web pack configuration:
//next.config.js file
module.exports = {
webpack(config) {
config.resolve.modules.push(__dirname)
return config;
},
}
Then use it like this:
import TopBar from 'components/TopBar' // for components
import "public/baseLine.css" // for any public resources

Firebase Functions local "file:" dependencies

I'm using a react-crud-shared as dependency for react-crud-backend which uses Firebase Cloud Functions.
At react-crud-backend I have the following:
{
"name": "react-crud-backend",
"description": "Cloud Functions for Firebase",
"scripts": {
...
},
"dependencies": {
...
"react-crud-shared": "file:../shared",
...
},
"engines": {
"node": "8"
},
"private": true,
"devDependencies": {
...
}
}
At react-crud-shared I have the following:
{
"name": "react-crud-shared",
"version": "0.0.1",
"description": "",
"main": "src/index.js",
"private": true,
"dependencies": {
"lodash": "^4.17.11"
}
}
It works fine on development: "firebase serve --only functions", but an error is thrown on deployment:
Did you list all required modules in the package.json dependencies?
Detailed stack trace: Error: Cannot find module 'react-crud-shared'
Is there a way to make it work without having to publish the private repository to NPM?
Thanks
EDIT: I found a solution for this that I like much better. I commented on this github issue here: https://github.com/firebase/firebase-tools/issues/968#issuecomment-460323113 . Basically, I have a preinstall script the runs npm pack to copy over the package under the functions directory before I use firebase deploy.
FWIW I have the exact same problem. Not exactly sure how I'm going to solve it, but this information from the doc was helpful (https://firebase.google.com/docs/functions/handle-dependencies):
To specify a dependency for your function, add it to your package.json file. If you are deploying through the gcloud command-line tool, you can also pre-install dependencies and deploy them alongside your function. By default, the node_modules folder is added to your .gcloudignore file and is not uploaded as part of your deployment. To deploy pre-installed dependencies, remove node_modules/ from the .gcloudignore file before deploying your function.
Note: Deploying pre-installed dependencies works with gcloud only; the Firebase CLI ignores the local node_modules folder.
Thus, it appears you could first run "npm install" locally, and then use gcloud for deployment, as it would copy up your node_modules directory, which would have your peer dependency in it.
Really kind of stinks, though, that I would have to switch to gcloud from firebase CLI for deployment. Ugh.
node_modules are (ordinary) being ignored for the deployment;
one can still deploy private modules with a directory structure like that:
functions/
index.js
package.json
react-crud-shared/
package.json
and a package.json alike that:
{
"dependencies": {
...
"react-crud-shared": "file:./react-crud-shared"
}
}
another method would be to blank the ignores:
{
"functions": {
"ignore": []
}
}
just think the first one is better, because this would push the whole local node_modules directory.
beside these workaround methods ...
one can install internally published modules from Cloud Source Repositories, via git+https://.
If the goal is to only share module between web and function, you may simple put the shared package under functions as file:react-crud-shared and then reference the package from web using file:../functions/react-crud-shared.
functions/
package.json
...
react-crud-shared/
package.json
...
web/
package.json
...
in functions/package.json
{
"dependencies": {
...
"react-crud-shared": "file:react-crud-shared"
}
}
in web/package.json
{
"dependencies": {
...
"react-crud-shared": "file:../functions/react-crud-shared"
}
}
It works perfectly fine for my case since I use shared protobufjs for cleaner typescript.
What I have found is that the location of your private package has to be inside your cloud functions folder (default to be functions)
So if you move your private package inside your cloud function folder and set the path of that package correctly in package.json, it should work.

laravel mix sass images not found/hash

I am working for the first time with Laravel. With the 5.4 version they introduced the laraval mix. I tried to paste my SASS of the static website (I compile this with gulp) into sass files in the resources folder. This goes all well, my SASS will be compiled to the app.css file in the public map.
I have 1 main problem. All images in the sass files (resources/assets/images) are not compiling as I would like to have.
Code in SASS file (resources/assets/SASS/banners.scss)
section.module.parallax-1 {
background-image: url('../images/banner1.jpg');
}
Compiled with mix in (app.css)
section.module.parallax-1 {
background-image: url(/images/banner1.jpg?ef4f135bad144d886f07c8b65f757a85);
}
So instead of compiling the url to css like I have it in my SASS file, it compiles it to something different with the hash at the end. Also, after compiling the sass it generates a images map with the images I used in my SASS files. My images map originally is located at resources/assets/images.
I don't know what I am doing wrong. I've tried to change the url in my sass files but this will not help. Is there someone who can help me out? Or is there a other solution for this?
webpack.mix code / js
const mix = require('laravel-mix');
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css');
I had the same issue right now. As far as I can see this is no longer the case in the newest laravel mix version. But since its not yet up on npmjs
You can use the following fix:
in webpack.mix.js add
mix.options({
processCssUrls: false // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched.
});
Then copy node_modules/laravel_mix/setup/webpack.config.js to your root directory.
(Same as where the webpack.mix.js is)
Find and remove this string from your new webpack.config.js file
{ loader: 'resolve-url-loader' + sourceMap },
When thats done you have to update your npm scripts to use your webpack.config.js file.
In your package.json use these scripts instead
"scripts": {
"dev": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules",
"watch": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules",
"hot": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot",
"production": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules"
},

ASP .NET 5 - grunt task to copy files from node modules to wwwroot

I have a simple ASP .NET 5 empty project - with npm and grunt installed.
I've used npm to install a few client-side libraries, at present located in the node_modules directory directly under my ASP .NET project.
I want to copy the relevant files (for example, jquery.min.js) from the node_modules folder into the wwwroot folder.
It's unclear to me how to use grunt to do this - as each node module has it's own dependency tree, and there doesn't seem to be any consistency in the file structure from package to package.
I could write a grunt task explicitly for each client side library I use, but in that case I may as well download everything manually and place the files where I need them manually, avoiding npm all together.
I know I could use bower, which has a flat dependency tree - which is probably the root I should go down - but I've read a few articles saying "there's no need for bower - npm can do it all" and therefore I would like to know if there's a way to do this purely with npm.
Is there a way? Or is the "npm can do it all" statement aimed at projects that will require the components directly from the node_modules?
TL DR; Is bower a better fit than npm for ASP .NET 5 projects with separation of source and build files, and if not, what's the recommended way of doing it purely with npm?
I don't fill me professional in grunt, but I use it myself and I think that I can explain you how one can use it corresponds to your requirements.
First of all you should add "New Item" to your project, choose "Client-Side" and "NPM Configuration file" to add package.json to the the project (in the same directory where you have project.json). I suppose you have already created the file, but the existence of the file is important for grunt too. Then you adds some dependencies, which you need on the client-side to "dependencies" part of package.json and add at least grunt and grunt-contrib-copy to "devDependencies" part. An example of the file you will see below
{
"version": "1.0.0",
"name": "ASP.NET",
"private": true,
"dependencies": {
"font-awesome": "^4.5.0",
"jquery": "^1.11.3"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-clean": "^0.7.0",
"grunt-contrib-copy": "^0.8.2"
}
}
Now you should add "Grunt Configuration File" in the same way like you added "NPM Configuration file". You will create gruntfile.js (in the same directory where you have project.json). Finally you should fill gruntfile.js with more helpful code. For example the code
module.exports = function(grunt) {
grunt.initConfig({
clean: ["wwwroot/font-awesome/", "wwwroot/jquery*.*"],
copy: {
main: {
files: [
{
src: "node_modules/font-awesome/css/*",
dest: "wwwroot/font-awesome/css/",
expand: true,
filter: "isFile",
flatten: true
},
{
src: "node_modules/font-awesome/fonts/*",
dest: "wwwroot/font-awesome/fonts/",
expand: true,
filter: "isFile",
flatten: true
},
{
src: "node_modules/jquery/dist/*",
dest: "wwwroot/",
expand: true,
filter: "isFile",
flatten: true
}
]
}
}
});
grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.registerTask("all", ["clean", "copy"]);
grunt.registerTask("default", "all");
};
registers two tasks: clean and copy and the aliases all and default. You can select gruntfile.js file in the solution explorer, open context menu and choose "Task Runner Explorer". You will see all defined tasks. The task with the name "default" will be executed if you execute grunt without parameters (without the task name) in the command line.
Now you can choose some task and run it. You can choose some task, click right mouse button to open context menu and check "After Build" in "Bindings":
Now the task will be executed every time when you build the project. You can click optionally "V" button on the left side to see verbose information from the executed tasks.
I hope it's already the main information which you need. Many other helpful information about plugins grunt-contrib-clean, grunt-contrib-copy, grunt-contrib-jshint, grunt-jscs, grunt-newer and many other you will find yourself. One official place of ASP.NET 5 documentation should be mentioned. It's the place.
P.S. You asked additionally about the usage of bower. I find both npm and bower not perfect, but still very practical. I would prefer to hold full control over the dependencies and especially about the data, which will be copied under wwwroot. Thus I change the content of .bowerrc file from { "directory": "wwwroot/lib" } to { "directory": "bower_components" } and I use grunt to copy the required data from bower_components in the same way like I do this with files from node_modules. See the article for more details. In other words I use packages published only in bower repository in the same way like I use npm packages.

Resources