Torchlight.dev — The VS Code Compatible Syntax Highlighting API.

Laravel Torchlight Client

Tests Latest Stable Version Total Downloads License GitHub

View the Laravel client on GitHub at github.com/torchlight-api/torchlight-laravel.

Installation

To install, require the package from composer:

1composer require torchlight/torchlight-laravel

Middleware

Include the RenderTorchlight middleware in your Http/Kernel.php. You should include this as the very first middleware in your global middleware stack, to ensure that it will be the last middleware to run as the response comes out.

1protected $middleware = [
+ \Torchlight\Middleware\RenderTorchlight::class,
3 \App\Http\Middleware\TrustProxies::class,
4 \Fruitcake\Cors\HandleCors::class,
5 \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
6 \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
7 \App\Http\Middleware\TrimStrings::class,
8 \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
9];

The Torchlight client is designed in such a way that regardless of how many blocks you have on a page, only one request to the Torchlight API will ever be made. If all the blocks are cached, zero requests are made.

When the middleware runs, it will fire a request to the Torchlight API if there are any blocks that aren't already cached. Once the client has gathered all the blocks from the API or the cache, it will replace the plain code blocks with properly highlighted blocks.

Configuration

You can run the following command to publish your configuration file:

1php artisan torchlight:install

Once run, you should see a new torchlight.php file in your config folder, with contents that look like this:

<?php
return [
// The Torchlight client caches highlighted code blocks. Here
// you can define which cache driver you'd like to use.
'cache' => env('TORCHLIGHT_CACHE_DRIVER'),
// Which theme you want to use. You can find all of the themes at
// https://torchlight.dev/themes. [tl! autolink]
'theme' => env('TORCHLIGHT_THEME', 'material-theme-palenight'),
// Your API token from torchlight.dev.
'token' => env('TORCHLIGHT_TOKEN'),
// If you want to register the blade directives, set this to true.
'blade_components' => true,
// The Host of the API.
'host' => env('TORCHLIGHT_HOST', 'https://api.torchlight.dev'),
// Global options to control blocks-level settings.
// @see https://torchlight.dev/docs/options [tl! autolink]
'options' => [
// Turn line numbers on or off globally
'lineNumbers' => true,
// Control the `style` attribute applied to line numbers.
// 'lineNumbersStyle' => '',
// Turn on +/- diff indicators.
'diffIndicators' => true,
// If there are any diff indicators for a line, put them
// in place of the line number to save horizontal space.
'diffIndicatorsInPlaceOfLineNumbers' => true,
// When lines are collapsed, this is the text that will
// be shown to indicate that they can be expanded.
// 'summaryCollapsedIndicator' => '...',
]
];

Cache

Torchlight caches code blocks based on their contents and configuration, so that blocks that have already been rendered won't be rendered again. Using the cache key you can set which driver you would like to use.

If you don't specify a cache, your application's default cache will be used.

Theme

You can change the theme of all your code blocks by adjusting the theme key in your configuration. To view all of the themes provided by Torchlight, head over to torchlight.dev/themes.

Token

This is your API token from torchlight.dev. (Torchlight is completely free for personal and open source projects.)

Blade Components

Torchlight works by using a custom Laravel Blade component. If you'd like to disable the registration of the component for whatever reason, you can set this to false.

Options

These are options that you can set to control every code block on your site. Read more in the options section.

The Blade Component

The Laravel client provides you with a custom custom Laravel Blade component registered as <x-torchlight-code>. To highlight code, you would use this component in place of the standard HTML <code> tag.

<x-torchlight-code language='php'>
echo "Hello World!";
</x-torchlight-code>

The contents inside of the custom component will be sent to Torchlight, parsed as PHP (based on the language attribute), and returned as fully rendered HTML:

<code class="torchlight" style="background-color: #fff;">
<div class="line">
<span style="color: #1b1f234d; text-align: right; -webkit-user-select: none; user-select: none;" class="line-number">1</span>
<span style="color: #005CC5;">echo</span>
<span style="color: #24292E;"> </span>
<span style="color: #032F62;">"Hello World!"</span>
<span style="color: #24292E;">;</span>
</div>
</code>

