diff --git a/packages/vite-plugin-shopify-modules/README.md b/packages/vite-plugin-shopify-modules/README.md index cea8469b..1da786d8 100644 --- a/packages/vite-plugin-shopify-modules/README.md +++ b/packages/vite-plugin-shopify-modules/README.md @@ -111,10 +111,6 @@ See the [vite-plugin-shopify docs](https://github.com/barrel/barrel-shopify/tree See [seed-theme](https://github.com/barrel/barrel-shopify/tree/main/themes/seed-theme) for an example Shopify theme using this plugin. -## To-Do - -- [ ] Unit tests - ## Bugs Please create an issue if you found any bugs, to help us improve this project! diff --git a/packages/vite-plugin-shopify-modules/package.json b/packages/vite-plugin-shopify-modules/package.json index fd247d81..64dd5429 100644 --- a/packages/vite-plugin-shopify-modules/package.json +++ b/packages/vite-plugin-shopify-modules/package.json @@ -35,8 +35,7 @@ "dependencies": { "chokidar": "^3.5.3", "debug": "^4.3.4", - "fast-glob": "^3.2.11", - "lodash": "^4.17.21" + "fast-glob": "^3.2.11" }, "devDependencies": { "tsconfig": "workspace:*", diff --git a/packages/vite-plugin-shopify-modules/src/index.ts b/packages/vite-plugin-shopify-modules/src/index.ts index 93f2e474..a110ba34 100644 --- a/packages/vite-plugin-shopify-modules/src/index.ts +++ b/packages/vite-plugin-shopify-modules/src/index.ts @@ -1,28 +1,16 @@ -import { promises as fs, existsSync } from 'fs' +import { lstatSync, renameSync, unlinkSync, symlinkSync, existsSync, statSync } from 'fs' import path from 'path' -import { Plugin, ResolvedConfig } from 'vite' -import { throttle } from 'lodash' +import { Plugin, normalizePath } from 'vite' import chokidar from 'chokidar' import glob from 'fast-glob' import createDebugger from 'debug' -import { VitePluginShopifyModulesOptions, ResolvedVitePluginShopifyModulesOptions, resolveOptions } from './options' +import { VitePluginShopifyModulesOptions, resolveOptions } from './options' const debug = createDebugger('vite-plugin-shopify:modules') export default function shopifyModules (options: VitePluginShopifyModulesOptions = {}): Plugin { const resolvedOptions = resolveOptions(options) - let _config: ResolvedConfig - - // Create throttled function for generating module symlinks - const linkModulesFn = throttle( - linkModules.bind(null, resolvedOptions), - 500, - { - leading: true, - trailing: false - } - ) return { name: 'vite-plugin-shopify-modules', @@ -37,14 +25,11 @@ export default function shopifyModules (options: VitePluginShopifyModulesOptions } } }, - configResolved (config) { - _config = config - }, resolveId: async (id) => { // Check if path is within modules directory if (!path.relative(path.resolve(resolvedOptions.modulesDir), id).includes('..')) { try { - const fileStat = await fs.stat(id) + const fileStat = statSync(id) // Check if path refers to folder instead of file if (fileStat.isDirectory()) { @@ -66,63 +51,63 @@ export default function shopifyModules (options: VitePluginShopifyModulesOptions } return null }, - buildStart: () => { - // Link modules on build start - linkModulesFn() - - if (_config.command === 'serve') { - // Watch for relevant file or directory changes to re-run script - chokidar.watch([resolvedOptions.modulesDir, '(sections|snippets)/*.liquid'], { - ignoreInitial: true, - followSymlinks: false - }).on('all', linkModulesFn) - } + buildEnd: async () => { + const modulePaths = await glob(`${normalizePath(resolvedOptions.modulesDir)}/**/*.liquid`) + + // Link modules on build end + modulePaths.forEach(modulePath => linkModule(modulePath, resolvedOptions)) + }, + configureServer () { + const watcher = chokidar.watch([`${resolvedOptions.modulesDir}/**/*.liquid`], { + ignoreInitial: true, + followSymlinks: false + }) + + // Watch for relevant file or directory changes to re-run script + watcher.on('add', path => linkModule(path, resolvedOptions)) + watcher.on('change', path => linkModule(path, resolvedOptions)) + watcher.on('unlink', path => linkModule(path, resolvedOptions)) } } } // Check for module folders with corresponding liquid files and set up symlinks as needed -const linkModules = ({ modulesDir, themeRoot }: ResolvedVitePluginShopifyModulesOptions): void => { +const linkModule = (modulePath: string, { modulesDir, themeRoot }: Required): void => { + const themeFilePath = getThemeFilePath(modulePath, { modulesDir, themeRoot }) + setupSymlink(modulePath, themeFilePath) +} + +const getThemeFilePath = (modulePath: string, { modulesDir, themeRoot }: Required): string => { const rootPath = path.resolve(themeRoot) const sectionsDir = path.resolve(rootPath, './sections') const snippetsDir = path.resolve(rootPath, './snippets') + const fileName = path.basename(modulePath) - if (existsSync(modulesDir)) { - fs.readdir(modulesDir) - .then( - async (modules: string[]) => await Promise.all(modules.flatMap((module) => [ - setupSectionSymlink(module, { modulesDir, sectionsDir }), - setupSnippetSymlink(module, { modulesDir, snippetsDir }) - ])), - (err) => { throw err } - ) + if (/\.section.liquid/.test(fileName)) { + const moduleName = fileName.replace(/\.section/, '') + return path.join(sectionsDir, `${moduleName}`) } -} -// Set up symlink for module's liquid section file -const setupSectionSymlink = async (moduleName: string, pathConfig: { modulesDir: string, sectionsDir: string }): Promise => { - const moduleSectionPath = path.join(pathConfig.modulesDir, `${moduleName}/${moduleName}.section.liquid`) - const themeSectionPath = path.join(pathConfig.sectionsDir, `${moduleName}.liquid`) - - return await setupSymlink(moduleSectionPath, themeSectionPath) -} - -// Set up symlink for module's liquid snippet file -const setupSnippetSymlink = async (moduleName: string, pathConfig: { modulesDir: string, snippetsDir: string }): Promise => { - const moduleSnippetPath = path.join(pathConfig.modulesDir, `${moduleName}/${moduleName}.snippet.liquid`) - const themeSnippetPath = path.join(pathConfig.snippetsDir, `${moduleName}.liquid`) - - return await setupSymlink(moduleSnippetPath, themeSnippetPath) + const moduleName = fileName.replace(/\.snippet/, '') + return path.join(snippetsDir, `${moduleName}`) } // Move liquid file from module path to theme path and generate symbolic link -const setupSymlink = async (modulePath: string, themePath: string): Promise => { +const setupSymlink = (modulePath: string, themePath: string): void => { + const moduleDir = path.basename(path.dirname(modulePath)) let modulePathStats + const fileName = path.basename(modulePath) + const regex = new RegExp(moduleDir) + const isPotentialModuleName = regex.test(fileName) - debug({ modulePath, themePath }) + debug({ modulePath, themePath, moduleDir, fileName }) + + if (!isPotentialModuleName) { + return + } try { - modulePathStats = await fs.lstat(modulePath) + modulePathStats = lstatSync(modulePath) } catch (e) { // } @@ -135,8 +120,8 @@ const setupSymlink = async (modulePath: string, themePath: string): Promise ({ +): Required => ({ modulesDir: typeof options.modulesDir !== 'undefined' ? path.normalize(options.modulesDir) : 'modules', themeRoot: typeof options.themeRoot !== 'undefined' ? path.normalize(options.themeRoot) : './' }) diff --git a/packages/vite-plugin-shopify-modules/test/__fixtures__/modules/collage/foo.snippet.liquid b/packages/vite-plugin-shopify-modules/test/__fixtures__/modules/collage/foo.snippet.liquid new file mode 100644 index 00000000..e69de29b diff --git a/packages/vite-plugin-shopify-modules/test/index.test.ts b/packages/vite-plugin-shopify-modules/test/index.test.ts index 61ef1aea..4b111b44 100644 --- a/packages/vite-plugin-shopify-modules/test/index.test.ts +++ b/packages/vite-plugin-shopify-modules/test/index.test.ts @@ -33,6 +33,7 @@ describe('vite-plugin-shopify:modules', () => { expect(existsSync(path.join(__dirname, '__fixtures__', 'snippets', 'multirow.liquid'))).toEqual(true) expect(existsSync(path.join(__dirname, '__fixtures__', 'sections', 'multirow.liquid'))).toEqual(true) + expect(existsSync(path.join(__dirname, '__fixtures__', 'sections', 'foo.liquid'))).toEqual(false) expect(lstatSync(path.join(__dirname, '__fixtures__', 'modules', 'multirow', 'multirow.section.liquid')).isSymbolicLink()).toEqual(true) expect(lstatSync(path.join(__dirname, '__fixtures__', 'modules', 'multirow', 'multirow.snippet.liquid')).isSymbolicLink()).toEqual(true) expect(lstatSync(path.join(__dirname, '__fixtures__', 'modules', 'collage', 'collage.section.liquid')).isSymbolicLink()).toEqual(true) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 65e471fb..19dcfc57 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,7 +81,6 @@ importers: chokidar: ^3.5.3 debug: ^4.3.4 fast-glob: ^3.2.11 - lodash: ^4.17.21 tsconfig: workspace:* vite: ^4.0.4 vitest: ^0.25.7 @@ -89,7 +88,6 @@ importers: chokidar: 3.5.3 debug: 4.3.4 fast-glob: 3.2.11 - lodash: 4.17.21 vite: 4.0.4 devDependencies: tsconfig: link:../tsconfig