loader.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. 'use strict';
  2. const fs = require('fs');
  3. const vueTemplateCompiler = require('vue-template-compiler');
  4. require('upath');
  5. require('globby');
  6. require('scule');
  7. async function extractTags(resourcePath) {
  8. const tags = new Set();
  9. const file = (await fs.readFileSync(resourcePath)).toString("utf8");
  10. const component = vueTemplateCompiler.parseComponent(file);
  11. if (component.template) {
  12. if (component.template.lang === "pug") {
  13. try {
  14. const pug = require("pug");
  15. component.template.content = pug.render(component.template.content, { filename: resourcePath });
  16. } catch (err) {
  17. }
  18. }
  19. vueTemplateCompiler.compile(component.template.content, {
  20. modules: [{
  21. postTransformNode: (el) => {
  22. tags.add(el.tag);
  23. }
  24. }]
  25. });
  26. }
  27. return [...tags];
  28. }
  29. function matcher(tags, components) {
  30. return tags.reduce((matches, tag) => {
  31. const match = components.find(({ pascalName, kebabName }) => [pascalName, kebabName].includes(tag));
  32. match && matches.push(match);
  33. return matches;
  34. }, []);
  35. }
  36. function install(content, components) {
  37. const imports = "{" + components.map((c) => `${c.pascalName}: ${c.isAsync ? c.asyncImport : c.import}`).join(",") + "}";
  38. let newContent = "/* nuxt-component-imports */\n";
  39. newContent += `installComponents(component, ${imports})
  40. `;
  41. const hotReload = content.indexOf("/* hot reload */");
  42. if (hotReload > -1) {
  43. content = content.slice(0, hotReload) + newContent + "\n\n" + content.slice(hotReload);
  44. } else {
  45. content += "\n\n" + newContent;
  46. }
  47. return content;
  48. }
  49. async function loader(content) {
  50. this.async();
  51. this.cacheable();
  52. if (!this.resourceQuery) {
  53. this.addDependency(this.resourcePath);
  54. const { getComponents } = this.query;
  55. const nonAsyncComponents = getComponents().filter((c) => c.isAsync !== true);
  56. const tags = await extractTags(this.resourcePath);
  57. const matchedComponents = matcher(tags, nonAsyncComponents);
  58. if (matchedComponents.length) {
  59. content = install.call(this, content, matchedComponents);
  60. }
  61. }
  62. this.callback(null, content);
  63. }
  64. module.exports = loader;