gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Here's our mission: to get rid of all the JavaScript and CSS stuff from our public/
directory. Our next target is admin_article_form.js
:
Dropzone.autoDiscover = false; | |
$(document).ready(function() { | |
... lines 4 - 33 | |
}); | |
// todo - use Webpack Encore so ES6 syntax is transpiled to ES5 | |
class ReferenceList | |
{ | |
... lines 39 - 123 | |
} | |
/** | |
* @param {ReferenceList} referenceList | |
*/ | |
function initializeDropzone(referenceList) { | |
... lines 130 - 148 | |
} |
This probably won't come as a huge shock, but this is used in the admin section. Go to /admin/article
. If you need to log in, use admin1@thespacebar.com
, password engage
. Then click to edit any of the articles.
This page has JavaScript to handle the Dropzone upload and a few other things. Open the template: templates/article_admin/edit.html.twig
and scroll down. Ok: we have a traditional <script>
tag for admin_article_form.js
as well as two external JavaScript files that we'll handle in a minute:
... lines 1 - 35 | |
{% block javascripts %} | |
{{ parent() }} | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.js" integrity="sha256-cs4thShDfjkqFGk5s2Lxj35sgSRr4MRcyccmi0WKqCM=" crossorigin="anonymous"></script> | |
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.8.3/Sortable.min.js" integrity="sha256-uNITVqEk9HNQeW6mAAm2PJwFX2gN45l8a4yocqsFI6I=" crossorigin="anonymous"></script> | |
<script src="{{ asset('js/admin_article_form.js') }}"></script> | |
{% endblock %} |
This is super similar to what we just did. First, move admin_article_form.js
into assets/js
. This will be our third entry. So, in webpack.config.js
copy addEntry()
, call this one admin_article_form
and point it to admin_article_form.js
:
... lines 1 - 2 | |
Encore | |
... lines 4 - 21 | |
.addEntry('admin_article_form', './assets/js/admin_article_form.js') | |
... lines 23 - 73 | |
; | |
... lines 75 - 76 |
Finally, inside edit.html.twig
, change this to use {{ encore_entry_script_tags('admin_article_form')
}}:
... lines 1 - 35 | |
{% block javascripts %} | |
... lines 37 - 40 | |
{{ encore_entry_script_tags('admin_article_form') }} | |
{% endblock %} |
Now, stop and restart Encore:
yarn watch
Perfect! 3 entries and a lot of good code splitting. But we shouldn't be too surprised that when we refresh, we get our favorite JavaScript error:
$ is not defined
Let's implement phase 2 of refactoring. In admin_article_form.js
, import $ from 'jquery'
:
import $ from 'jquery'; | |
... lines 2 - 152 |
And... we're good to go!
In addition to moving things out of public/
, I also want to remove all of these external script tags:
... lines 1 - 35 | |
{% block javascripts %} | |
... lines 37 - 38 | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.js" integrity="sha256-cs4thShDfjkqFGk5s2Lxj35sgSRr4MRcyccmi0WKqCM=" crossorigin="anonymous"></script> | |
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.8.3/Sortable.min.js" integrity="sha256-uNITVqEk9HNQeW6mAAm2PJwFX2gN45l8a4yocqsFI6I=" crossorigin="anonymous"></script> | |
... line 41 | |
{% endblock %} |
Actually, there's nothing wrong with including external scripts - and you can definitely argue that including some things - like jQuery - could be good for performance. If you do want to keep a few script tags for external stuff, check out Webpack's "externals" feature to make it work nicely.
The reason I don't like them is that, in the new way of writing JavaScript, you never want undefined variables. If we need a $
variable, we need to import $
! But check it out: we're referencing Dropzone
:
... lines 1 - 2 | |
Dropzone.autoDiscover = false; | |
... lines 4 - 152 |
Where the heck does that come from? Answer: it's a global variable created by this Dropzone script tag!
... lines 1 - 35 | |
{% block javascripts %} | |
... lines 37 - 38 | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.js" integrity="sha256-cs4thShDfjkqFGk5s2Lxj35sgSRr4MRcyccmi0WKqCM=" crossorigin="anonymous"></script> | |
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.8.3/Sortable.min.js" integrity="sha256-uNITVqEk9HNQeW6mAAm2PJwFX2gN45l8a4yocqsFI6I=" crossorigin="anonymous"></script> | |
... line 41 | |
{% endblock %} |
The same is true for Sortable
further down. I don't want to rely on global variables anymore.
Trash both of these script tags. Then, find your terminal, go to your open tab and run:
yarn add dropzone sortablejs --dev
I already looked up those exact package names to make sure they're right. Next, inside admin_article_form.js
, these variables will truly be undefined now. Try it: refresh. A most excellent error!
Dropzone is undefined
It sure is! Fix that with import Dropzone from 'dropzone'
and also import Sortable from 'sortablejs'
:
import $ from 'jquery'; | |
import Dropzone from 'dropzone'; | |
import Sortable from 'sortablejs'; | |
... lines 4 - 154 |
Now it works.
But there's one more thing hiding in our edit template: we have a CDN link to the Dropzone CSS!
... lines 1 - 29 | |
{% block stylesheets %} | |
{{ parent() }} | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.css" integrity="sha256-e47xOkXs1JXFbjjpoRr1/LhVcqSzRmGmPqsrUQeVs+g=" crossorigin="anonymous" /> | |
{% endblock %} | |
... lines 35 - 41 |
We don't need that either. Instead, in admin_article_form.js
, we can import the CSS from the Dropzone package directly. Hold Command
or Control
and click to open Dropzone. I'll double-click the dropzone
directory to take us there.
Inside dist
... there it is: dropzone.css
. That's the path we want to import. How? With import 'dropzone/dist/dropzone.css'
:
... line 1 | |
import Dropzone from 'dropzone'; | |
import 'dropzone/dist/dropzone.css' | |
... lines 4 - 155 |
Most of the time, we're lazy and we say import
then the package name. But it's totally legal to import the package name / a specific file path.
As soon as we do that, go check out the Encore watch tab. Wow! The code splitting is getting crazy! Hiding inside there is one CSS file: vendors~admin_article_form.css
.
Flip back to the edit template and add {{ encore_entry_link_tags('admin_article_form') }}
:
... lines 1 - 29 | |
{% block stylesheets %} | |
{{ parent() }} | |
{{ encore_entry_link_tags('admin_article_form') }} | |
{% endblock %} | |
... lines 35 - 41 |
Try it! Find your browser and refresh! Ok, it looks like the Dropzone CSS is still working. I think we're good!
This same JavaScript & CSS code is needed on one other page. Go back to /admin/article
and click create. Oof, we still have some problems here. I'll close up node_modules/
and open templates/article_admin/new.html.twig
:
... lines 1 - 2 | |
{% block javascripts %} | |
{{ parent() }} | |
<script src="https://cdn.jsdelivr.net/autocomplete.js/0/autocomplete.jquery.min.js"></script> | |
<script src="{{ asset('js/algolia-autocomplete.js') }}"></script> | |
<script src="{{ asset('js/admin_article_form.js') }}"></script> | |
{% endblock %} | |
... lines 10 - 24 |
Ah, cool. Replace the admin_article_form.js
script with our helper Twig function:
... lines 1 - 2 | |
{% block javascripts %} | |
... lines 4 - 7 | |
{{ encore_entry_script_tags('admin_article_form') }} | |
{% endblock %} | |
... lines 10 - 25 |
Under stylesheets, the new page doesn't use Dropzone, so it didn't have that same link tag here. Add {{ encore_entry_link_tags('admin_article_form') }}
anyways so that this page has all the JS and CSS it needs:
... lines 1 - 10 | |
{% block stylesheets %} | |
{{ parent() }} | |
{{ encore_entry_link_tags('admin_article_form') }} | |
... line 15 | |
{% endblock %} | |
... lines 17 - 25 |
But this does highlight one... let's say... "not ideal" thing. Some of the JavaScript on the edit page - like the Dropzone & Sortable stuff - isn't needed here... but it's part of admin_article_form.js
anyways. And actually, the reverse is true! That autocomplete stuff? That's needed on the "new" page, but not the edit page. At the end of the tutorial, we'll talk about async imports, which is one really nice way to help avoid packaging code all the time that is only needed some of the time.
Anyways, if we refresh now... the page is still totally broken! Apparently this "autocomplete" library we're importing is trying to reference jQuery. Let's fix that next... which will involve a... sort of "magical" feature of Webpack and Encore.
try it this way:
<link rel="icon" type="image/svg" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20128%20128%22%3E%3Ctext%20y%3D%221.2em%22%20font-size%3D%2296%22%3E%E2%9A%AB%EF%B8%8F%3C%2Ftext%3E%3C%2Fsvg%3E">
so there are many SVG encoders around so you can find them with inline svg favicon
search string and use any you want
Cheers!
hi i think there is no need to import each time we can import it one time at app.js because its the main script and make a $ global varible that for one time
Hey @Mina-R,
Probably if you want to use jQuery on each page, then maybe yes, but in case you don't need it everywhere and for assets optimisation it will be better to import it only on use case
PS as for me jQuery is not something I'd like to have globaly
Cheers!
Hey Bogdan,
Are you sure the code was actually updated after you put that import statement? Some browsers like Chrome may cache the file. I'd recommend you to open the page in incognito mode and do force refresh of the page. You can also make sure that file was updated by adding an alert() or console.log() call to that file with a custom message to make sure the browser uses the new code.
If you still have the problem - let us know.
Cheers!
Hi.
thank you for your response.
I am sorry that I cant paste a screnshoot.
the problem I am trying to install the material-kit from yarn and I have an error.
WAIT Compiling... 4:53:57 PM
ERROR Failed to compile with 1 errors 4:53:57 PM
error in ./node_modules/material-kit/index.html
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/conc...
>
| <html lang="en">
|
@ ./assets/js/app.js 11:0-22
Hey Bogdan,
Hm, I don't see how this error relates to the initial error from your previous comment. May I know what exactly command you're executing when see this error? I suppose material-kit was installed successfully.
Cheers!
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"aws/aws-sdk-php": "^3.87", // 3.91.4
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
"knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
"knplabs/knp-time-bundle": "^1.8", // 1.9.0
"league/flysystem-aws-s3-v3": "^1.0", // 1.0.22
"league/flysystem-cached-adapter": "^1.0", // 1.0.9
"liip/imagine-bundle": "^2.1", // 2.1.0
"nexylan/slack-bundle": "^2.0,<2.2.0", // v2.1.0
"oneup/flysystem-bundle": "^3.0", // 3.0.3
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"sensio/framework-extra-bundle": "^5.1", // v5.3.1
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.2.5
"symfony/console": "^4.0", // v4.2.5
"symfony/flex": "^1.9", // v1.17.6
"symfony/form": "^4.0", // v4.2.5
"symfony/framework-bundle": "^4.0", // v4.2.5
"symfony/orm-pack": "^1.0", // v1.0.6
"symfony/security-bundle": "^4.0", // v4.2.5
"symfony/serializer-pack": "^1.0", // v1.0.2
"symfony/twig-bundle": "^4.0", // v4.2.5
"symfony/validator": "^4.0", // v4.2.5
"symfony/web-server-bundle": "^4.0", // v4.2.5
"symfony/webpack-encore-bundle": "^1.4", // v1.5.0
"symfony/yaml": "^4.0", // v4.2.5
"twig/extensions": "^1.5" // v1.5.4
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.1.0
"easycorp/easy-log-handler": "^1.0.2", // v1.0.7
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/debug-bundle": "^3.3|^4.0", // v4.2.5
"symfony/dotenv": "^4.0", // v4.2.5
"symfony/maker-bundle": "^1.0", // v1.11.5
"symfony/monolog-bundle": "^3.0", // v3.3.1
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.2.5
"symfony/profiler-pack": "^1.0", // v1.0.4
"symfony/var-dumper": "^3.3|^4.0" // v4.2.5
}
}
// package.json
{
"devDependencies": {
"@symfony/webpack-encore": "^0.27.0", // 0.27.0
"autocomplete.js": "^0.36.0",
"autoprefixer": "^9.5.1", // 9.5.1
"bootstrap": "^4.3.1", // 4.3.1
"core-js": "^3.0.0", // 3.0.1
"dropzone": "^5.5.1", // 5.5.1
"font-awesome": "^4.7.0", // 4.7.0
"jquery": "^3.4.0", // 3.4.0
"popper.js": "^1.15.0",
"postcss-loader": "^3.0.0", // 3.0.0
"sass": "^1.29.0", // 1.29.0
"sass-loader": "^7.0.1", // 7.3.1
"sortablejs": "^1.8.4", // 1.8.4
"webpack-notifier": "^1.6.0" // 1.7.0
}
}
how can i import svgs without making the more request overhead on my app like how can i imoprt somthing like that: