JavaScript Language Injection in JSP
In IntelliJ, JSP files are considered as HTML content by default.
However, I have the situation that in our project some files contain JavaScript code, because these *.tag files are included from within a <script> block.
Now, I want the amazing code highlighting, suggestion, inspections, etc. of IntelliJ for this JavaScript code. I tried to trick the IDE to get what I want, but I did not quite succeed.
Example:
in javascript-init-main.tag I have
<script>
let bla = "This is recognized as JavaScript by IntelliJ and everything is working fine.";
let usingJsp1 = 'Mixing with ${"Java world"}.'
<mytaglib:javascript-init-sub.tag />
</script>
in javascript-init-sub.tag I have
let blub = "This is not recognized as JavaScript by IntelliJ because it is not placed inside a <script> tag"
let usingJsp2 = 'Mixing with ${"Java world"}'
Question: how to get proper JavaScript support in javascript-init-sub.tag?
I tried the following hack, to place a not-really-active script tag to trick the IDE
${"/*"}<script>${"*/"}
let blub = "This is now recognized as JavaScript by IntelliJ because it is assumed to be placed inside a <script> tag"
let usingJsp2 = 'Mixing with ${"Java world"}'
${"/*"}</script>${"*/"}
However, this does not work in the browser because </script> is terminating the original <script> tag from javascript-init-main.
But it would work when using something else than <script>.
I know about Language Injection and tried to introduce a <typescript> tag that should inject the language just as <script> does.
Therefor, I extended the built-in injection rule to "XML Tag: script|typescript". Then I tried:
${"/*"}<typescript>${"*/"}
let blub = "I did not find a way to make this work. Either JavaScript is not recognized, or mixing with JSP did not work."
let usingJsp2 = 'Mixing with ${"Java world"}'
${"/*"}</typescript>${"*/"}
Sadly, this trickery did not work. The mixing with JSP is broken when I do this. I guess IntelliJ has some custom logic for the script tag.
So I am back where I started.
How to tell IntelliJ, what is the primary language inside a *.tag file? Maybe there is some rule that I can apply to the whole file?
Please sign in to leave a comment.
Actually, I just noticed that my trickery *does* work.
I can just omit the closing fake-tag, because the opening fake-tag in the end is only a JavaScript comment and does not need a counterpart.
IntelliJ will assume all text after the fake-tag to be JavaScript. Problem solved.
So, in javascript-init-sub.tag it is now
Still, it would be nice if IntelliJ (or the JSP standard) would allow to specify the primary language in a *.tag file somehow.
You can add javascript-init-sub.tag to a list of file name patterns associated with JavaScript file type in Settings | Editor | File Types - this particular file will be treated as a javascript file while other .tag files will still be considered HTML
When using Settings | Editor | File Types, then everything JSP in the file is highlighted as error (e.g. <% %>).
I still want JSP but the rest should be considered JavaScript, like when using <script> element.
You can specify the data language right in your JSP code with
contentType
(see https://stackoverflow.com/questions/48382179/what-is-the-content-type-of-a-jsp-file, for example), likeYes, this would be what I want.
Problem is that it is not allowed in a *.tag file and IntelliJ does not know (cannot know) where I include the tag file.
When I do
then I get "Tag should not be used in tag file", i.e., the <@page is not allowed.
When I do
then I get "Attribute contentType is not allowed here".
So, what I want does not seem to be possible with JSP features.
I just found out about Template Data Languages.
But this did not work (or I use it wrong). When I specify the path to one of my tag files and set the Template Data Language to "JavaScript", then it does not make a difference. I don't get the same IDE features like when I use a <script> element.
It doesn't work for JSP file type, the data language is detected from the
contentType
(if any)Related ticket: https://youtrack.jetbrains.com/issue/IDEA-100191
I changed my workaround slightly such that the the fake script element does not appear in the generated output anymore:
Note that you could also omit the /* and */ part because the script element is not printed to the output anyway:
This way, you could also add a fake closing script element:
This workaround works well for me in IntelliJ 2021.1.1.