Line breaks added for readability. In reality, it's all compressed onto a single.

You will likely want to wrap blocks of code in <pre> tags just like you would normally do:

<pre><x-torchlight-code language='php'>
echo "Hello World!";
</x-torchlight-code></pre>

Language

You must declare a language attribute, so that Torchlight knows how to parse the contents.

<x-torchlight-code language='php'>
echo "Hello World!";
</x-torchlight-code>

To see all of the available languages, check the languages page.

Theme

You may also override the theme for a specific block by passing in a theme attribute

<x-torchlight-code language='php' theme='github-dark'>
echo "Hello World!";
</x-torchlight-code>

Regardless of what is specified in your torchlight.php file, this block will be using the github-dark theme.

Rendering Files

Sometimes it's easier to write your code in a dedicated file instead of inline in your blade view. The code component accepts a contents attribute for just such use cases.

Using the contents attribute, you can pass in the path of a file to be rendered:

<x-torchlight-code language='js' contents="{{ base_path('webpack.mix.js') }}" />
{{-- Or... --}}
<x-torchlight-code language='js' :contents="base_path('webpack.mix.js')" />

Torchlight will read the contents of that file and send it off to be highlighted. This lets you write your docs or examples in your editor with proper indentation and highlighting.

Content Paths

If you use the contents attribute, Torchlight will first check to see if the attribute you have provided is a file. If you pass in an absolute path, Torchlight will render that file.

If the path is not a valid file, Torchlight will wrap check the resource_path to see if your file lives there.

If you have a folder of examples in your resources folder, then you can pass a string as a shorthand:

<x-torchlight-code language='php' contents='examples/very-impressive-example.php' />

Since examples/very-impressive-example.php is not a file, but resource_path('examples/very-impressive-example.php') is, the component will read the content from that file and send it to Torchlight.

Other Attributes

All other attributes will be passed through to the code tag.

If you add classes to your component, they will be merged with the classes that come back from the Torchlight API.

So if you add e.g. my-6:

<x-torchlight-code language='php' class='my-6'>
echo "Hello World!";
</x-torchlight-code>

It will still be there when the contents are swapped in:

<code class="torchlight my-6" style="background-color: #fff;">
<!-- ... -->
</code>

All other attributes will be passed through unmodified:

<x-torchlight-code id="block-1" language='php'>
echo "Hello World!";
</x-torchlight-code>

It will still be there when the contents are swapped in:

<code id="block-1" class="torchlight my-6" style="background-color: #fff;">
<!-- ... -->
</code>

Post-Processing Blocks

The Laravel client allows you to register "post processors" that can change the contents of a code block after it comes back from the API and before it's sent to your frontend.

This can be particularly useful if you want to inject some user information (API keys, URL endpoints, etc), or if you want to further mark up a specific string for easier JavaScript access.

Let's take a look at an example that will add a user's authentication token to a block of code.

Creating the Post-Processor

The first thing you'll need to do is create a post-processor class. It must implement the PostProcessor interface:

use Torchlight\Block;
class InjectAuthToken implements PostProcessor
{
public function process(Block $block)
{
// @TODO
}
}

The only required method is process, which will receive a Torchlight Block. You can modify the contents of the block in this method. For this example, we will look for user_auth_token and replace it with the user's actual token.

use Torchlight\Block;
class InjectAuthToken implements PostProcessor
{
public function process(Block $block) // [tl! focus:start]
{
$token = Auth::check() ? Auth::user()->token : 'token';
// Replace the placeholder with the user's token.
$block->highlighted = str_replace(
'user_auth_token', $token, $block->highlighted
);
} // [tl! focus:end]
}

Every single block will run through this process method, so make sure the placeholder you choose is pretty unique. You may make it a little bit longer and more random:

