From 7db14df76883ba52f6fcc13a2f7a18f6ed7914e3 Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Tue, 1 Jun 2021 23:39:46 -0400 Subject: [PATCH 1/9] Remove @sveltedirect Blade Directive Remove the custom blade directive, so we can replace with a @stack call --- src/SvelteDirectServiceProvider.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/SvelteDirectServiceProvider.php b/src/SvelteDirectServiceProvider.php index 4fe7183..d7de32e 100644 --- a/src/SvelteDirectServiceProvider.php +++ b/src/SvelteDirectServiceProvider.php @@ -16,7 +16,6 @@ public function boot(): void { $this->loadManifestFile(); $this->loadBladePreCompiler(); - $this->loadBladeDirective(); } public function defaultManifestPath() : string @@ -40,15 +39,6 @@ public function loadBladePreCompiler() : void $this->app['blade.compiler']->precompiler([$this, 'findTagsInBladeTemplate']); } - public function loadBladeDirective() : void - { - if (! $this->manifest) { - return; - } - - Blade::directive('sveltedirect', [$this, 'generateDirectiveHtml']); - } - /** @internal */ public function findTagsInBladeTemplate(string $view) : string { From c009ed43c7a53182a73fac2797102c50585595ba Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Tue, 1 Jun 2021 23:54:52 -0400 Subject: [PATCH 2/9] Refactor Precompiler Function - Use Push Blade Directive instead of custom @sveltedirect one - This allows us to not have to keep track of the found tags for each blade view, and to load the corresponding JS as we find it --- src/SvelteDirectServiceProvider.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/SvelteDirectServiceProvider.php b/src/SvelteDirectServiceProvider.php index d7de32e..bd8bef5 100644 --- a/src/SvelteDirectServiceProvider.php +++ b/src/SvelteDirectServiceProvider.php @@ -10,7 +10,6 @@ class SvelteDirectServiceProvider extends ServiceProvider { public ?array $manifest = []; - public array $tagsBeingUsed = []; public function boot(): void { @@ -45,16 +44,19 @@ public function findTagsInBladeTemplate(string $view) : string $tagPattern = implode('|', array_keys($this->manifest)); $pattern = "/(?<=<)\s*{$tagPattern}/"; preg_match_all($pattern, $view, $matches); - $this->tagsBeingUsed = array_merge(array_unique($matches[0]), $this->tagsBeingUsed); - return $view; + $identifiedTags = array_intersect(array_keys($this->manifest), array_unique($matches[0])); + + $pushHtml = "@push('sveltedirect')" . PHP_EOL . + $this->generateHtml($identifiedTags) + . PHP_EOL . "@endpush"; + + return $view . $pushHtml; } /** @internal */ - public function generateDirectiveHtml(string $expression) : string + public function generateHtml(array $tagsToLoad) : string { - $tagsToLoad = array_intersect(array_keys($this->manifest), $this->tagsBeingUsed); - return array_reduce($tagsToLoad, function ($previous, $current) { return $previous . '' . PHP_EOL; }, ''); From ecf3c1f26ee59e4e9d23c8cfe55e7fec74c42b21 Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Thu, 3 Jun 2021 00:44:30 -0400 Subject: [PATCH 3/9] Move Mix Plugin JavaScript To This Main Package mix.js also contains the updated bootstrap code that uses svelte-tag package under the hood --- src/js/mix.js | 282 +++++++++++++++++++++++++++++++++++ src/js/svelte-code-helper.js | 18 +++ 2 files changed, 300 insertions(+) create mode 100644 src/js/mix.js create mode 100644 src/js/svelte-code-helper.js diff --git a/src/js/mix.js b/src/js/mix.js new file mode 100644 index 0000000..067016d --- /dev/null +++ b/src/js/mix.js @@ -0,0 +1,282 @@ +let mix = require('laravel-mix'); +const { resolve, basename } = require('path'); +const { readdir, writeFile, readFile, unlink } = require('fs').promises; +const { findSvelteProps, findSvelteTagName } = require('./svelte-code-helper'); + +class SvelteDirect { + + /** + * Constructor + */ + constructor() { + this.options = { + componentMode: true, + loaderOptions: { + dev: !Mix.inProduction(), + compilerOptions: { + customElement: false + } + } + }; + + this.manifest = []; + this.tempJavascriptBootloaderFiles = []; + } + + /** + * Dependencies for Svelte webpack + */ + dependencies() { + this.requiresReload = true; + return ["svelte", "svelte-loader"]; + } + + /** + * Plugin entry point + * + * @param {string} inputPath + * @param {string} outputPath + * @param {object} options + */ + register(inputPath, outputPath, options) + { + this.options = { ...this.options, ...options}; + + this.options.loaderOptions.compilerOptions.customElement = !this.options.componentMode; + + this.handle(inputPath, outputPath); + } + + /** + * Webpack rules for building Svelte files + */ + webpackRules() { + return [ + { + test: /\.(html|svelte)$/, + use: [ + { loader: 'babel-loader', options: Config.babel() }, + { loader: 'svelte-loader', options: this.options.loaderOptions } + ] + }, + { + test: /\.(mjs)$/, + use: { loader: 'babel-loader', options: Config.babel() } + } + ]; + } + + /** + * Prepare the provided path for processing. + * + * @param {object} webpackConfig + */ + webpackConfig(webpackConfig) { + webpackConfig.resolve.mainFields = [ + 'svelte', + 'browser', + 'module', + 'main', + ]; + webpackConfig.resolve.extensions = ['.mjs', '.js', '.svelte']; + webpackConfig.resolve.alias = webpackConfig.resolve.alias || {}; + webpackConfig.resolve.alias.svelte = resolve( + 'node_modules', + 'svelte' + ); + } + + /** + * Import our dependencies + */ + boot() { + let svelte = require("svelte"); + let loader = require("svelte-loader"); + } + + /** + * Main Plugin logic + * + * Load config, create temp bootloaders, add them to mix + * + * @param {string} inputPath + * @param {string} outputPath + */ + handle(inputPath, outputPath) + { + let enableSvelteComponentMode =this.options.componentMode; + + mix.before(async () => { + try { + await this.createSvelteBootloaders(inputPath, outputPath, enableSvelteComponentMode); + } catch (error) { + console.error('[SvelteDirect] Encountered error...'); + await this.cleanUp(); + throw error; + } + }); + + mix.after(async () => { + await this.writeManifest(); + await this.cleanUp(); + }); + } + + /** + * Write a manifest file that our Blade pre-compiler uses + * to determine which maps to which compiled JS file + * + * @todo make this an option via config + */ + async writeManifest() + { + const bootstrapFile = resolve( 'bootstrap', 'cache') + '/svelte-direct-components.php'; + let phpCode = ' previous + `'${current.tag}' => '${current.filename}', ` + , '' + ) + + phpCode = phpCode + arrayContent + '];'; + + await writeFile(bootstrapFile, phpCode, 'utf8'); + } + + /** + * Cleanup our generated bootstrap JS files + */ + async cleanUp() + { + for (const f of this.tempJavascriptBootloaderFiles) { + const compiledFilename = f.replace('.svelte', '.js'); + //await unlink(compiledFilename); + } + } + + /** + * Locate all Svelte files in the given path + * + * @param {string} dir + */ + async* fetchSvelteFiles(dir) { + const dirents = await readdir(dir, { withFileTypes: true }); + for (const dirent of dirents) { + const res = resolve(dir, dirent.name); + if (dirent.isDirectory()) { + yield* this.fetchSvelteFiles(res); + } else if (res.toLowerCase().indexOf('.svelte') !== -1) { + yield res; + } + } + } + + /** + * Generate bootstrap JS files that load our Svelte components + * + * @param {string} inputPath + * @param {string} outputPath + * @param {boolean} enableSvelteComponentMode + */ + async createSvelteBootloaders(inputPath, outputPath, enableSvelteComponentMode) { + this.tempJavascriptBootloaderFiles = []; + + for await (const f of this.fetchSvelteFiles(inputPath)) { + const compiledFilename = f.replace('.svelte', '.js'); + const svelteAppData = enableSvelteComponentMode + ? await this.generateBootstrapSvelteComponent(f) + : await this.generateBootstrapWebComponent(f); + + await writeFile(compiledFilename, svelteAppData.code, 'utf8'); + + mix.js(compiledFilename, outputPath); + + this.manifest.push({ + tag: svelteAppData.tag, + filename: this.normalizePath(outputPath) + '/' + basename(compiledFilename) + }) + + this.tempJavascriptBootloaderFiles.push(compiledFilename); + } + }; + + /** + * Prepare the provided path for processing. + * + * Stolen from Laravel Mix to make sure we were compatible + * + * @param {string} filePath + */ + normalizePath(filePath) { + if ( + Mix.config.publicPath && + filePath.startsWith(Mix.config.publicPath) + ) { + filePath = filePath.substring(Mix.config.publicPath.length); + } + filePath = filePath.replace(/\\/g, '/'); + + if (!filePath.startsWith('/')) { + filePath = '/' + filePath; + } + + return filePath; + } + + /** + * Generate bootstrap JS code for Svelte Component + * + * Using WebComponents/Svelte (customElement:true) + * + * @param {string} svelteComponentPath + */ + async generateBootstrapWebComponent(svelteComponentPath) + { + let svelteCode = await readFile(svelteComponentPath).then(); + let svelteTagName = findSvelteTagName(svelteCode); + + if (!svelteTagName) { + throw '[SvelteDirect] Cannot Determine Tag Name In: ' + svelteComponentPath + } + + return { + code: 'export { default as App } from "./' + basename(svelteComponentPath) + '";', + tag: svelteTagName + }; + } + + /** + * Generate bootstrap JS code for Svelte Component + * + * Using Standard Svelte Component (customElement: false) + * + * @param {string} svelteComponentPath + */ + async generateBootstrapSvelteComponent(svelteComponentPath) + { + let svelteCode = await readFile(svelteComponentPath).then(); + let svelteProps = findSvelteProps(svelteCode); + let svelteTagName = findSvelteTagName(svelteCode); + + if (!svelteTagName) { + throw '[SvelteDirect] Cannot Determine Tag Name In: ' + svelteComponentPath + } + + return { + code: ` + + // Generated By SvelteDirect + + import component from "svelte-tag"; + import App from "./${basename(svelteComponentPath)}" + const props = JSON.parse('${JSON.stringify(svelteProps)}'); + + new component({component:App,tagname:"${svelteTagName}",attributes: props, shadow: false}) + + `, + tag: svelteTagName + }; + } +} + +mix.extend("svelteDirect", new SvelteDirect()); diff --git a/src/js/svelte-code-helper.js b/src/js/svelte-code-helper.js new file mode 100644 index 0000000..d217d51 --- /dev/null +++ b/src/js/svelte-code-helper.js @@ -0,0 +1,18 @@ +const html2 = require("htmlparser2"); + +exports.findSvelteProps = (svelteCode) => /(?<=export ).+?((?= =)|(?==)|(?=;))/g[Symbol.match](svelteCode)?.map((match) => match.replace(/let |const |var /g, '')) ?? []; +exports.findSvelteTagName = (svelteCode) => { + let tag = null; + const parser = new html2.Parser({ + onopentag(name, attributes) { + if (name.toLowerCase() === 'svelte:options') { + tag = attributes?.tag.trim() || null + } + } + }); + + parser.write(svelteCode); + parser.end(); + return tag; +}; + From 74f4517dfb67db9cdbcd5bbf0534afd39681a8cb Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Thu, 3 Jun 2021 01:38:41 -0400 Subject: [PATCH 4/9] Refactor The SveltDirectServiceProvider To Include Cleaner Functions Also added DocBlocks --- src/SvelteDirectServiceProvider.php | 89 +++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 12 deletions(-) diff --git a/src/SvelteDirectServiceProvider.php b/src/SvelteDirectServiceProvider.php index bd8bef5..b6ec4d8 100644 --- a/src/SvelteDirectServiceProvider.php +++ b/src/SvelteDirectServiceProvider.php @@ -4,24 +4,45 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Facades\App; -use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; class SvelteDirectServiceProvider extends ServiceProvider { + /** + * @var array|null + */ public ?array $manifest = []; + /** + * Main class entrypoint + */ public function boot(): void { $this->loadManifestFile(); $this->loadBladePreCompiler(); } + /** + * Provide the default path to the SvelteDirect manifest file + * + * @todo allow control via proper config file + * + * @internal + * @return string + */ public function defaultManifestPath() : string { return App::bootstrapPath('cache/svelte-direct-components.php'); } + /** + * Loads the "tag name to JavaScript file" mapping + * aka manifest file + * + * @internal + * @param string|null $manifestFilePath + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ public function loadManifestFile(?string $manifestFilePath = null) : void { $files = new Filesystem(); @@ -29,33 +50,77 @@ public function loadManifestFile(?string $manifestFilePath = null) : void $this->manifest = file_exists($manifestPath) ? $files->getRequire($manifestPath):null; } + /** + * Register our precompiler function within the Blade compiler engine + * + * @internal + */ public function loadBladePreCompiler() : void { if (! $this->manifest) { return; } - $this->app['blade.compiler']->precompiler([$this, 'findTagsInBladeTemplate']); + $this->app['blade.compiler']->precompiler([$this, 'precompiler']); } - /** @internal */ - public function findTagsInBladeTemplate(string $view) : string + + /** + * Our precompiler function that finds any Svelte component tags + * and then appends the proper call to the @stack Blade directive + * to our existing Blade template code + * + * @param string $viewTemplateCode + * @return string + */ + public function precompiler(string $viewTemplateCode) + { + $tagsToLoad = $this->findSvelteComponentTagsInBlade($viewTemplateCode); + return $viewTemplateCode . $this->appendPushDirective($tagsToLoad); + } + + + /** + * Given Blade template code, find any of our Svelte component tags + * that were used within the template + * + * @internal + * @param string $view + * @return array + */ + public function findSvelteComponentTagsInBlade(string $view) : array { $tagPattern = implode('|', array_keys($this->manifest)); $pattern = "/(?<=<)\s*{$tagPattern}/"; preg_match_all($pattern, $view, $matches); - $identifiedTags = array_intersect(array_keys($this->manifest), array_unique($matches[0])); - - $pushHtml = "@push('sveltedirect')" . PHP_EOL . - $this->generateHtml($identifiedTags) - . PHP_EOL . "@endpush"; + return array_intersect(array_keys($this->manifest), array_unique($matches[0])); + } - return $view . $pushHtml; + /** + * Create the @push directive code for the given Svelte tags + * + * @internal + * @param array $tagsToLoad + * @return string + */ + public function appendPushDirective(array $tagsToLoad) : string + { + return "@push('sveltedirect')" . PHP_EOL . + $this->generateScriptHtml($tagsToLoad) + . PHP_EOL . "@endpush"; } - /** @internal */ - public function generateHtml(array $tagsToLoad) : string + + /** + * Generate the script tag HTML to load our component JavaScript file(s) + * for a given set of tags + * + * @internal + * @param array $tagsToLoad + * @return string + */ + public function generateScriptHtml(array $tagsToLoad) : string { return array_reduce($tagsToLoad, function ($previous, $current) { return $previous . '' . PHP_EOL; From 281cda17f202acf6840bc545603139c03583dbdc Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Fri, 11 Jun 2021 21:42:17 -0400 Subject: [PATCH 5/9] Improve Regex Pattern For Tag Matching This covers more edge cases besides our standard tags. Covers the 4-5 cases in the new test. --- src/SvelteDirectServiceProvider.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SvelteDirectServiceProvider.php b/src/SvelteDirectServiceProvider.php index b6ec4d8..4e856aa 100644 --- a/src/SvelteDirectServiceProvider.php +++ b/src/SvelteDirectServiceProvider.php @@ -91,9 +91,8 @@ public function precompiler(string $viewTemplateCode) public function findSvelteComponentTagsInBlade(string $view) : array { $tagPattern = implode('|', array_keys($this->manifest)); - $pattern = "/(?<=<)\s*{$tagPattern}/"; + $pattern = "/(?<=<)\s*(?:{$tagPattern})(?=\s|>|\/)+/"; preg_match_all($pattern, $view, $matches); - return array_intersect(array_keys($this->manifest), array_unique($matches[0])); } From 9b529d0d806032115f73c3a914305d99d0b89c82 Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Fri, 11 Jun 2021 21:42:37 -0400 Subject: [PATCH 6/9] Add More Complete Test Suite --- tests/SvelteDirectTest.php | 234 +++++++++++++++++++++++++++++++++++-- 1 file changed, 224 insertions(+), 10 deletions(-) diff --git a/tests/SvelteDirectTest.php b/tests/SvelteDirectTest.php index b6d1cda..852e816 100644 --- a/tests/SvelteDirectTest.php +++ b/tests/SvelteDirectTest.php @@ -5,31 +5,245 @@ use Illuminate\Filesystem\Filesystem; use Nickpoulos\SvelteDirect\SvelteDirectServiceProvider; +/** + * Class SvelteDirectTest + * @package Nickpoulos\SvelteDirect\Tests + */ class SvelteDirectTest extends TestCase { /** * @var SvelteDirectServiceProvider */ - protected $svelteDirect; + protected SvelteDirectServiceProvider $svelteDirect; + /** + * @var Filesystem + */ + protected Filesystem $filesystem; + + /** + * Define a test manifest path + */ + public const TEST_MANIFEST_FILE_PATH = './manifest.php'; + + /** + * Define a test manifest of tags + * + * @var array|string[] + */ + protected array $testManifest = [ + 'test-tag' => '/js/TestTag.js', + 'nick-poulos' => '/js/NickPoulos.js' + ]; + + /** + * Test setup + */ public function setUp() : void { parent::setUp(); + $this->filesystem = new Filesystem(); $this->svelteDirect = new SvelteDirectServiceProvider($this->app); + $this->createTestManifestFile($this->testManifest); + } + + /** + * Tear Down/Clean Up + */ + public function tearDown() : void + { + $this->filesystem->delete(self::TEST_MANIFEST_FILE_PATH); + } + + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function testLoadManifestFile() : void + { + $this->svelteDirect->loadManifestFile(self::TEST_MANIFEST_FILE_PATH); + self::assertEquals($this->svelteDirect->manifest, $this->testManifest); + } + + + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function testGenerateScriptHtml() : void + { + $tagsToLoad = array_keys($this->testManifest); + + $expected = array_reduce($tagsToLoad, function ($previous, $current) { + return $previous . '' . PHP_EOL; + }, ''); + + $this->svelteDirect->loadManifestFile(self::TEST_MANIFEST_FILE_PATH); + + $actual = $this->svelteDirect->generateScriptHtml($tagsToLoad); + + self::assertEquals($expected, $actual); + } + + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function testAppendPushDirective() + { + $tagsToLoad = array_keys($this->testManifest); + + $scriptHtml = array_reduce($tagsToLoad, function ($previous, $current) { + return $previous . '' . PHP_EOL; + }, ''); + + $expected = "@push('sveltedirect')" . PHP_EOL . $scriptHtml . PHP_EOL . "@endpush"; + + $this->svelteDirect->loadManifestFile(self::TEST_MANIFEST_FILE_PATH); + + $actual = $this->svelteDirect->appendPushDirective($tagsToLoad); + + self::assertEquals($expected, $actual); + } + + /** + * @dataProvider bladeTemplateCodeDataProvider + */ + public function testFindSvelteComponentTagsInBlade(array $expectedResult, string $testBladeTemplateCode) + { + $this->svelteDirect->loadManifestFile(self::TEST_MANIFEST_FILE_PATH); + $actual = $this->svelteDirect->findSvelteComponentTagsInBlade($testBladeTemplateCode); + self::assertEquals($expectedResult, $actual); + } + + /** + * @return array[] + */ + public function bladeTemplateCodeDataProvider() : array + { + $expectedResultWhenFound = array_keys($this->testManifest); + $expectedResultWhenNotFound = []; + + $regularStyleTags = << + + Testing Regular Blade + + +
+ @include('some fake directive stuff') +
+ This is a regular tag test + Nothing fancy here + + + BLADE1; + + $singleClosingStyleTags = << + + Single Tag Closing Style + + +
+ @include('some fake directive stuff') +
+ + + + + BLADE2; + + $nestedRegularStyleTags = << + + Testing Nested/Slot Style Blade + + +
+ @include('some fake directive stuff') +
+ + + + + + BLADE3; + + $nestedSingleClosingStyleTags = << + + Testing Nested/Slot Style Single/Closing Only Blade + + +
+ @include('some fake directive stuff') +
+ + + + + + BLADE4; + + $brokenTagsWithCloseName = << + + Testing Broken Tag Name + + +
+ @include('some fake directive stuff') +
+ + + + + + BLADE5; + + return [ + "Regular Style Tags" => [ + $expectedResultWhenFound, + $regularStyleTags + ], + "Single Closing Style Tags" => [ + $expectedResultWhenFound, + $singleClosingStyleTags + ], + "Nested Regular Style Tags" => [ + $expectedResultWhenFound, + $nestedRegularStyleTags + ], + "Nested Single Closing Style Tags" => [ + $expectedResultWhenFound, + $nestedSingleClosingStyleTags + ], + "Broken Tag That Is Close" => [ + $expectedResultWhenNotFound, + $brokenTagsWithCloseName + ], + ]; } - public function testLoadManifestFile() + /** + * @param array $testManifest + * @return string + */ + protected function buildTestManifestCode(array $testManifest) : string { - $testManifest = ['test-tag' => '/js/TestTag.js']; - $testManifestString = " '/js/TestTag.js']; ?>"; - $testManifestPath = './manifest.php'; + $result = " '" . $jsFile . "'," . PHP_EOL; + }); - $files = new Filesystem(); + return $result . "]; ?>"; + } - $files->put($testManifestPath, $testManifestString); - $this->svelteDirect->loadManifestFile($testManifestPath); - $files->delete($testManifestPath); - self::assertEquals($this->svelteDirect->manifest, $testManifest); + /** + * @param array $testManifest + */ + protected function createTestManifestFile(array $testManifest) + { + $this->filesystem->put(self::TEST_MANIFEST_FILE_PATH, $this->buildTestManifestCode($testManifest)); } } From 099e68edaa1cfa0eabcea2b5ddb0bba2628d69b6 Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Fri, 11 Jun 2021 21:43:54 -0400 Subject: [PATCH 7/9] Update README.md - Remove references to custom blade directive (we use @stack now) - Remove references to old npm package (js is now included here) - Add new examples due to above --- README.md | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 60161bd..4bcc384 100644 --- a/README.md +++ b/README.md @@ -25,24 +25,23 @@ But I like eating my cake too, and so this little project was born. ## How? -This project consists of two pieces. +This package has two main pieces. -- Laravel Mix plugin installed via NPM - - Compiles Svelte components into bite-sized JS files - -- Blade Pre-Compiler/Directive installed via Composer - - Scans Blade templates and loads the right bite sized component JS +- A Laravel Mix plugin that compiles each of your Svelte components into their own bite-sized JS files + +- A Blade Pre-Compiler that scans Blade templates identifies your Svelte component tags, and loads the right component JS automatically + +### Install Laravel Svelte Direct -### Install Laravel Svelte Direct JavaScript ```bash -npm install laravel-svelte-direct-mix -```` +composer require nickpoulos/laravel-svelte-direct +``` ### Configure Laravel Mix webpack.mix.js ```javascript const mix = require('laravel-mix'); -require('laravel-svelte-direct-mix') +require('./vendor/nickpoulos/laravel-svelte-direct/js/mix'); mix.svelteDirect('resources/js/Components', 'public/js'); @@ -60,17 +59,9 @@ The options tag tells Svelte (and Svelte Direct), what the component's HTML tag The comment tag tells Svelte to ignore when we don't have `customElement` set to true. -### Install Laravel Svelte Direct PHP - -You can install the package via composer: - -```bash -composer require nickpoulos/laravel-svelte-direct -``` - ### Configure Blade Template -In your applications's main Blade layout/component, add the `@sveltedirect`above your ending `` tag. +In your applications's main Blade layout/component, add the `@stack('sveltedirect')'`above your ending `` tag. Feel free to add your Svelte component anywhere inside the Blade HTML. You will notice the tag we use in the HTML below matches the `` tag attribute above. @@ -97,7 +88,7 @@ example.blade.php -@sveltedirect +@stack('sveltedirect') From 44ad3b0dfa7edcf22a01fe7aeea1dc2afdd48853 Mon Sep 17 00:00:00 2001 From: Nick Poulos Date: Fri, 11 Jun 2021 21:44:02 -0400 Subject: [PATCH 8/9] Update CHANGELOG.md --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a170051..965ec41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to `laravel-svelte-direct` will be documented in this file. +## 0.1.0 - 2021-06-11 + +- Refactor the generated bootstrap JavaScript to use the `svelte-tag` package under the hood + +- Replace custom @sveltedirect Blade directive with Laravel's built-in @stack('sveltedirect') + +- Migrate Laravel Svelte Direct Mix from its own package into this one + +- Improve Regex for tag matching + +- Refactor the main ServiceProvider to have cleaner functions + +- Added several tests for the rest of the ServiceProvider functions + ## 0.0.1b - 2021-05-24 - Hotfix to add default values for class vars, was causing errors in some cases From d7f68ba6342aacad7247ecb755c1235e18be86b3 Mon Sep 17 00:00:00 2001 From: nickpoulos Date: Sat, 12 Jun 2021 01:44:27 +0000 Subject: [PATCH 9/9] Fix styling --- src/SvelteDirectServiceProvider.php | 2 ++ tests/SvelteDirectTest.php | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/SvelteDirectServiceProvider.php b/src/SvelteDirectServiceProvider.php index 4e856aa..d93e6ba 100644 --- a/src/SvelteDirectServiceProvider.php +++ b/src/SvelteDirectServiceProvider.php @@ -76,6 +76,7 @@ public function loadBladePreCompiler() : void public function precompiler(string $viewTemplateCode) { $tagsToLoad = $this->findSvelteComponentTagsInBlade($viewTemplateCode); + return $viewTemplateCode . $this->appendPushDirective($tagsToLoad); } @@ -93,6 +94,7 @@ public function findSvelteComponentTagsInBlade(string $view) : array $tagPattern = implode('|', array_keys($this->manifest)); $pattern = "/(?<=<)\s*(?:{$tagPattern})(?=\s|>|\/)+/"; preg_match_all($pattern, $view, $matches); + return array_intersect(array_keys($this->manifest), array_unique($matches[0])); } diff --git a/tests/SvelteDirectTest.php b/tests/SvelteDirectTest.php index 852e816..b117b51 100644 --- a/tests/SvelteDirectTest.php +++ b/tests/SvelteDirectTest.php @@ -33,7 +33,7 @@ class SvelteDirectTest extends TestCase */ protected array $testManifest = [ 'test-tag' => '/js/TestTag.js', - 'nick-poulos' => '/js/NickPoulos.js' + 'nick-poulos' => '/js/NickPoulos.js', ]; /** @@ -203,23 +203,23 @@ public function bladeTemplateCodeDataProvider() : array return [ "Regular Style Tags" => [ $expectedResultWhenFound, - $regularStyleTags + $regularStyleTags, ], "Single Closing Style Tags" => [ $expectedResultWhenFound, - $singleClosingStyleTags + $singleClosingStyleTags, ], "Nested Regular Style Tags" => [ $expectedResultWhenFound, - $nestedRegularStyleTags + $nestedRegularStyleTags, ], "Nested Single Closing Style Tags" => [ $expectedResultWhenFound, - $nestedSingleClosingStyleTags + $nestedSingleClosingStyleTags, ], "Broken Tag That Is Close" => [ $expectedResultWhenNotFound, - $brokenTagsWithCloseName + $brokenTagsWithCloseName, ], ]; } @@ -232,7 +232,7 @@ protected function buildTestManifestCode(array $testManifest) : string { $result = " '" . $jsFile . "'," . PHP_EOL; });