use Torchlight\Block;
class InjectAuthToken implements PostProcessor
{
public function process(Block $block) // [tl! focus:start]
{
$token = Auth::check() ? Auth::user()->token : 'token';
// Replace the placeholder with the user's token.
$block->highlighted = str_replace(
'processor_replace_user_token_here', $token, $block->highlighted // [tl! highlight]
);
} // [tl! focus:end]
}

You can also use post-processors to add HTML markup, that will not be escaped. This is helpful if you want to add some sort of JavaScript enhancement and need a way to target a specific element.

use Torchlight\Block;
class InjectAuthToken implements PostProcessor
{
public function process(Block $block) // [tl! focus:start]
{
$token = Auth::check() ? Auth::user()->token : 'token';
// Wrap the token in a `mark` tag and give it a class
// so JavaScript can target it and enhance it.
$token = "<mark class='user-auth-token'>{$token}</mark>";
// Replace the placeholder with the user's token.
$block->highlighted = str_replace(
'user_auth_token', $token, $block->highlighted
);
} // [tl! focus:end]
}

Registering the Post-Processor

Once you have your class created, you'll need to register it, typically in a service provider:

Torchlight::addPostProcessors([
InjectAuthToken::class
]);

Post-Processing + Laravel Markdown

If you are using the Laravel Markdown package by Graham Campbell and you're using post-processors, there is one thing you'll need to look out for.

The Laravel Markdown package allows you to return .md views from your controller and Laravel Markdown will render them to proper HTML. It also writes the rendered file to the view cache, and pulls it from the cache the next time it's needed.

By default, post-processors are disabled when the views are being compiled by the Laravel Markdown package. The reason we do this is because if you inject a user's auth token into a block, the Markdown package will save it to disk and serve it to every user from there on out, showing the user's auth token to everyone. Obviously this is a huge security issue.

If you understand this risk, you can add a property to your post-processor called $processEvenWhenCompiling and set it to true.

use Torchlight\Block;
class InjectAuthToken implements PostProcessor
{
public $processEvenWhenCompiling = true;
public function process(Block $block)
{
// Do NOT use Auth::user() here!
}
}

This processor will now run when views are being compiled, so be sure to not inject any user data.

Troubleshooting

There are a few common things that can go wrong. Read below for solutions.

Component Not Rendering File

If your component is not rendering, make sure that you are not using the same kind of quote (single/double) on the outside and inside of the contents attribute. This is a Laravel limitation, not a Torchlight one.

{{-- This will work, double quotes on the outside, single on the inside. --}}
<x-torchlight-code contents="{{ base_path('webpack.mix.js') }}" language='js' />
{{-- This will NOT work, single quotes for both out and inside. --}}
<x-torchlight-code contents='{{ base_path('webpack.mix.js') }}' language='js' />

Views Not Updating

If you are changing your code or Torchlight config and not seeing changes reflected in the browser, it is likely because Laravel has cached your views and is serving old versions instead of the most recent versions.

You can clear that by calling php artisan view:clear. If you are still seeing cached results, you may try clearing your application cache as well:

php artisan view:clear && php artisan cache:clear

Un-rendered Blocks

Are you seeing weird stuff like this? ##PRE_TL_COMPONENT##__torchlight-block-[6179eb34-30dd-406d-b870-1b03988fa248]__##POST_TL_COMPONENT##

That means that the blade component has captured your code contents and left its placeholder on the page, but it was never replaced by the rendered code. Typically this means that you haven't registered the middleware (see above).

If you aren't using the middleware at all (e.g. Jigsaw doesn't use the middleware), then you'll need to make sure you are manually calling BladeManager::renderContent($content) somewhere. This is the function that replaces all the placeholders with fully rendered blocks.

Our first-party clients (e.g. the Jigsaw one) handle this for you, but if you're off the beaten path you'll want to make sure you're completing "Step 2" of the Torchlight process.

A Hammerstone, LLC Product.
Built with Love & Care by Aaron in Dallas, Texas.