diff --git a/404.html b/404.html index ec6815ec3..adbdcd5a2 100644 --- a/404.html +++ b/404.html @@ -8,11 +8,11 @@ - - - + + + -
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

\ No newline at end of file diff --git a/assets/css/styles.a7c2456e.css b/assets/css/styles.71429604.css similarity index 91% rename from assets/css/styles.a7c2456e.css rename to assets/css/styles.71429604.css index f493c0b50..ee787255d 100644 --- a/assets/css/styles.a7c2456e.css +++ b/assets/css/styles.71429604.css @@ -1 +1 @@ -@import url(https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown.css);@import url(https://rsms.me/inter/inter.css);.col,.container{padding:0 var(--ifm-spacing-horizontal)}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,.tab_J4Y8{-webkit-user-select:none}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}html[data-theme=dark],html[data-theme=light]{--ifm-menu-color-active:var(--ifm-color-primary-text);--admonition-note-c-color:#ff9ff3;--admonition-code-note-c-bg:#ff9ff350}.theme-admonition,:root{--ifm-alert-color:var(--ifm-font-color-base)}.theme-admonition-note,.theme-admonition-warning{--admonition-bar-c-bg:var(--admonition-bar-note-c-bg);--admonition-link-c:var(--admonition-link-note-c)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50,.from-transparent{--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.bg-fuchsia-600,.bg-gray-100,.bg-gray-500,.bg-neutral-100,.bg-zinc-950{--tw-bg-opacity:1}.toggleButton_IoGO,html{-webkit-tap-highlight-color:transparent}.dark,:root{--dm-mask-bg-color:#656c85cc;--dm-highlight-color:var(--dm-color-brand)}*,.DocSearch-Container,.DocSearch-Container *,.tab_J4Y8{box-sizing:border-box}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--doc-sidebar-width:17.5rem;--dropdown-icon-width:0.625rem;--dropdown-icon-height:0.375rem;--dropdown-icon-gap:0.688rem;--ifm-menu-link-padding-vertical:0.5rem;--sidebar-spacing-horizontal:1.5rem;--ifm-menu-color-background-hover:#0000}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_h4wM{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.items-center,.menuExternalLink_UU74,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width);width:100%}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size);inherit:unset}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList_DbQE{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration);color:#c44cac}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_tb_L .wordWrapButtonIcon_M_ov{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.admonitionHeading_rz2u code,.btn_bvfa{text-transform:none}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover,.enter-to[data-v-3926b6c7],.hash-link:focus,.leave-from[data-v-3926b6c7],:hover>.hash-link{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button,.flex-grow{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_dqoy:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;pointer-events:none;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;transform:translateY(-50%);top:4px}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}:root,[data-theme=dark]{--ifm-footer-background-color:#181818}.footer__links,.mb-4{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color)}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_bY4Y article>:first-child,.docItemContainer_bY4Y header+*,.footer__item{margin-top:0}.admonitionContent_hXXP>:last-child,.collapsibleContent_SYrp p:last-child,.details_Erfu>summary>p:last-child,.footer__items,.tabItem_iV9q>:last-child{margin-bottom:0}[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_Dxmf{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_Erfu[data-collapsed=false].isBrowser_bjSw>summary:before,.details_Erfu[open]:not(.isBrowser_bjSw)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;top:0;bottom:0;visibility:hidden;left:0}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.after\:blur-\[var\(--after-blur\)\]:after,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.flex,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_DkJa,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.h-full,.navbar__logo img,body,html{height:100%}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}#nprogress,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}:root,[data-theme=dark],html[data-theme=light]{--ifm-menu-color-background-active:#ff9ff330}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.DocSearch-Button,.DocSearch-Link,.DocSearch-Prefill,.DocSearch-Reset,.cursor-pointer,.dropdownNavbarItemMobile_viHK,.hover\:cursor-pointer:hover,.pills__item,.tab_J4Y8,.tabs__item{cursor:pointer}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.overflow-x-auto,.tabs{overflow-x:auto}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover,.shadow-\[inset_0_-8px_10px_\#8fdfff1f\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.group:hover .group-hover\:translate-x-0\.5,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.inline-flex,.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_DV6A>li)>.containsTaskList_DV6A{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.transition,.transition-all,.transition-shadow,.transition-transform{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--sidebar-category-c:var(--c-gray-0);--sidebar-border-c:var(--c-gray-90);--ifm-menu-color:var(--c-gray-20);--note-color:#e3e3e3;--admonition-tip-border:var(--c-green-50);--admonition-tip-color:var(--c-green-50);--admonition-note-c-bg:#0000;--admonition-info-c-bg:#0000;--admonition-tip-c-bg:#0000;--admonition-warning-c-bg:#0000;--admonition-caution-c-bg:#0000;--admonition-danger-c-bg:#0000;--admonition-info-c-color:var(--c-blue-50);--admonition-tip-c-color:var(--c-green-50);--admonition-warning-c-color:var(--c-yellow-50);--admonition-caution-c-color:var(--c-orange-50);--admonition-danger-c-color:var(--c-red-50);--ifm-alert-tip-background-color:var(--c-green-50-a);--admonition-code-warning-c-bg:var(--c-yellow-50-a);--admonition-code-info-c-bg:#00163d;--admonition-code-tip-c-bg:#003d11;--admonition-code-caution-c-bg:#3d1200;--admonition-code-danger-c-bg:#3d0003;--ifm-alert-warning-background-color:var(--c-yellow-30-a);--c-brand:#ff73ec90;--c-yellow-50:#f9d76f;--c-yellow-50-a:#ffd75a60;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.302);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}html[data-theme=light]{--sidebar-category-c:var(--c-gray-100);--sidebar-border-c:var(--c-gray-0);--ifm-menu-color:var(--c-indigo-80);--note-color:#241800;--admonition-note-c-bg:linear-gradient(to bottom,var(--ifm-alert-note-background-color),#0000 40%);--admonition-info-c-bg:linear-gradient(to bottom,var(--ifm-alert-info-background-color),#0000 40%);--admonition-tip-c-bg:linear-gradient(to bottom,var(--ifm-alert-tip-background-color),#0000 40%);--admonition-warning-c-bg:linear-gradient(to bottom,var(--ifm-alert-warning-background-color),#0000 40%);--admonition-caution-c-bg:linear-gradient(to bottom,var(--ifm-alert-caution-background-color),#0000 40%);--admonition-danger-c-bg:linear-gradient(to bottom,var(--ifm-alert-danger-background-color),#0000 40%);--admonition-info-c-color:inherit;--admonition-tip-c-color:inherit;--admonition-warning-c-color:inherit;--admonition-caution-c-color:inherit;--admonition-danger-c-color:inherit;--admonition-code-info-c-bg:var(--c-teal-20);--admonition-code-warning-c-bg:var(--c-yellow-20);--admonition-code-tip-c-bg:var(--c-green-20);--admonition-code-caution-c-bg:var(--c-orange-20);--admonition-code-danger-c-bg:var(--c-red-10);--admonition-tip-border:var(--c-green-100);--admonition-tip-color:var(--c-green-100);--ifm-alert-warning-background-color:var(--c-yellow-10);--ifm-alert-tip-background-color:var(--c-green-10);--ifm-alert-danger-background-color:var(--c-red-10);--ifm-alert-note-background-color:#ff9ff360;--ifm-alert-info-background-color:var(--c-teal-10);--ifm-alert-caution-background-color:var(--c-green-10)}[class^=docRoot_]{width:1440px!important}.links_A3uT,.sp-link_GRPb,[class^=docsWrapper_]{display:flex;justify-content:center}#__docusaurus .theme-doc-sidebar-container{background:var(--token-primary-bg-c);border-inline-end:1px solid var(--sidebar-border-c);bottom:0;height:calc(100vh - 60px);margin-block-start:0;position:sticky;top:60px;will-change:auto}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a{align-items:center;display:flex;height:var(--ifm-navbar-height)}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a,#__docusaurus [class^=sidebar_]{padding-inline-end:var(--sidebar-spacing-horizontal);padding-inline-start:var(--sidebar-spacing-horizontal)}#__docusaurus [class^=sidebar_]{max-height:100vh;overflow-y:auto;padding-block-start:1rem;position:static}#__docusaurus [class^=sidebar_]>.menu{overflow-x:initial;padding-block-end:2rem;padding:0}#__docusaurus [class^=sidebarLogo]{display:none!important}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list,.codeBlockStandalone_VnB1,.p-0{padding:0}#__docusaurus .menu__list{transition:height .35s cubic-bezier(.36,.66,.04,1) 25ms!important;will-change:auto!important}#__docusaurus .menu__list .menu__list .menu__link--sublist{margin-inline-start:calc((var(--dropdown-icon-width) + var(--dropdown-icon-gap))*-1)}#__docusaurus .menu__list .menu__list .menu__link--sublist:after,.header-github-link:hover{opacity:.6}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1{padding-inline-start:calc(var(--dropdown-icon-width))}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1>.menu__link{color:var(--sidebar-category-c);font-size:14px;font-weight:500}#__docusaurus .menu__list-item:not(:first-child){margin-block-start:0}#__docusaurus .menu__list-item .menu__list .menu__link{padding-inline-start:calc(var(--dropdown-icon-width) + var(--dropdown-icon-gap));padding:7px 10px}#__docusaurus .menu__list-item-collapsible,.block{display:block}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list>.menu__list-item:last-of-type{padding-block-end:.5rem}#__docusaurus .theme-doc-sidebar-item-category-level-1:last-of-type{margin-block-end:.5rem}#__docusaurus .menu__link{align-items:center;display:flex;font-size:.85rem;font-weight:500;letter-spacing:-.01em;line-height:16px;transition:opacity .2s ease-out}#__docusaurus .menu__link:not(.menu__link--active:not(.menu__link--sublist)){background:initial}#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):active,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):focus,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):hover{opacity:.7}#__docusaurus .menu__link--sublist{align-items:center;display:flex;flex-direction:row-reverse;justify-content:flex-end;margin-block-end:0;padding-inline-end:0;padding-inline-start:0}#__docusaurus .menu__link--sublist:after{background:var(--ifm-menu-link-sublist-icon) center/var(--dropdown-icon-width) var(--dropdown-icon-height);background-repeat:no-repeat;height:var(--dropdown-icon-height);margin-block-end:0;margin-inline-end:var(--dropdown-icon-gap);margin-inline-start:unset;min-width:auto;width:var(--dropdown-icon-width)}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list-item-collapsible .menu__link{color:var(--sidebar-category-c);font-size:.938rem;font-weight:600;line-height:100%}html[data-theme=light] body{--angle:220deg;background-attachment:fixed;background-image:linear-gradient(var(--angle),#fff 15%,rgba(255,159,243,.376) 20%,#fff 25%,#f4eef8 30%,#fff 35%,#f8edf5 40%,#fff 60%);background-size:cover}.theme-admonition{border:none;position:relative;--ifm-alert-padding-horizontal:2rem;--ifm-alert-padding-vertical:1.5rem}.theme-admonition [class^=admonitionHeading_]{font-size:1rem;line-height:1.6;text-transform:capitalize}.theme-admonition [class^=admonitionHeading_] [class^=admonitionIcon_]{display:none}.theme-admonition [class^=admonitionContent_] p a{color:var(--admonition-link-c);text-decoration:underline}.theme-admonition [class^=admonitionContent_] p code{background:var(--admonition-code-c-bg)}.theme-admonition-warning{--admonition-code-c-bg:var(--admonition-code-warning-c-bg);background:#0000;border:2px solid var(--c-yellow-90-a);color:var(--c-yellow-90)}.theme-admonition-note{--admonition-code-c-bg:var(--admonition-code-note-c-bg);background:#0000;border:2px solid var(--c-brand-a);color:var(--c-brand)}.theme-admonition-info{--ifm-alert-background-color:var(--c-teal-210);--admonition-bar-c-bg:var(--admonition-bar-info-c-bg);--admonition-code-c-bg:var(--admonition-code-info-c-bg);--admonition-link-c:var(--admonition-link-info-c);background:#0000;border:2px solid var(--c-teal-60);color:var(--c-teal-90)}.theme-admonition-tip{--admonition-bar-c-bg:var(--admonition-bar-tip-c-bg);--admonition-code-c-bg:var(--admonition-code-tip-c-bg);--admonition-link-c:var(--admonition-link-tip-c);background:#0000;border:2px solid var(--admonition-tip-border);color:var(--admonition-tip-color)}.theme-admonition-caution{--ifm-alert-background-color:var(--admonition-caution-c-bg);--admonition-bar-c-bg:var(--admonition-bar-caution-c-bg);--admonition-code-c-bg:var(--admonition-code-caution-c-bg);--admonition-link-c:var(--admonition-link-caution-c);background:#0000}.theme-admonition-danger,.theme-admonition-important{--admonition-bar-c-bg:var(--admonition-bar-danger-c-bg);--admonition-code-c-bg:var(--admonition-code-danger-c-bg);--admonition-link-c:var(--admonition-link-danger-c)}.theme-admonition-danger{--ifm-alert-background-color:var(--admonition-danger-c-bg);background:#0000;border:2px solid var(--c-red-50-a);color:var(--c-red-50)}.theme-admonition-important{--ifm-alert-background-color:var(--c-lavender-210);background:linear-gradient(to bottom,var(--ifm-alert-background-color),#0000);border:2px solid var(--c-lavender-220)}:root{--admonition-bar-note-c-bg:var(--c-yellow-80);--admonition-bar-info-c-bg:var(--c-blue-80);--admonition-bar-tip-c-bg:var(--c-green-80);--admonition-bar-caution-c-bg:var(--c-orange-80);--admonition-bar-danger-c-bg:var(--c-red-60);--admonition-link-note-c:var(--c-brand);--admonition-link-info-c:var(--c-teal-90);--admonition-link-tip-c:var(--c-green-60);--admonition-color-tip-c:var(--note-color);--admonition-color-note-c:var(--note-color);--admonition-link-caution-c:var(--c-orange-90);--admonition-link-danger-c:var(--c-red-60);--c-black:#000;--c-white:#fff;--c-blue-0:#f0f6ff;--c-blue-10:#e3edff;--c-blue-20:#cddfff;--c-blue-30:#b2ceff;--c-blue-40:#97bdff;--c-blue-50:#7cabff;--c-blue-60:#639bff;--c-blue-70:#4d8dff;--c-blue-80:#3880ff;--c-blue-90:#176bff;--c-blue-100:#0054e9;--c-blue-110:#004dd6;--c-blue-120:#0046c1;--c-blue-130:#003fae;--c-blue-140:#00389b;--c-blue-150:#002d7c;--c-blue-160:#002669;--c-blue-170:#001d52;--c-blue-180:#001740;--c-blue-190:#00112f;--c-blue-200:#000b1f;--c-gray-0:#f3f3f3;--c-gray-10:#e4e4e4;--c-gray-20:#c8c8c8;--c-gray-30:#aeaeae;--c-gray-40:#959595;--c-gray-50:#818181;--c-gray-60:#6d6d6d;--c-gray-70:#5f5f5f;--c-gray-80:#474747;--c-gray-90:#2f2f2f;--c-gray-100:#141414;--c-carbon-0:#eef1f3;--c-carbon-10:#d7dde2;--c-carbon-20:#b4bcc6;--c-carbon-30:#98a2ad;--c-carbon-40:#7d8894;--c-carbon-50:#677483;--c-carbon-60:#556170;--c-carbon-70:#434f5e;--c-carbon-80:#35404e;--c-carbon-90:#222d3a;--c-carbon-100:#03060b;--c-indigo-0:#fbfbfd;--c-indigo-10:#f6f8fc;--c-indigo-20:#e9edf3;--c-indigo-30:#dee3ea;--c-indigo-40:#ced6e0;--c-indigo-50:#b2becd;--c-indigo-60:#92a0b3;--c-indigo-70:#73849a;--c-indigo-80:#445b78;--c-indigo-90:#2d4665;--c-indigo-100:#001a3a;--c-green-0:#f1fdf5;--c-green-10:#deffe7;--c-green-20:#c7fbd5;--c-green-30:#a7f1bb;--c-green-40:#80e89d;--c-green-50:#62e085;--c-green-50-a:#62e08560;--c-green-60:#4ada71;--c-green-70:#2dd55b;--c-green-80:#17c948;--c-green-90:#00ba33;--c-green-100:#00a52d;--c-green-110:#009b2b;--c-green-120:#009128;--c-green-130:#008725;--c-green-140:#007d22;--c-green-150:#00711f;--c-green-160:#00661c;--c-green-170:#00581a;--c-green-180:#004314;--c-green-190:#002f0e;--c-green-200:#001807;--c-lime-0:#f5fff0;--c-lime-10:#ebfee3;--c-lime-20:#ddfcd0;--c-lime-30:#cffbbc;--c-lime-40:#bbf9a2;--c-lime-50:#a3f581;--c-lime-60:#8bf35f;--c-lime-70:#64ec44;--c-lime-80:#4ddf2b;--c-lime-90:#3ad515;--c-lime-100:#27c100;--c-lime-110:#25b400;--c-lime-120:#22a400;--c-lime-130:#1e9200;--c-lime-140:#1a7e00;--c-lime-150:#176d00;--c-lime-160:#135a00;--c-lime-170:#0f4900;--c-lime-180:#0c3900;--c-lime-190:#092c00;--c-lime-200:#061d00;--c-lavender-0:#f7f8ff;--c-lavender-10:#e6ebff;--c-lavender-20:#ced9ff;--c-lavender-30:#b6c6ff;--c-lavender-40:#9fb5ff;--c-lavender-50:#8aa4ff;--c-lavender-60:#7493ff;--c-lavender-70:#597eff;--c-lavender-80:#3c67ff;--c-lavender-90:#194bfd;--c-lavender-100:#0033e8;--c-lavender-110:#002dcc;--c-lavender-120:#0028b8;--c-lavender-130:#0023a2;--c-lavender-140:#002092;--c-lavender-150:#001a79;--c-lavender-160:#001560;--c-lavender-170:#00114e;--c-lavender-180:#000e41;--c-lavender-190:#000a30;--c-lavender-200:#000721;--c-lavender-210:#8aa4ff50;--c-lavender-220:#7493ff40;--c-purple-0:#f4f4ff;--c-purple-10:#e9eaff;--c-purple-20:#d0d2ff;--c-purple-30:#b6b9f9;--c-purple-40:#9a99fc;--c-purple-50:#8482fb;--c-purple-60:#786df9;--c-purple-70:#6e5afd;--c-purple-80:#6030ff;--c-purple-90:#4712fb;--c-purple-100:#3400e6;--c-purple-110:#3000d1;--c-purple-120:#2b00bc;--c-purple-130:#2600a6;--c-purple-140:#20008e;--c-purple-150:#1b0075;--c-purple-160:#15005c;--c-purple-170:#100048;--c-purple-180:#0d0038;--c-purple-190:#0b0030;--c-purple-200:#080022;--c-brand:#8f1a7f;--c-brand-a:#8f1a7f60;--c-pink-0:#ffeff5;--c-pink-10:#ffe3ed;--c-pink-20:#ffd8e5;--c-pink-30:#ffc9db;--c-pink-40:#ffb6d0;--c-pink-50:#ff99bd;--c-pink-60:#ff80ac;--c-pink-70:#ff6098;--c-pink-80:#fb4082;--c-pink-90:#ec216a;--c-pink-100:#da0d56;--c-pink-110:#d0004a;--c-pink-120:#c40046;--c-pink-130:#b30040;--c-pink-140:#a3003b;--c-pink-150:#940035;--c-pink-160:#850030;--c-pink-170:#710029;--c-pink-180:#5f0022;--c-pink-190:#460019;--c-pink-200:#20000b;--c-red-0:#fff1f3;--c-red-10:#ffe6e8;--c-red-20:#ffcfd3;--c-red-30:#feb7bc;--c-red-40:#fc9aa2;--c-red-50:#f9838c;--c-red-50-a:#f9838c60;--c-red-60:#f56570;--c-red-70:#f24c58;--c-red-80:#ef3442;--c-red-90:#e21827;--c-red-100:#d0000f;--c-red-110:#c5000f;--c-red-120:#b3000e;--c-red-130:#9c000c;--c-red-140:#89000b;--c-red-150:#760009;--c-red-160:#650008;--c-red-170:#520006;--c-red-180:#410005;--c-red-190:#300004;--c-red-200:#1d0002;--c-red-210:#f24c5830;--c-red-220:#ef344215;--c-orange-0:#fff5f0;--c-orange-10:#ffede6;--c-orange-20:#ffdfd1;--c-orange-30:#ffd0bc;--c-orange-40:#ffc0a5;--c-orange-50:#ffaf8c;--c-orange-60:#ff9b70;--c-orange-70:#ff8753;--c-orange-80:#ff7336;--c-orange-90:#ff5b13;--c-orange-100:#eb4700;--c-orange-110:#d94200;--c-orange-120:#c93d00;--c-orange-130:#b63700;--c-orange-140:#a53200;--c-orange-150:#8c2a00;--c-orange-160:#772400;--c-orange-170:#5e1c00;--c-orange-180:#481600;--c-orange-190:#341000;--c-orange-200:#1d0900;--c-yellow-0:#fffbef;--c-yellow-10:#fff8e2;--c-yellow-20:#fff4d1;--c-yellow-30:#ffefbd;--c-yellow-30-a:#fcd28550;--c-yellow-40:#ffe9a3;--c-yellow-50:#ffcb2d;--c-yellow-50-a:#ffd75a60;--c-yellow-60:#ffd75a;--c-yellow-60-a:#ffd75a30;--c-yellow-70:#ffce31;--c-yellow-80:#ffc409;--c-yellow-90:#f4b100;--c-yellow-90-a:#f4b10060;--c-yellow-100:#eaa100;--c-yellow-110:#dd9800;--c-yellow-120:#cc8d00;--c-yellow-130:#be8300;--c-yellow-140:#b17a00;--c-yellow-150:#9c6c00;--c-yellow-160:#8a6000;--c-yellow-170:#755100;--c-yellow-180:#5f4100;--c-yellow-190:#452f00;--c-yellow-200:#231800;--c-yellow-210:#ffc40950;--c-yellow-220:#ffce3140;--c-aqua-0:#f0fff9;--c-aqua-10:#e6fff6;--c-aqua-20:#ceffed;--c-aqua-30:#b7fce3;--c-aqua-40:#93f9d5;--c-aqua-50:#79f5c9;--c-aqua-60:#59f0ba;--c-aqua-70:#38e9aa;--c-aqua-80:#1ae19a;--c-aqua-90:#00d287;--c-aqua-100:#00ba78;--c-aqua-110:#00aa6d;--c-aqua-120:#009b63;--c-aqua-130:#00915c;--c-aqua-140:#008152;--c-aqua-150:#016e46;--c-aqua-160:#015d3c;--c-aqua-170:#014f32;--c-aqua-180:#013e28;--c-aqua-190:#012e1e;--c-aqua-200:#011e13;--c-teal-0:#eefeff;--c-teal-10:#dffdff;--c-teal-20:#d0fdff;--c-teal-30:#bbfcff;--c-teal-40:#a2fcff;--c-teal-50:#8bfbff;--c-teal-60:#73f6fb;--c-teal-60-a:#73f6fb60;--c-teal-70:#55ecf2;--c-teal-80:#35e2e9;--c-teal-90:#1bd2d9;--c-teal-100:#00b9c0;--c-teal-110:#01adb4;--c-teal-120:#019fa5;--c-teal-130:#018f94;--c-teal-210:#3dc1d340;--c-teal-220:#3dc1d325;--c-teal-140:#017e83;--c-teal-150:#016d71;--c-teal-160:#015d61;--c-teal-170:#014d4f;--c-teal-180:#013c3e;--c-teal-190:#012c2e;--c-teal-200:#011c1d;--c-cyan-0:#f3faff;--c-cyan-10:#e8f5ff;--c-cyan-20:#d3ecff;--c-cyan-30:#bfe4ff;--c-cyan-40:#a7daff;--c-cyan-50:#8dcfff;--c-cyan-60:#77c6ff;--c-cyan-70:#62bdff;--c-cyan-80:#46b1ff;--c-cyan-90:#24a3ff;--c-cyan-100:#0091fa;--c-cyan-110:#0189ec;--c-cyan-120:#017ed8;--c-cyan-130:#0170c0;--c-cyan-140:#0163aa;--c-cyan-150:#015592;--c-cyan-160:#01487b;--c-cyan-170:#013a64;--c-cyan-180:#012d4d;--c-cyan-190:#011e33;--c-cyan-200:#01121e;--sans-serif:-apple-system,BlinkMacSystemFont,san-francisco,Avenir Next,Segoe UI,Roboto,Noto Sans,Helvetica Neue;--serif:Iowan Old Style,Apple Garamond,Baskerville,Times New Roman;--monospaced:Menlo;--border:#03a9f4;--g1:#0003;--g2:#8f1a7f33;--g3:#1f1f1f33;--ifm-color-primary:#8f1a7f;--ifm-color-primary-dark:#6f1a5f;--ifm-color-primary-text:#6f1a5f;--ifm-color-primary-darker:#5f1a4f;--ifm-color-primary-darkest:#4f1a3f;--ifm-color-primary-light:#9f1a8f;--ifm-color-primary-lighter:#af1a9f;--ifm-color-primary-lightest:#bf1aaf;--ifm-code-font-size:95%;--ifm-border-color:#0000000d;--ifm-background:#00000003;--ifm-announcementBar-height:40px;--ifm-primary-hue-saturation:308 78%;--ifm-primary-hue-saturation-light:308 78%;--accent:113,26,95;--accent-background-card-gradient:linear-gradient(45deg,rgb(var(--accent)),#fda7df 10%,var(--ifm-f-white) 40%);--ifm-f-white:#fff;--ifm-f-re-white:#181818;--ifm-f-white-soft:#f8f8f8;--ifm-f-white-mute:#f2f2f2;--ifm-f-bg-soft:#f6f6f7;--farm--border:rgba(86,86,86,.125);--docsearch-searchbox-background:#8f1a7fb3;--max-layout-width:1680px;--ifm-navbar-link-hover-color:initial;--ifm-navbar-padding-vertical:0;--ifm-navbar-item-padding-vertical:0;--ifm-font-family-base:-apple-system,BlinkMacSystemFont,Inter,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI emoji";--ifm-font-family-monospace:"SFMono-Regular","Roboto Mono",Consolas,"Liberation Mono",Menlo,Courier,monospace;--ifm-menu-link-sublist-icon:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSI2IiBmaWxsPSJub25lIj48cGF0aCBzdHJva2U9IiMwMzA2MEIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjUiIGQ9Ik05IDUgNSAxIDEgNSIvPjwvc3ZnPg==");--z-sidebar:2000;--z-backdrop:1100;--ifm-menu-color-background:#ff9ff310;--docusaurus-highlighted-code-line-bg:#ff9ff310;--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base);--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--dm-color-brand:#3451b2;--dm-color-bg-alt:#f6f6f7;--dm-color-hint:#3c3c43c7;--dm-button-font-size:13px;--dm-button-height:40px;--dm-c-white:#fff;--dm-text-color:#374151;--dm-modal-bg-color:var(--dm-c-white);--dm-divider-color:#f3f4f6;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.container,.w-full{width:100%}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.absolute{position:absolute}.chat-container[data-v-3926b6c7],.relative{position:relative}.inset-0{inset:0}.z-10{z-index:10}.m-auto{margin:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-10{margin-bottom:2.5rem;margin-top:2.5rem}.my-14{margin-bottom:3.5rem;margin-top:3.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-8{margin-bottom:2rem;margin-top:2rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.mt-10{margin-top:2.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.loader_qPMq,.mt-8{margin-top:2rem}.inline,.tags_HSrq{display:inline}.grid{display:grid}.size-3{height:.75rem;width:.75rem}.size-4{height:1rem;width:1rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.documate-button .icon[data-v-956ba6e9],.h-4{height:1rem}.h-52{height:13rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.min-h-\[2rem\]{min-height:2rem}.min-h-\[inherit\]{min-height:inherit}.w-16{width:4rem}.w-20{width:5rem}.w-36{width:9rem}.w-40{width:10rem}.w-6{width:1.5rem}.w-9\/12{width:75%}.w-\[1px\]{width:1px}.max-w-7xl{max-width:80rem}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}@keyframes a{0%,90%,to{background-position:calc(-100% - var(--shimmer-width)) 0}30%,60%{background-position:calc(100% + var(--shimmer-width)) 0}}.animate-shimmer{animation:8s infinite a}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center,.mdxPageWrapper_uWPR{justify-content:center}.justify-between{justify-content:space-between}.gap-10{gap:2.5rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-5{column-gap:1.25rem}.gap-y-12{row-gap:3rem}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.self-start{align-self:flex-start}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[var\(--border-radius\)\]{border-radius:var(--border-radius)}.rounded-\[var\(--card-content-radius\)\]{border-radius:var(--card-content-radius)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-black\/5{border-color:#0000000d}.bg-fuchsia-600{background-color:rgb(192 38 211/var(--tw-bg-opacity))}.bg-gray-100{background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-500{background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-neutral-100{background-color:rgb(245 245 245/var(--tw-bg-opacity))}.bg-white\/40{background-color:#fff6}.bg-zinc-950{background-color:rgb(9 9 11/var(--tw-bg-opacity))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-\[\#ffaa40\]{--tw-gradient-from:#ffaa40 var(--tw-gradient-from-position)}.from-\[\#ffaa40\]\/50{--tw-gradient-from:#ffaa4080 var(--tw-gradient-from-position)}.from-transparent{--tw-gradient-from:#0000 var(--tw-gradient-from-position);--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.via-\[\#9c40ff\],.via-\[\#9c40ff\]\/50{--tw-gradient-to:#9c40ff00 var(--tw-gradient-to-position)}.via-\[\#9c40ff\]{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-\[\#9c40ff\]\/50{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff80 var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-black\/80{--tw-gradient-to:#0000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#000c var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-50\%{--tw-gradient-via-position:50%}.to-\[\#ffaa40\]{--tw-gradient-to:#ffaa40 var(--tw-gradient-to-position)}.to-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4080 var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.bg-\[length\:var\(--bg-size\)_100\%\]{background-size:var(--bg-size) 100%}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.p-2{padding:.5rem}.p-6{padding:1.5rem}.p-\[1px\]{padding:1px}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.text-left{text-align:left}.data_ODnV,.kbd-text[data-v-3926b6c7],.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.tracking-wide{letter-spacing:.025em}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-neutral-600\/50{color:#52525280}.text-transparent{color:#0000}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow-\[inset_0_-8px_10px_\#8fdfff1f\]{--tw-shadow:inset 0 -8px 10px #8fdfff1f;--tw-shadow-colored:inset 0 -8px 10px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter}.transition-all{transition-property:all}.transition-shadow{transition-property:box-shadow}.transition-transform{transition-property:transform}.duration-200{transition-duration:.2s}.duration-300,.hover\:duration-300:hover{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--bg-size\:300\%\]{--bg-size:300%}.\[background-position\:0_0\]{background-position:0 0}.\[background-size\:var\(--shimmer-width\)_100\%\]{background-size:var(--shimmer-width) 100%}.\[border-radius\:inherit\]{border-radius:inherit}.\!\[mask-composite\:subtract\]{-webkit-mask-composite:source-out!important;mask-composite:subtract!important}.\[mask\:linear-gradient\(\#fff_0_0\)_content-box\2c linear-gradient\(\#fff_0_0\)\]{-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0)}[data-theme=dark]{--ifm-f-bg-soft:#252529;--ifm-background-color:#000!important;--ifm-color-primary:#fff;--ifm-color-primary-text:#fff;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--ifm-menu-color-background:#ff9ff340;--ifm-background:#0000004d;--ifm-f-white:#c74040;--ifm-f-re-white:#fff;--ifm-f-white-soft:#222;--ifm-f-white-mute:#282828;--farm--border:#fafafa20;--docusaurus-highlighted-code-line-bg:#8f1a7fb3;--docsearch-primary-color:var(--ifm-color-primary-dark)!important;--docsearch-searchbox-background:#3a3a3a!important}.navbar__title{color:#6f1a5f;font-size:1.5em}.navbar__title:hover{color:#bf1aaf}.header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat;content:"";display:flex;height:20px;width:20px}[data-theme=dark] .header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.bg{background-color:var(--ifm-f-white-soft)}.bg-re{background-color:var(--ifm-f-re-white)}.color{color:var(--ifm-f-white)}.token.color{color:#c44cac}.color-re{color:var(--ifm-f-re-white)}.theme-back-to-top-button{height:50px!important;width:50px!important}[class^=backToTopButton_]:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:3rem 3rem!important;-webkit-mask-size:3rem 3rem!important}.clean-btn:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:1.5rem 1.5rem!important;-webkit-mask-size:1.5rem 1.5rem!important}div[class^=announcementBar_]{--site-announcement-bar-stripe-color1:hsl(var(--ifm-primary-hue-saturation) 85%);--site-announcement-bar-stripe-color2:hsl(var(--ifm-primary-hue-saturation) 95%);background:linear-gradient(45deg,#711a5f,#c44cac 30%,#9f1a8f 60%,#fda7df 80%);color:var(--c-white);font-weight:700;height:var(--ifm-announcementBar-height)}footer[class=footer]{background-color:var(--ifm-f-white-soft)!important}.footer__link-item{gap:6px;line-height:3}.DocSearch-Button-Container,.footer__link-item,.navbar__link{align-items:center;display:flex}.code-block-highlight-line{background-color:var(--docusaurus-highlighted-code-line-bg);border-left:5px solid #c44cac;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.DocSearch-Button{border-radius:8px!important;width:250px}.theme-admonition-warning{color:var(--c-yellow-120)}.theme-admonition-danger{color:var(--c-red-60)}.theme-doc-version-badge{margin:10px 0}.navbar--fixed-top{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background:#0000;box-shadow:0 4px 10px #00000014}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}figure{margin:12px}.after\:absolute:after,.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:left-0:before{content:var(--tw-content);left:0}.before\:right-0:before{content:var(--tw-content);right:0}.before\:top-\[-var\(--border-size\)\]:before{content:var(--tw-content);top:-var(--border-size)}.after\:-z-10:after,.before\:z-\[-10\]:before{content:var(--tw-content);z-index:-10}.after\:block:after,.before\:block:before{content:var(--tw-content);display:block}.after\:h-\[var\(--pseudo-element-height\)\]:after,.before\:h-\[var\(--pseudo-element-height\)\]:before{content:var(--tw-content);height:var(--pseudo-element-height)}.before\:w-full:before{content:var(--tw-content);width:100%}.after\:animate-backgroundPositionSpin:after,.before\:animate-backgroundPositionSpin:before{animation:3s infinite alternate b;content:var(--tw-content)}.before\:bg-\[var\(--pseudo-element-background-image\)\]:before{background-color:var(--pseudo-element-background-image);content:var(--tw-content)}.before\:bg-\[length\:200\%_100\%\]:before{background-size:200% 100%;content:var(--tw-content)}.after\:content-\[\'\'\]:after,.before\:content-\[\'\'\]:before{--tw-content:"";content:var(--tw-content)}.after\:-left-\[var\(--border-size\)\]:after{content:var(--tw-content);left:calc(var(--border-size)*-1)}.after\:-top-\[var\(--border-size\)\]:after{content:var(--tw-content);top:calc(var(--border-size)*-1)}.after\:w-\[var\(--pseudo-element-width\)\]:after{content:var(--tw-content);width:var(--pseudo-element-width)}@keyframes b{0%{background-position:top;content:var(--tw-content)}to{background-position:bottom;content:var(--tw-content)}}.after\:rounded-\[var\(--border-radius\)\]:after{border-radius:var(--border-radius);content:var(--tw-content)}.after\:bg-\[linear-gradient\(0deg\2c var\(--neon-first-color\)\2c var\(--neon-second-color\)\2c var\(--neon-third-color\)\)\]:after{background-image:linear-gradient(0deg,var(--neon-first-color),var(--neon-second-color),var(--neon-third-color));content:var(--tw-content)}.after\:bg-\[length\:100\%_200\%\]:after{background-size:100% 200%;content:var(--tw-content)}.after\:opacity-80:after{content:var(--tw-content);opacity:.8}.after\:blur-\[var\(--after-blur\)\]:after{content:var(--tw-content);--tw-blur:blur(var(--after-blur))}.hover\:bg-neutral-200:hover{--tw-bg-opacity:1;background-color:rgb(229 229 229/var(--tw-bg-opacity))}.hover\:text-neutral-600:hover{--tw-text-opacity:1;color:rgb(82 82 82/var(--tw-text-opacity))}.focus\:text-opacity-80:focus,.hover\:text-opacity-80:hover{--tw-text-opacity:0.8}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover{--tw-shadow:inset 0 -5px 10px #8fdfff3f;--tw-shadow-colored:inset 0 -5px 10px var(--tw-shadow-color)}.group:hover .group-hover\:translate-x-0\.5{--tw-translate-x:0.125rem}.container__nVC{border-radius:6px;contain:content}}.tab-list_aJ1t{display:flex;min-width:100%;overflow-x:scroll;padding:4px 0 8px 8px}.tab_J4Y8{border-bottom:2px solid #0000;margin-bottom:-1px;margin-right:10px;padding:6px 12px;transition:.2s ease-in-out;user-select:none}.tab_J4Y8:last-child{margin-right:0}.selected_erAK{border-color:currentColor}.no-scrollbar_vtMC::-webkit-scrollbar{display:none}.no-scrollbar_vtMC{-ms-overflow-style:none;scrollbar-width:none}.backToTopButton_CW5h{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_CW5h:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_pJBw{opacity:1;transform:scale(1);visibility:visible}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;color:var(--docsearch-muted-color);display:flex;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch-Button-Key--pressed{box-shadow:var(--docsearch-key-pressed-shadow);transform:translate3d(0,1px,0)}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a,.sidebarItemLink_tcbF:hover{text-decoration:none}.DocSearch-Hit[aria-selected=true] mark,.content__jQl a{text-decoration:underline}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset,p[data-v-3926b6c7],ul[data-v-3926b6c7]{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards c;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.sidebar_HzcY,.tableOfContents_HR7E{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}#__docusaurus-base-url-issue-banner-container,.button-placeholder[data-v-3926b6c7],.docSidebarContainer_ZZsd,.loading.hide[data-v-3926b6c7],.navbarSearchContainer_ND2d:empty,.sidebarLogo_vqPK,.themedComponent_kF_f,[data-theme=dark] .lightToggleIcon__XKe,[data-theme=light] .darkToggleIcon_fMED,html[data-announcement-bar-initially-dismissed=true] .announcementBar_egfn,svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon,.tocCollapsibleContent_KIE9 a{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands li,.DocSearch-Commands-Key,.buttons_AeoN{align-items:center;display:flex}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@keyframes c{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container,.skipToContent_izU8{z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_izU8{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem}.skipToContent_izU8:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_rNcS{line-height:0;padding:0}.content__jQl{font-size:85%;padding:5px 0;text-align:center}.content__jQl a{color:inherit}.announcementBar_egfn{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_OBFz{flex:0 0 10px}.announcementBarClose_EolD{align-self:stretch;flex:0 0 30px}.toggle_pkrm{height:2rem;width:2rem}.toggleButton_IoGO{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_IoGO:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_zO9u{cursor:not-allowed}.darkNavbarColorModeToggle_p1rI:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_ucyz,[data-theme=light] .themedComponent--light_WVpI,html:not([data-theme]) .themedComponent--light_WVpI{display:initial}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_L0Og{display:none;margin:0}.iconExternalLink_GQRh{margin-left:.3rem}.docMainContainer_LfAu,.docRoot_CVEc{display:flex;width:100%}.docsWrapper_V_L6{display:flex;flex:1 0 auto}.iconLanguage_VYTf{margin-right:5px;vertical-align:text-bottom}.dark{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-divider-color:#2e2e32}.sp_EK1s .sp-link_GRPb.link_ib43:focus,.sp_EK1s .sp-link_GRPb.link_ib43:hover,body:not(.navigation-with-keyboard) :not(input):focus,input[data-v-3926b6c7],input[data-v-3926b6c7]:focus{outline:0}.enter[data-v-3926b6c7]{transition:opacity .2s ease-out}.enter-from[data-v-3926b6c7],.leave-to[data-v-3926b6c7]{opacity:0}.leave[data-v-3926b6c7]{transition:opacity .1s ease-in}.transition-child-ref[data-v-3926b6c7]{bottom:0;left:0;position:fixed;right:0;top:0;transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dialog[data-v-3926b6c7]{background-color:var(--dm-mask-bg-color);bottom:0;left:0;overflow-y:auto;position:fixed;right:0;top:0;z-index:999999}.dialog-container[data-v-3926b6c7]{padding:1rem}.dialog-panel[data-v-3926b6c7]{background-color:var(--dm-modal-bg-color);border-radius:.75rem;box-shadow:0 25px 50px -12px #00000040;margin:0 auto;max-width:36rem;overflow:hidden;transition-duration:.3s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.magnifying-glass-icon[data-v-3926b6c7]{color:var(--dm-text-color);height:1.25rem;left:1rem;pointer-events:none;position:absolute;top:.875rem;width:1.25rem}.chat-input[data-v-3926b6c7]{background-color:initial;border-width:0;border-bottom:1px solid var(--dm-divider-color);box-sizing:border-box;color:var(--dm-text-color);height:3rem;padding-left:2.75rem;padding-right:1rem;width:100%}.chat-input[data-v-3926b6c7]::placeholder{font-size:1rem}.combobox-options[data-v-3926b6c7]{list-style:none;max-height:20rem;min-height:5rem;overflow-y:auto;padding:1rem;scroll-padding-bottom:.5rem;scroll-padding-top:2.5rem}.combobox-option[data-v-3926b6c7]{cursor:pointer;display:flex;padding:.5rem 1rem;-webkit-user-select:none;user-select:none}.combobox-options-container[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;margin-left:-1rem;margin-right:-1rem;margin-top:.5rem}.active[data-v-3926b6c7]{background-color:var(--dm-highlight-color);color:var(--dm-c-white)}.combobox-options-name[data-v-3926b6c7]{flex:1 1 auto;margin-left:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.loading[data-v-3926b6c7]{align-items:center;display:flex;justify-content:left;padding:1rem 1rem 1rem 2.6rem}.loading-spin[data-v-3926b6c7]{animation:1s linear infinite d;height:1.5rem;margin-right:.5rem;width:1.5rem}.option-icon[data-v-3926b6c7]{flex:none;height:1.5rem;width:1.5rem}.question-anwser-section[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;list-style:none;max-height:20rem;scroll-padding-bottom:.5rem;scroll-padding-top:.5rem}.question-anwser-item[data-v-3926b6c7]{padding-bottom:.875rem;padding-top:.875rem}.question-role-user[data-v-3926b6c7]{display:flex;gap:1.2rem}.question-role-icon[data-v-3926b6c7]{display:inline-block;flex:none;height:1.5rem;width:1.5rem}.documate-logo[data-v-3926b6c7]{height:1.4rem;width:1.4rem}.result-not-found[data-v-3926b6c7]{padding:3.5rem 1.5rem;text-align:center}.result-not-found-text[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.85rem;margin-top:.5rem}.anwser-content[data-v-3926b6c7]{display:flex;gap:1.5rem}.markdown-body[data-v-3926b6c7]{border-width:0;color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;list-style:auto;overflow-wrap:break-word}.footer[data-v-3926b6c7]{align-content:center;align-items:center;border-top:1px solid var(--dm-divider-color);color:var(--dm-text-color);display:flex;flex-wrap:wrap;font-size:.75rem;justify-content:space-between;line-height:1rem;padding:.625rem 1rem}.kbd-wrap[data-v-3926b6c7]{align-content:center;display:flex;justify-content:center}.kbd-text[data-v-3926b6c7],.kbd[data-v-3926b6c7]{align-items:center;display:flex;justify-content:center}.kbd[data-v-3926b6c7]{border-radius:.25rem;border-width:1px;font-weight:600;height:1.25rem;margin-left:.25rem;margin-right:.25rem;width:1.25rem}.esc[data-v-3926b6c7]{width:2rem}.powered-by[data-v-3926b6c7]{align-items:center;color:var(--dm-text-color);display:flex;gap:.25rem;justify-content:center;text-decoration:none}@keyframes d{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.dark .hljs{background:#0d1117;color:#c9d1d9}.dark .hljs-doctag,.dark .hljs-keyword,.dark .hljs-meta .hljs-keyword,.dark .hljs-template-tag,.dark .hljs-template-variable,.dark .hljs-type,.dark .hljs-variable.language_{color:#ff7b72}.dark .hljs-title,.dark .hljs-title.class_,.dark .hljs-title.class_.inherited__,.dark .hljs-title.function_{color:#d2a8ff}.dark .hljs-attr,.dark .hljs-attribute,.dark .hljs-literal,.dark .hljs-meta,.dark .hljs-number,.dark .hljs-operator,.dark .hljs-selector-attr,.dark .hljs-selector-class,.dark .hljs-selector-id,.dark .hljs-variable{color:#79c0ff}.dark .hljs-meta .hljs-string,.dark .hljs-regexp,.dark .hljs-string{color:#a5d6ff}.dark .hljs-built_in,.dark .hljs-symbol{color:#ffa657}.dark .hljs-code,.dark .hljs-comment,.dark .hljs-formula{color:#8b949e}.dark .hljs-name,.dark .hljs-quote,.dark .hljs-selector-pseudo,.dark .hljs-selector-tag{color:#7ee787}.dark .hljs-subst{color:#c9d1d9}.dark .hljs-section{color:#1f6feb;font-weight:700}.dark .hljs-bullet{color:#f2cc60}.dark .hljs-emphasis{color:#c9d1d9;font-style:italic}.dark .hljs-strong{color:#c9d1d9;font-weight:700}.dark .hljs-addition{background-color:#033a16;color:#aff5b4}.dark .hljs-deletion{background-color:#67060c;color:#ffdcd7}.documate-button[data-v-956ba6e9]{align-items:center;cursor:pointer;display:flex;height:var(--dm-button-height);justify-content:flex-start;padding-left:.75rem;padding-right:.75rem;transition:border-color .25s ease-in-out}.navbarHideable_zRUE{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_sWQh{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_P1by{color:red;white-space:pre-wrap}.errorBoundaryFallback_jSVL{color:red;padding:.55rem}.anchorWithStickyNavbar__Jjv{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_KMPm{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_GSFM{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.searchQueryInput_QXFO,.searchVersionInput_Blrj{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_QXFO:focus,.searchVersionInput_Blrj:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_QXFO::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_Ts2M{font-size:.9rem;font-weight:700}.algoliaLogo_Kh6k{max-width:150px}.algoliaLogoPathFill_pnph{fill:var(--ifm-font-color-base)}.searchResultItem_lZq0{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_mfOK{font-weight:400;margin-bottom:0}.searchResultItemPath_HKdS{color:var(--ifm-color-content-secondary);font-size:.8rem;--ifm-breadcrumb-separator-size-multiplier:1}.searchResultItemSummary_lVXw{font-style:italic;margin:.5rem 0 0}.loadingSpinner_gx04{animation:1s linear infinite e;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes e{to{transform:rotate(1turn)}}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}.card-container_mQSC:after,.card_L8bV{background:var(--ifm-f-white-soft);border-radius:10px;box-shadow:0 1px 4px #00000029;width:100%;transition:background-position .35s}.features_t9lD{align-items:center;display:flex;padding:2rem 0;width:100%}.item_fAv5{margin:0 auto;width:100%}.card_L8bV{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;padding:2rem .5rem 0;position:relative;z-index:2}.backgroundImage_M6A8{background:linear-gradient(-45deg,#e67ac6 50%,#47caff 0);border-radius:50%;filter:blur(36px)}.card-container_mQSC{cursor:pointer;justify-content:center;position:relative}.card-container_mQSC:hover:before{animation:16s linear infinite f;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;border-radius:10px;content:"";filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;position:absolute;top:-2px;transition:opacity .3s ease-in-out;width:calc(100% + 4px);z-index:-1000}.card-container_mQSC:after{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;content:"";height:100%;left:0;position:absolute;top:0;z-index:100}.card-container-content_HPWq{position:relative;transition:background-position .35s;z-index:1000}@keyframes f{0%,to{background-position:0 0}50%{background-position:400% 0}}.progress-bar-container_Btve{border:1px solid var(--farm--border);border-radius:4px;box-sizing:initial;height:25px;padding:4px;width:50vw}.progress-bar-inner-container_RjNy{background:#9f1a8f;border-radius:2px;height:25px}.progress-bar_MQ9H{background:linear-gradient(90deg,#c026d3,#d2269e);border-radius:2px;height:100%}.font-mono_qmiE{font-family:Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace}}.main_Gz2F{border:2px solid #272727;border-radius:5px;cursor:pointer;height:50px;overflow:hidden;position:relative;width:200px}.container_GXFn,.layer,canvas{height:100%}.fill_bMTX{background:#ff69b4}.content__pcr,.fill_bMTX{height:100%;left:0;position:absolute;top:0;width:100%}.content__pcr{color:#272727}.container_GXFn,.content__pcr{align-items:center;display:flex;justify-content:center}.tabs_FETH{align-items:center;display:flex;flex-direction:column;justify-content:center;width:100%}canvas{margin:0;padding:0;width:100%}.layer{bottom:0;left:0;width:100%}.layer,span.header{pointer-events:none;position:absolute}span.header{display:inline-block;font-size:9em;font-weight:700;left:50px;line-height:.9em;top:350px;transform:translate3d(0,-50%,0);width:500px}.heroBanner_qdFl{overflow:hidden;padding:3rem 0;position:relative;text-align:center}.banner_IlVB,.banner_d9gt{background:linear-gradient(45deg,#711a5f,#fda7df 70%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:#0000;color:#0000}.farmButton2_X03M,.farmButton_siNL{color:#fff;height:50px;outline:0;z-index:0;cursor:pointer}.btn_bvfa{border-radius:8px;border-width:2px;font-family:Open Sans;font-size:1rem;font-style:normal;font-weight:600;line-height:1.5rem;min-width:130px;padding:12px 20px}.farmButton_siNL{background:#111;border:none;border-radius:10px;position:relative}.farmButton_siNL:before{animation:120s linear infinite g;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .5s ease-in-out;width:calc(100% + 4px)}.farmButton2_X03M:after,.farmButton2_X03M:before,.farmButton_siNL:after,.farmButton_siNL:before{border-radius:10px;content:"";position:absolute;z-index:-1}.farmButton2_X03M:after,.farmButton_siNL:after{background:#111;height:100%;left:0;top:0;width:100%}.fKVWgc_SGll{inset:0;-webkit-mask-image:linear-gradient(#000,#0000);mask-image:linear-gradient(#000,#0000);position:absolute}.farmButton2_X03M{background:#171717;border:none;border-radius:10px;position:relative}.farmButton2_X03M:before{animation:100s linear infinite g;background:linear-gradient(45deg,#ffaa40,#9f1a8f,#ffaa40,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .2s ease-in-out;width:calc(100% + 4px)}@keyframes g{0%,to{background-position:0 0}30%{background-position:400% 0}}.gradientText_nNG0{background:linear-gradient(to bottom right,#000,gray 40%,#fff);-webkit-background-clip:text;color:#0000}.sidebar_HzcY{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.card-main_mTfv,.teamMembersItem_XVAE{height:100%;overflow:hidden;width:100%}.sidebarItemTitle_xInU{font-size:var(--ifm-h3-font-size);font-weight:var(--ifm-font-weight-bold)}.container_Bf5U,.sidebarItemList_T4cF{font-size:.9rem}.sidebarItem_vQne{margin-top:.7rem}.sidebarItemLink_tcbF{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_Tnzw{color:var(--ifm-color-primary)!important}.authorCol_Pb4k{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_yfhS{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_ejJf{margin-left:.3rem;margin-right:.3rem}.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(130px,1fr))}.container_hhjZ{display:grid;gap:40px;margin:0 auto;width:100%}.card-main_mTfv{align-items:center;display:flex;justify-content:center}.card_sVd9{border-radius:8px;transition:box-shadow .5s;will-change:transform}.teamMembersItem_XVAE{border-radius:12px;display:flex;flex-direction:column;gap:2px}.teamMembersItem_XVAE .profile_WQFr{padding:10px}.teamMembersItem_XVAE .avatar_B5t7{cursor:pointer;height:64px;transition:.2s ease-in-out;width:64px}.teamMembersItem_XVAE .name_LD5w{font-size:16px;line-height:24px}.teamMembersItem_XVAE .org_o4tg{font-size:14px;line-height:24px}.teamMembersItem_XVAE .affiliation_rzqG{font-size:14px;line-height:20px;padding-top:4px}.teamMembersItem_XVAE .desc_pfHu{font-size:14px;line-height:20px;padding-top:12px}.teamMembersItem_XVAE .links_A3uT{margin:0 -16px -20px;padding:10px 0 0}.profile_WQFr{align-items:center;display:flex;flex-direction:column;flex-grow:1;gap:20px}.avatar_B5t7{border-radius:50%;flex-shrink:0;margin:0 auto;position:relative}.avatar-img_PAbF{border-radius:50%;bottom:0;left:0;object-fit:cover;position:absolute;right:0;top:0}.name_LD5w{font-weight:600;margin:0}.affiliation_rzqG{font-weight:500;margin:0}.org_o4tg.link_ib43{transition:color .25s}.desc_pfHu{margin:0 auto}.desc_pfHu :deep(a){font-weight:500;text-decoration-style:dotted;transition:color .25s}.links_A3uT{height:56px}.sp-link_GRPb{align-items:center;background-color:var(--ifm-f-white);font-size:14px;font-weight:500;padding:16px;text-align:center;transition:color .25s,background-color .25s}.buttonGroup_EH9s button,.codeBlockContainer_hacD{background:var(--prism-background-color);color:var(--prism-color)}.sp-icon_KrGn{height:16px;margin-right:8px;width:16px;fill:currentColor}.codeBlockContainer_hacD{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_dlr7{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_G6ED{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_MgM5{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_G6ED+.codeBlockContent_dlr7 .codeBlock_MgM5{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_wRYc{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_AT7_{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup_EH9s{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup_EH9s button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup_EH9s button:focus-visible,.buttonGroup_EH9s button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup_EH9s button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_JL7T{counter-increment:a;display:table-row}.codeLineNumber_dqoy{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_dqoy:before{content:counter(a);opacity:.4}.codeLineContent_nqyk{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_WZ8_{opacity:1!important}.copyButtonIcons_fpP_{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_LywX,.copyButtonSuccessIcon_W0Bz{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_W0Bz{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_WZ8_ .copyButtonIcon_LywX{opacity:0;transform:scale(.33)}.copyButtonCopied_WZ8_ .copyButtonSuccessIcon_W0Bz{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_M_ov{height:1.2rem;width:1.2rem}.tag_eQYG{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_eQYG:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_hEyF{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_Mx1W{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_Mx1W:after,.tagWithCount_Mx1W:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_Mx1W:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_Mx1W:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_Mx1W span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_qQMi{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit_KbD1{margin-right:.3em;vertical-align:sub}.details_Erfu{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_Erfu>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_Erfu>summary::-webkit-details-marker{display:none}.details_Erfu>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_SYrp{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.lastUpdated_Eyme{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_z9HT{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_z9HT:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_h18n:after,.tocCollapsibleExpanded_HXYb{transform:none}.tocCollapsible_cvpH{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_KIE9>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_KIE9 ul li{margin:.4rem .8rem}.details_XeDr{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_DV6A{list-style:none}.img_c7M8{height:auto}.tableOfContents_HR7E{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.admonition_lXA4{margin-bottom:1em}.admonitionHeading_rz2u{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);text-transform:uppercase}.admonitionHeading_rz2u:not(:last-child){margin-bottom:.3rem}.admonitionIcon_GXmn{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_GXmn svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.breadcrumbHomeIcon_hi01{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_YqSF{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:375px){.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}}@media (min-width:640px){.container{max-width:640px}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:block{display:block}.sm\:w-40{width:10rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-6{padding-bottom:1.5rem;padding-top:1.5rem}.sm\:pr-4{padding-right:1rem}.sm\:pt-12{padding-top:3rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}.sm\:text-base{font-size:1rem;line-height:1.5rem}.dialog-container[data-v-3926b6c7]{padding:1.5rem}.chat-input[data-v-3926b6c7]{font-size:.875rem;line-height:1.25rem}.result-not-found[data-v-3926b6c7]{padding-left:3.5rem;padding-right:3.5rem}.kbd[data-v-3926b6c7]{margin-left:.5rem;margin-right:.5rem}}@media (min-width:768px){.container{max-width:768px}.md\:order-1{order:1}.md\:order-2{order:2}.md\:col-span-1{grid-column:span 1/span 1}.md\:mt-0{margin-top:0}.button-placeholder[data-v-3926b6c7],.md\:block{display:block}.md\:w-auto{width:auto}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:gap-x-12{column-gap:3rem}.dialog-container[data-v-3926b6c7]{padding:5rem}.documate-button[data-v-956ba6e9]{background:var(--dm-color-bg-alt);border:1px solid #0000;border-radius:.5rem;color:var(--dm-color-hint);font-size:var(--dm-button-font-size);margin-left:2rem}.documate-button .icon[data-v-956ba6e9]{height:var(--dm-button-font-size);margin-right:.2rem}.documate-button[data-v-956ba6e9]:hover{border-color:var(--dm-color-brand)}}@media (min-width:997px){.collapseSidebarButton_L0Og,.expandButton_oNFi{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_EolD,.announcementBarPlaceholder_OBFz{flex-basis:50px}.collapseSidebarButton_L0Og{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_zsCQ{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_WIom,[dir=rtl] .collapseSidebarButtonIcon_zsCQ{transform:rotate(0)}.collapseSidebarButton_L0Og:focus,.collapseSidebarButton_L0Og:hover,.expandButton_oNFi:focus,.expandButton_oNFi:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_iYT8{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_RjaT{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_RjaT{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_qXbw{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_ypQ8{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_fhRN{padding-top:0}.sidebarHidden_g0iV{opacity:0;visibility:hidden}.sidebarLogo_vqPK{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_vqPK img{height:2rem;margin-right:.5rem}.expandButton_oNFi{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_WIom{transform:rotate(180deg)}.docSidebarContainer_ZZsd{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_KBRw{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_OKtC{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_LfAu{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_ZXcV{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_upd9{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.navbarSearchContainer_ND2d{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_Eyme{text-align:right}.tocMobile_CgoI{display:none}.docItemCol_yjpU{max-width:75%!important}}@media (min-width:1024px){.container{max-width:1024px}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:row-start-2{grid-row-start:2}.lg\:h-auto{height:auto}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:justify-end{justify-content:flex-end}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-8{padding-bottom:2rem;padding-top:2rem}.lg\:pt-20{padding-top:5rem}.lg\:text-6xl{font-size:3.75rem;line-height:1}.lg\:text-base{font-size:1rem;line-height:1.5rem}.lg\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (min-width:1536px){.container{max-width:1536px}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_Mvik,.footer__link-separator,.navbar__item,.sidebar_HzcY,.tableOfContents_HR7E{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_ND2d{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_E09O{padding:0 .3rem}}@media only screen and (max-width:996px){.searchQueryColumn_a_BC,.searchResultsColumn_Ts2M{max-width:60%!important}.searchLogoColumn_c1ea,.searchVersionColumn_y88e{max-width:40%!important}.searchLogoColumn_c1ea{padding-left:0!important}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:768px){div[class^=announcementBar_]{height:calc(var(--ifm-announcementBar-height) + 12px)}.navbar__items .documate-button,.navbar__link{display:none!important}.dialog-panel[data-v-3926b6c7]{margin-top:2rem}.powered-by[data-v-3926b6c7]{margin-top:.2rem}.progress-bar-container_Btve,.progress-bar-inner-container_RjNy{height:30px}.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_Dxmf{font-size:2rem}}@media screen and (max-width:576px){.searchQueryColumn_a_BC{max-width:100%!important}.searchVersionColumn_y88e{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@media (max-width:454px){.footer[data-v-3926b6c7]{justify-content:center}}@media (hover:hover){.backToTopButton_CW5h:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-color-scheme:dark){.dark\:border-white\/5{border-color:#ffffff0d}.dark\:bg-\[rgb\(2\2c 2\2c 2\)\]{--tw-bg-opacity:1;background-color:rgb(2 2 2/var(--tw-bg-opacity))}.dark\:bg-black\/40{background-color:#0006}.dark\:bg-neutral-900{--tw-bg-opacity:1;background-color:rgb(23 23 23/var(--tw-bg-opacity))}.dark\:bg-transparent{background-color:initial}.dark\:via-white\/80{--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#fffc var(--tw-gradient-via-position),var(--tw-gradient-to)}.dark\:text-neutral-400\/50{color:#a3a3a380}.dark\:after\:bg-transparent:after,.dark\:before\:bg-transparent:before{background-color:initial;content:var(--tw-content)}.dark\:hover\:bg-neutral-800:hover{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity))}.hover\:dark\:text-neutral-400:hover{--tw-text-opacity:1;color:rgb(163 163 163/var(--tw-text-opacity))}:root{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-mask-bg-color:#656c85cc;--dm-divider-color:#2e2e32;--dm-highlight-color:var(--dm-color-brand)}.hljs{background:#0d1117;color:#c9d1d9}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{background-color:#033a16;color:#aff5b4}.hljs-deletion{background-color:#67060c;color:#ffdcd7}}@media (prefers-color-scheme:light){.hljs{background:#fff;color:#24292e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{background-color:#f0fff4;color:#22863a}.hljs-deletion{background-color:#ffeef0;color:#b31d28}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_egfn,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_CgoI{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_wRYc{white-space:pre-wrap}} \ No newline at end of file +@import url(https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown.css);@import url(https://rsms.me/inter/inter.css);.col,.container{padding:0 var(--ifm-spacing-horizontal)}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,.tab_J4Y8{-webkit-user-select:none}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}html[data-theme=dark],html[data-theme=light]{--ifm-menu-color-active:var(--ifm-color-primary-text);--admonition-note-c-color:#ff9ff3;--admonition-code-note-c-bg:#ff9ff350}.theme-admonition,:root{--ifm-alert-color:var(--ifm-font-color-base)}.theme-admonition-note,.theme-admonition-warning{--admonition-bar-c-bg:var(--admonition-bar-note-c-bg);--admonition-link-c:var(--admonition-link-note-c)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50,.from-transparent{--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.bg-fuchsia-600,.bg-gray-100,.bg-gray-500,.bg-neutral-100,.bg-zinc-950{--tw-bg-opacity:1}.toggleButton_SA1E,html{-webkit-tap-highlight-color:transparent}.dark,:root{--dm-mask-bg-color:#656c85cc;--dm-highlight-color:var(--dm-color-brand)}*,.DocSearch-Container,.DocSearch-Container *,.tab_J4Y8{box-sizing:border-box}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--doc-sidebar-width:17.5rem;--dropdown-icon-width:0.625rem;--dropdown-icon-height:0.375rem;--dropdown-icon-gap:0.688rem;--ifm-menu-link-padding-vertical:0.5rem;--sidebar-spacing-horizontal:1.5rem;--ifm-menu-color-background-hover:#0000}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_jY3I{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.items-center,.menuExternalLink_givM,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width);width:100%}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size);inherit:unset}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList_u0Lq{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration);color:#c44cac}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_c4T5 .wordWrapButtonIcon_Ci1R{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.admonitionHeading_N477 code,.btn_bvfa{text-transform:none}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover,.enter-to[data-v-3926b6c7],.hash-link:focus,.leave-from[data-v-3926b6c7],:hover>.hash-link{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button,.flex-grow{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_tjKH:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;pointer-events:none;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;transform:translateY(-50%);top:4px}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}:root,[data-theme=dark]{--ifm-footer-background-color:#181818}.footer__links,.mb-4{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color)}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_blJp article>:first-child,.docItemContainer_blJp header+*,.footer__item{margin-top:0}.admonitionContent_o_y9>:last-child,.collapsibleContent_ytpx p:last-child,.details_rMme>summary>p:last-child,.footer__items,.tabItem_FKkE>:last-child{margin-bottom:0}[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_BZZK{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_rMme[data-collapsed=false].isBrowser_hcAL>summary:before,.details_rMme[open]:not(.isBrowser_hcAL)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;top:0;bottom:0;visibility:hidden;left:0}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.after\:blur-\[var\(--after-blur\)\]:after,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.flex,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_KIGE,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.h-full,.navbar__logo img,body,html{height:100%}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}#nprogress,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}:root,[data-theme=dark],html[data-theme=light]{--ifm-menu-color-background-active:#ff9ff330}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.DocSearch-Button,.DocSearch-Link,.DocSearch-Prefill,.DocSearch-Reset,.cursor-pointer,.dropdownNavbarItemMobile_p8nV,.hover\:cursor-pointer:hover,.pills__item,.tab_J4Y8,.tabs__item{cursor:pointer}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.overflow-x-auto,.tabs{overflow-x:auto}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover,.shadow-\[inset_0_-8px_10px_\#8fdfff1f\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.group:hover .group-hover\:translate-x-0\.5,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.inline-flex,.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_bW6b>li)>.containsTaskList_bW6b{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.transition,.transition-all,.transition-shadow,.transition-transform{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--sidebar-category-c:var(--c-gray-0);--sidebar-border-c:var(--c-gray-90);--ifm-menu-color:var(--c-gray-20);--note-color:#e3e3e3;--admonition-tip-border:var(--c-green-50);--admonition-tip-color:var(--c-green-50);--admonition-note-c-bg:#0000;--admonition-info-c-bg:#0000;--admonition-tip-c-bg:#0000;--admonition-warning-c-bg:#0000;--admonition-caution-c-bg:#0000;--admonition-danger-c-bg:#0000;--admonition-info-c-color:var(--c-blue-50);--admonition-tip-c-color:var(--c-green-50);--admonition-warning-c-color:var(--c-yellow-50);--admonition-caution-c-color:var(--c-orange-50);--admonition-danger-c-color:var(--c-red-50);--ifm-alert-tip-background-color:var(--c-green-50-a);--admonition-code-warning-c-bg:var(--c-yellow-50-a);--admonition-code-info-c-bg:#00163d;--admonition-code-tip-c-bg:#003d11;--admonition-code-caution-c-bg:#3d1200;--admonition-code-danger-c-bg:#3d0003;--ifm-alert-warning-background-color:var(--c-yellow-30-a);--c-brand:#ff73ec90;--c-yellow-50:#f9d76f;--c-yellow-50-a:#ffd75a60;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.302);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}html[data-theme=light]{--sidebar-category-c:var(--c-gray-100);--sidebar-border-c:var(--c-gray-0);--ifm-menu-color:var(--c-indigo-80);--note-color:#241800;--admonition-note-c-bg:linear-gradient(to bottom,var(--ifm-alert-note-background-color),#0000 40%);--admonition-info-c-bg:linear-gradient(to bottom,var(--ifm-alert-info-background-color),#0000 40%);--admonition-tip-c-bg:linear-gradient(to bottom,var(--ifm-alert-tip-background-color),#0000 40%);--admonition-warning-c-bg:linear-gradient(to bottom,var(--ifm-alert-warning-background-color),#0000 40%);--admonition-caution-c-bg:linear-gradient(to bottom,var(--ifm-alert-caution-background-color),#0000 40%);--admonition-danger-c-bg:linear-gradient(to bottom,var(--ifm-alert-danger-background-color),#0000 40%);--admonition-info-c-color:inherit;--admonition-tip-c-color:inherit;--admonition-warning-c-color:inherit;--admonition-caution-c-color:inherit;--admonition-danger-c-color:inherit;--admonition-code-info-c-bg:var(--c-teal-20);--admonition-code-warning-c-bg:var(--c-yellow-20);--admonition-code-tip-c-bg:var(--c-green-20);--admonition-code-caution-c-bg:var(--c-orange-20);--admonition-code-danger-c-bg:var(--c-red-10);--admonition-tip-border:var(--c-green-100);--admonition-tip-color:var(--c-green-100);--ifm-alert-warning-background-color:var(--c-yellow-10);--ifm-alert-tip-background-color:var(--c-green-10);--ifm-alert-danger-background-color:var(--c-red-10);--ifm-alert-note-background-color:#ff9ff360;--ifm-alert-info-background-color:var(--c-teal-10);--ifm-alert-caution-background-color:var(--c-green-10)}[class^=docRoot_]{width:1440px!important}.links_A3uT,.sp-link_GRPb,[class^=docsWrapper_]{display:flex;justify-content:center}#__docusaurus .theme-doc-sidebar-container{background:var(--token-primary-bg-c);border-inline-end:1px solid var(--sidebar-border-c);bottom:0;height:calc(100vh - 60px);margin-block-start:0;position:sticky;top:60px;will-change:auto}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a{align-items:center;display:flex;height:var(--ifm-navbar-height)}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a,#__docusaurus [class^=sidebar_]{padding-inline-end:var(--sidebar-spacing-horizontal);padding-inline-start:var(--sidebar-spacing-horizontal)}#__docusaurus [class^=sidebar_]{max-height:100vh;overflow-y:auto;padding-block-start:1rem;position:static}#__docusaurus [class^=sidebar_]>.menu{overflow-x:initial;padding-block-end:2rem;padding:0}#__docusaurus [class^=sidebarLogo]{display:none!important}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list,.codeBlockStandalone_yM_Q,.p-0{padding:0}#__docusaurus .menu__list{transition:height .35s cubic-bezier(.36,.66,.04,1) 25ms!important;will-change:auto!important}#__docusaurus .menu__list .menu__list .menu__link--sublist{margin-inline-start:calc((var(--dropdown-icon-width) + var(--dropdown-icon-gap))*-1)}#__docusaurus .menu__list .menu__list .menu__link--sublist:after,.header-github-link:hover{opacity:.6}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1{padding-inline-start:calc(var(--dropdown-icon-width))}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1>.menu__link{color:var(--sidebar-category-c);font-size:14px;font-weight:500}#__docusaurus .menu__list-item:not(:first-child){margin-block-start:0}#__docusaurus .menu__list-item .menu__list .menu__link{padding-inline-start:calc(var(--dropdown-icon-width) + var(--dropdown-icon-gap));padding:7px 10px}#__docusaurus .menu__list-item-collapsible,.block{display:block}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list>.menu__list-item:last-of-type{padding-block-end:.5rem}#__docusaurus .theme-doc-sidebar-item-category-level-1:last-of-type{margin-block-end:.5rem}#__docusaurus .menu__link{align-items:center;display:flex;font-size:.85rem;font-weight:500;letter-spacing:-.01em;line-height:16px;transition:opacity .2s ease-out}#__docusaurus .menu__link:not(.menu__link--active:not(.menu__link--sublist)){background:initial}#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):active,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):focus,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):hover{opacity:.7}#__docusaurus .menu__link--sublist{align-items:center;display:flex;flex-direction:row-reverse;justify-content:flex-end;margin-block-end:0;padding-inline-end:0;padding-inline-start:0}#__docusaurus .menu__link--sublist:after{background:var(--ifm-menu-link-sublist-icon) center/var(--dropdown-icon-width) var(--dropdown-icon-height);background-repeat:no-repeat;height:var(--dropdown-icon-height);margin-block-end:0;margin-inline-end:var(--dropdown-icon-gap);margin-inline-start:unset;min-width:auto;width:var(--dropdown-icon-width)}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list-item-collapsible .menu__link{color:var(--sidebar-category-c);font-size:.938rem;font-weight:600;line-height:100%}html[data-theme=light] body{--angle:220deg;background-attachment:fixed;background-image:linear-gradient(var(--angle),#fff 15%,rgba(255,159,243,.376) 20%,#fff 25%,#f4eef8 30%,#fff 35%,#f8edf5 40%,#fff 60%);background-size:cover}.theme-admonition{border:none;position:relative;--ifm-alert-padding-horizontal:2rem;--ifm-alert-padding-vertical:1.5rem}.theme-admonition [class^=admonitionHeading_]{font-size:1rem;line-height:1.6;text-transform:capitalize}.theme-admonition [class^=admonitionHeading_] [class^=admonitionIcon_]{display:none}.theme-admonition [class^=admonitionContent_] p a{color:var(--admonition-link-c);text-decoration:underline}.theme-admonition [class^=admonitionContent_] p code{background:var(--admonition-code-c-bg)}.theme-admonition-warning{--admonition-code-c-bg:var(--admonition-code-warning-c-bg);background:#0000;border:2px solid var(--c-yellow-90-a);color:var(--c-yellow-90)}.theme-admonition-note{--admonition-code-c-bg:var(--admonition-code-note-c-bg);background:#0000;border:2px solid var(--c-brand-a);color:var(--c-brand)}.theme-admonition-info{--ifm-alert-background-color:var(--c-teal-210);--admonition-bar-c-bg:var(--admonition-bar-info-c-bg);--admonition-code-c-bg:var(--admonition-code-info-c-bg);--admonition-link-c:var(--admonition-link-info-c);background:#0000;border:2px solid var(--c-teal-60);color:var(--c-teal-90)}.theme-admonition-tip{--admonition-bar-c-bg:var(--admonition-bar-tip-c-bg);--admonition-code-c-bg:var(--admonition-code-tip-c-bg);--admonition-link-c:var(--admonition-link-tip-c);background:#0000;border:2px solid var(--admonition-tip-border);color:var(--admonition-tip-color)}.theme-admonition-caution{--ifm-alert-background-color:var(--admonition-caution-c-bg);--admonition-bar-c-bg:var(--admonition-bar-caution-c-bg);--admonition-code-c-bg:var(--admonition-code-caution-c-bg);--admonition-link-c:var(--admonition-link-caution-c);background:#0000}.theme-admonition-danger,.theme-admonition-important{--admonition-bar-c-bg:var(--admonition-bar-danger-c-bg);--admonition-code-c-bg:var(--admonition-code-danger-c-bg);--admonition-link-c:var(--admonition-link-danger-c)}.theme-admonition-danger{--ifm-alert-background-color:var(--admonition-danger-c-bg);background:#0000;border:2px solid var(--c-red-50-a);color:var(--c-red-50)}.theme-admonition-important{--ifm-alert-background-color:var(--c-lavender-210);background:linear-gradient(to bottom,var(--ifm-alert-background-color),#0000);border:2px solid var(--c-lavender-220)}:root{--admonition-bar-note-c-bg:var(--c-yellow-80);--admonition-bar-info-c-bg:var(--c-blue-80);--admonition-bar-tip-c-bg:var(--c-green-80);--admonition-bar-caution-c-bg:var(--c-orange-80);--admonition-bar-danger-c-bg:var(--c-red-60);--admonition-link-note-c:var(--c-brand);--admonition-link-info-c:var(--c-teal-90);--admonition-link-tip-c:var(--c-green-60);--admonition-color-tip-c:var(--note-color);--admonition-color-note-c:var(--note-color);--admonition-link-caution-c:var(--c-orange-90);--admonition-link-danger-c:var(--c-red-60);--c-black:#000;--c-white:#fff;--c-blue-0:#f0f6ff;--c-blue-10:#e3edff;--c-blue-20:#cddfff;--c-blue-30:#b2ceff;--c-blue-40:#97bdff;--c-blue-50:#7cabff;--c-blue-60:#639bff;--c-blue-70:#4d8dff;--c-blue-80:#3880ff;--c-blue-90:#176bff;--c-blue-100:#0054e9;--c-blue-110:#004dd6;--c-blue-120:#0046c1;--c-blue-130:#003fae;--c-blue-140:#00389b;--c-blue-150:#002d7c;--c-blue-160:#002669;--c-blue-170:#001d52;--c-blue-180:#001740;--c-blue-190:#00112f;--c-blue-200:#000b1f;--c-gray-0:#f3f3f3;--c-gray-10:#e4e4e4;--c-gray-20:#c8c8c8;--c-gray-30:#aeaeae;--c-gray-40:#959595;--c-gray-50:#818181;--c-gray-60:#6d6d6d;--c-gray-70:#5f5f5f;--c-gray-80:#474747;--c-gray-90:#2f2f2f;--c-gray-100:#141414;--c-carbon-0:#eef1f3;--c-carbon-10:#d7dde2;--c-carbon-20:#b4bcc6;--c-carbon-30:#98a2ad;--c-carbon-40:#7d8894;--c-carbon-50:#677483;--c-carbon-60:#556170;--c-carbon-70:#434f5e;--c-carbon-80:#35404e;--c-carbon-90:#222d3a;--c-carbon-100:#03060b;--c-indigo-0:#fbfbfd;--c-indigo-10:#f6f8fc;--c-indigo-20:#e9edf3;--c-indigo-30:#dee3ea;--c-indigo-40:#ced6e0;--c-indigo-50:#b2becd;--c-indigo-60:#92a0b3;--c-indigo-70:#73849a;--c-indigo-80:#445b78;--c-indigo-90:#2d4665;--c-indigo-100:#001a3a;--c-green-0:#f1fdf5;--c-green-10:#deffe7;--c-green-20:#c7fbd5;--c-green-30:#a7f1bb;--c-green-40:#80e89d;--c-green-50:#62e085;--c-green-50-a:#62e08560;--c-green-60:#4ada71;--c-green-70:#2dd55b;--c-green-80:#17c948;--c-green-90:#00ba33;--c-green-100:#00a52d;--c-green-110:#009b2b;--c-green-120:#009128;--c-green-130:#008725;--c-green-140:#007d22;--c-green-150:#00711f;--c-green-160:#00661c;--c-green-170:#00581a;--c-green-180:#004314;--c-green-190:#002f0e;--c-green-200:#001807;--c-lime-0:#f5fff0;--c-lime-10:#ebfee3;--c-lime-20:#ddfcd0;--c-lime-30:#cffbbc;--c-lime-40:#bbf9a2;--c-lime-50:#a3f581;--c-lime-60:#8bf35f;--c-lime-70:#64ec44;--c-lime-80:#4ddf2b;--c-lime-90:#3ad515;--c-lime-100:#27c100;--c-lime-110:#25b400;--c-lime-120:#22a400;--c-lime-130:#1e9200;--c-lime-140:#1a7e00;--c-lime-150:#176d00;--c-lime-160:#135a00;--c-lime-170:#0f4900;--c-lime-180:#0c3900;--c-lime-190:#092c00;--c-lime-200:#061d00;--c-lavender-0:#f7f8ff;--c-lavender-10:#e6ebff;--c-lavender-20:#ced9ff;--c-lavender-30:#b6c6ff;--c-lavender-40:#9fb5ff;--c-lavender-50:#8aa4ff;--c-lavender-60:#7493ff;--c-lavender-70:#597eff;--c-lavender-80:#3c67ff;--c-lavender-90:#194bfd;--c-lavender-100:#0033e8;--c-lavender-110:#002dcc;--c-lavender-120:#0028b8;--c-lavender-130:#0023a2;--c-lavender-140:#002092;--c-lavender-150:#001a79;--c-lavender-160:#001560;--c-lavender-170:#00114e;--c-lavender-180:#000e41;--c-lavender-190:#000a30;--c-lavender-200:#000721;--c-lavender-210:#8aa4ff50;--c-lavender-220:#7493ff40;--c-purple-0:#f4f4ff;--c-purple-10:#e9eaff;--c-purple-20:#d0d2ff;--c-purple-30:#b6b9f9;--c-purple-40:#9a99fc;--c-purple-50:#8482fb;--c-purple-60:#786df9;--c-purple-70:#6e5afd;--c-purple-80:#6030ff;--c-purple-90:#4712fb;--c-purple-100:#3400e6;--c-purple-110:#3000d1;--c-purple-120:#2b00bc;--c-purple-130:#2600a6;--c-purple-140:#20008e;--c-purple-150:#1b0075;--c-purple-160:#15005c;--c-purple-170:#100048;--c-purple-180:#0d0038;--c-purple-190:#0b0030;--c-purple-200:#080022;--c-brand:#8f1a7f;--c-brand-a:#8f1a7f60;--c-pink-0:#ffeff5;--c-pink-10:#ffe3ed;--c-pink-20:#ffd8e5;--c-pink-30:#ffc9db;--c-pink-40:#ffb6d0;--c-pink-50:#ff99bd;--c-pink-60:#ff80ac;--c-pink-70:#ff6098;--c-pink-80:#fb4082;--c-pink-90:#ec216a;--c-pink-100:#da0d56;--c-pink-110:#d0004a;--c-pink-120:#c40046;--c-pink-130:#b30040;--c-pink-140:#a3003b;--c-pink-150:#940035;--c-pink-160:#850030;--c-pink-170:#710029;--c-pink-180:#5f0022;--c-pink-190:#460019;--c-pink-200:#20000b;--c-red-0:#fff1f3;--c-red-10:#ffe6e8;--c-red-20:#ffcfd3;--c-red-30:#feb7bc;--c-red-40:#fc9aa2;--c-red-50:#f9838c;--c-red-50-a:#f9838c60;--c-red-60:#f56570;--c-red-70:#f24c58;--c-red-80:#ef3442;--c-red-90:#e21827;--c-red-100:#d0000f;--c-red-110:#c5000f;--c-red-120:#b3000e;--c-red-130:#9c000c;--c-red-140:#89000b;--c-red-150:#760009;--c-red-160:#650008;--c-red-170:#520006;--c-red-180:#410005;--c-red-190:#300004;--c-red-200:#1d0002;--c-red-210:#f24c5830;--c-red-220:#ef344215;--c-orange-0:#fff5f0;--c-orange-10:#ffede6;--c-orange-20:#ffdfd1;--c-orange-30:#ffd0bc;--c-orange-40:#ffc0a5;--c-orange-50:#ffaf8c;--c-orange-60:#ff9b70;--c-orange-70:#ff8753;--c-orange-80:#ff7336;--c-orange-90:#ff5b13;--c-orange-100:#eb4700;--c-orange-110:#d94200;--c-orange-120:#c93d00;--c-orange-130:#b63700;--c-orange-140:#a53200;--c-orange-150:#8c2a00;--c-orange-160:#772400;--c-orange-170:#5e1c00;--c-orange-180:#481600;--c-orange-190:#341000;--c-orange-200:#1d0900;--c-yellow-0:#fffbef;--c-yellow-10:#fff8e2;--c-yellow-20:#fff4d1;--c-yellow-30:#ffefbd;--c-yellow-30-a:#fcd28550;--c-yellow-40:#ffe9a3;--c-yellow-50:#ffcb2d;--c-yellow-50-a:#ffd75a60;--c-yellow-60:#ffd75a;--c-yellow-60-a:#ffd75a30;--c-yellow-70:#ffce31;--c-yellow-80:#ffc409;--c-yellow-90:#f4b100;--c-yellow-90-a:#f4b10060;--c-yellow-100:#eaa100;--c-yellow-110:#dd9800;--c-yellow-120:#cc8d00;--c-yellow-130:#be8300;--c-yellow-140:#b17a00;--c-yellow-150:#9c6c00;--c-yellow-160:#8a6000;--c-yellow-170:#755100;--c-yellow-180:#5f4100;--c-yellow-190:#452f00;--c-yellow-200:#231800;--c-yellow-210:#ffc40950;--c-yellow-220:#ffce3140;--c-aqua-0:#f0fff9;--c-aqua-10:#e6fff6;--c-aqua-20:#ceffed;--c-aqua-30:#b7fce3;--c-aqua-40:#93f9d5;--c-aqua-50:#79f5c9;--c-aqua-60:#59f0ba;--c-aqua-70:#38e9aa;--c-aqua-80:#1ae19a;--c-aqua-90:#00d287;--c-aqua-100:#00ba78;--c-aqua-110:#00aa6d;--c-aqua-120:#009b63;--c-aqua-130:#00915c;--c-aqua-140:#008152;--c-aqua-150:#016e46;--c-aqua-160:#015d3c;--c-aqua-170:#014f32;--c-aqua-180:#013e28;--c-aqua-190:#012e1e;--c-aqua-200:#011e13;--c-teal-0:#eefeff;--c-teal-10:#dffdff;--c-teal-20:#d0fdff;--c-teal-30:#bbfcff;--c-teal-40:#a2fcff;--c-teal-50:#8bfbff;--c-teal-60:#73f6fb;--c-teal-60-a:#73f6fb60;--c-teal-70:#55ecf2;--c-teal-80:#35e2e9;--c-teal-90:#1bd2d9;--c-teal-100:#00b9c0;--c-teal-110:#01adb4;--c-teal-120:#019fa5;--c-teal-130:#018f94;--c-teal-210:#3dc1d340;--c-teal-220:#3dc1d325;--c-teal-140:#017e83;--c-teal-150:#016d71;--c-teal-160:#015d61;--c-teal-170:#014d4f;--c-teal-180:#013c3e;--c-teal-190:#012c2e;--c-teal-200:#011c1d;--c-cyan-0:#f3faff;--c-cyan-10:#e8f5ff;--c-cyan-20:#d3ecff;--c-cyan-30:#bfe4ff;--c-cyan-40:#a7daff;--c-cyan-50:#8dcfff;--c-cyan-60:#77c6ff;--c-cyan-70:#62bdff;--c-cyan-80:#46b1ff;--c-cyan-90:#24a3ff;--c-cyan-100:#0091fa;--c-cyan-110:#0189ec;--c-cyan-120:#017ed8;--c-cyan-130:#0170c0;--c-cyan-140:#0163aa;--c-cyan-150:#015592;--c-cyan-160:#01487b;--c-cyan-170:#013a64;--c-cyan-180:#012d4d;--c-cyan-190:#011e33;--c-cyan-200:#01121e;--sans-serif:-apple-system,BlinkMacSystemFont,san-francisco,Avenir Next,Segoe UI,Roboto,Noto Sans,Helvetica Neue;--serif:Iowan Old Style,Apple Garamond,Baskerville,Times New Roman;--monospaced:Menlo;--border:#03a9f4;--g1:#0003;--g2:#8f1a7f33;--g3:#1f1f1f33;--ifm-color-primary:#8f1a7f;--ifm-color-primary-dark:#6f1a5f;--ifm-color-primary-text:#6f1a5f;--ifm-color-primary-darker:#5f1a4f;--ifm-color-primary-darkest:#4f1a3f;--ifm-color-primary-light:#9f1a8f;--ifm-color-primary-lighter:#af1a9f;--ifm-color-primary-lightest:#bf1aaf;--ifm-code-font-size:95%;--ifm-border-color:#0000000d;--ifm-background:#00000003;--ifm-announcementBar-height:40px;--ifm-primary-hue-saturation:308 78%;--ifm-primary-hue-saturation-light:308 78%;--accent:113,26,95;--accent-background-card-gradient:linear-gradient(45deg,rgb(var(--accent)),#fda7df 10%,var(--ifm-f-white) 40%);--ifm-f-white:#fff;--ifm-f-re-white:#181818;--ifm-f-white-soft:#f8f8f8;--ifm-f-white-mute:#f2f2f2;--ifm-f-bg-soft:#f6f6f7;--farm--border:rgba(86,86,86,.125);--docsearch-searchbox-background:#8f1a7fb3;--max-layout-width:1680px;--ifm-navbar-link-hover-color:initial;--ifm-navbar-padding-vertical:0;--ifm-navbar-item-padding-vertical:0;--ifm-font-family-base:-apple-system,BlinkMacSystemFont,Inter,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI emoji";--ifm-font-family-monospace:"SFMono-Regular","Roboto Mono",Consolas,"Liberation Mono",Menlo,Courier,monospace;--ifm-menu-link-sublist-icon:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSI2IiBmaWxsPSJub25lIj48cGF0aCBzdHJva2U9IiMwMzA2MEIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjUiIGQ9Ik05IDUgNSAxIDEgNSIvPjwvc3ZnPg==");--z-sidebar:2000;--z-backdrop:1100;--ifm-menu-color-background:#ff9ff310;--docusaurus-highlighted-code-line-bg:#ff9ff310;--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base);--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--dm-color-brand:#3451b2;--dm-color-bg-alt:#f6f6f7;--dm-color-hint:#3c3c43c7;--dm-button-font-size:13px;--dm-button-height:40px;--dm-c-white:#fff;--dm-text-color:#374151;--dm-modal-bg-color:var(--dm-c-white);--dm-divider-color:#f3f4f6;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.container,.w-full{width:100%}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.absolute{position:absolute}.chat-container[data-v-3926b6c7],.relative{position:relative}.inset-0{inset:0}.z-10{z-index:10}.m-auto{margin:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-10{margin-bottom:2.5rem;margin-top:2.5rem}.my-14{margin-bottom:3.5rem;margin-top:3.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-8{margin-bottom:2rem;margin-top:2rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.mt-10{margin-top:2.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.loader_KTq1,.mt-8{margin-top:2rem}.inline,.tags_y0VJ{display:inline}.grid{display:grid}.size-3{height:.75rem;width:.75rem}.size-4{height:1rem;width:1rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.documate-button .icon[data-v-956ba6e9],.h-4{height:1rem}.h-52{height:13rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.min-h-\[2rem\]{min-height:2rem}.min-h-\[inherit\]{min-height:inherit}.w-16{width:4rem}.w-20{width:5rem}.w-36{width:9rem}.w-40{width:10rem}.w-6{width:1.5rem}.w-9\/12{width:75%}.w-\[1px\]{width:1px}.max-w-7xl{max-width:80rem}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}@keyframes a{0%,90%,to{background-position:calc(-100% - var(--shimmer-width)) 0}30%,60%{background-position:calc(100% + var(--shimmer-width)) 0}}.animate-shimmer{animation:8s infinite a}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center,.mdxPageWrapper_Xr2N{justify-content:center}.justify-between{justify-content:space-between}.gap-10{gap:2.5rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-5{column-gap:1.25rem}.gap-y-12{row-gap:3rem}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.self-start{align-self:flex-start}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[var\(--border-radius\)\]{border-radius:var(--border-radius)}.rounded-\[var\(--card-content-radius\)\]{border-radius:var(--card-content-radius)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-black\/5{border-color:#0000000d}.bg-fuchsia-600{background-color:rgb(192 38 211/var(--tw-bg-opacity))}.bg-gray-100{background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-500{background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-neutral-100{background-color:rgb(245 245 245/var(--tw-bg-opacity))}.bg-white\/40{background-color:#fff6}.bg-zinc-950{background-color:rgb(9 9 11/var(--tw-bg-opacity))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-\[\#ffaa40\]{--tw-gradient-from:#ffaa40 var(--tw-gradient-from-position)}.from-\[\#ffaa40\]\/50{--tw-gradient-from:#ffaa4080 var(--tw-gradient-from-position)}.from-transparent{--tw-gradient-from:#0000 var(--tw-gradient-from-position);--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.via-\[\#9c40ff\],.via-\[\#9c40ff\]\/50{--tw-gradient-to:#9c40ff00 var(--tw-gradient-to-position)}.via-\[\#9c40ff\]{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-\[\#9c40ff\]\/50{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff80 var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-black\/80{--tw-gradient-to:#0000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#000c var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-50\%{--tw-gradient-via-position:50%}.to-\[\#ffaa40\]{--tw-gradient-to:#ffaa40 var(--tw-gradient-to-position)}.to-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4080 var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.bg-\[length\:var\(--bg-size\)_100\%\]{background-size:var(--bg-size) 100%}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.p-2{padding:.5rem}.p-6{padding:1.5rem}.p-\[1px\]{padding:1px}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.text-left{text-align:left}.data_ODnV,.kbd-text[data-v-3926b6c7],.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.tracking-wide{letter-spacing:.025em}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-neutral-600\/50{color:#52525280}.text-transparent{color:#0000}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow-\[inset_0_-8px_10px_\#8fdfff1f\]{--tw-shadow:inset 0 -8px 10px #8fdfff1f;--tw-shadow-colored:inset 0 -8px 10px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter}.transition-all{transition-property:all}.transition-shadow{transition-property:box-shadow}.transition-transform{transition-property:transform}.duration-200{transition-duration:.2s}.duration-300,.hover\:duration-300:hover{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--bg-size\:300\%\]{--bg-size:300%}.\[background-position\:0_0\]{background-position:0 0}.\[background-size\:var\(--shimmer-width\)_100\%\]{background-size:var(--shimmer-width) 100%}.\[border-radius\:inherit\]{border-radius:inherit}.\!\[mask-composite\:subtract\]{-webkit-mask-composite:source-out!important;mask-composite:subtract!important}.\[mask\:linear-gradient\(\#fff_0_0\)_content-box\2c linear-gradient\(\#fff_0_0\)\]{-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0)}[data-theme=dark]{--ifm-f-bg-soft:#252529;--ifm-background-color:#000!important;--ifm-color-primary:#fff;--ifm-color-primary-text:#fff;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--ifm-menu-color-background:#ff9ff340;--ifm-background:#0000004d;--ifm-f-white:#c74040;--ifm-f-re-white:#fff;--ifm-f-white-soft:#222;--ifm-f-white-mute:#282828;--farm--border:#fafafa20;--docusaurus-highlighted-code-line-bg:#8f1a7fb3;--docsearch-primary-color:var(--ifm-color-primary-dark)!important;--docsearch-searchbox-background:#3a3a3a!important}.navbar__title{color:#6f1a5f;font-size:1.5em}.navbar__title:hover{color:#bf1aaf}.header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat;content:"";display:flex;height:20px;width:20px}[data-theme=dark] .header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.bg{background-color:var(--ifm-f-white-soft)}.bg-re{background-color:var(--ifm-f-re-white)}.color{color:var(--ifm-f-white)}.token.color{color:#c44cac}.color-re{color:var(--ifm-f-re-white)}.theme-back-to-top-button{height:50px!important;width:50px!important}[class^=backToTopButton_]:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:3rem 3rem!important;-webkit-mask-size:3rem 3rem!important}.clean-btn:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:1.5rem 1.5rem!important;-webkit-mask-size:1.5rem 1.5rem!important}div[class^=announcementBar_]{--site-announcement-bar-stripe-color1:hsl(var(--ifm-primary-hue-saturation) 85%);--site-announcement-bar-stripe-color2:hsl(var(--ifm-primary-hue-saturation) 95%);background:linear-gradient(45deg,#711a5f,#c44cac 30%,#9f1a8f 60%,#fda7df 80%);color:var(--c-white);font-weight:700;height:var(--ifm-announcementBar-height)}footer[class=footer]{background-color:var(--ifm-f-white-soft)!important}.footer__link-item{gap:6px;line-height:3}.DocSearch-Button-Container,.footer__link-item,.navbar__link{align-items:center;display:flex}.code-block-highlight-line{background-color:var(--docusaurus-highlighted-code-line-bg);border-left:5px solid #c44cac;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.DocSearch-Button{border-radius:8px!important;width:250px}.theme-admonition-warning{color:var(--c-yellow-120)}.theme-admonition-danger{color:var(--c-red-60)}.theme-doc-version-badge{margin:10px 0}.navbar--fixed-top{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background:#0000;box-shadow:0 4px 10px #00000014}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}figure{margin:12px}.after\:absolute:after,.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:left-0:before{content:var(--tw-content);left:0}.before\:right-0:before{content:var(--tw-content);right:0}.before\:top-\[-var\(--border-size\)\]:before{content:var(--tw-content);top:-var(--border-size)}.after\:-z-10:after,.before\:z-\[-10\]:before{content:var(--tw-content);z-index:-10}.after\:block:after,.before\:block:before{content:var(--tw-content);display:block}.after\:h-\[var\(--pseudo-element-height\)\]:after,.before\:h-\[var\(--pseudo-element-height\)\]:before{content:var(--tw-content);height:var(--pseudo-element-height)}.before\:w-full:before{content:var(--tw-content);width:100%}.after\:animate-backgroundPositionSpin:after,.before\:animate-backgroundPositionSpin:before{animation:3s infinite alternate b;content:var(--tw-content)}.before\:bg-\[var\(--pseudo-element-background-image\)\]:before{background-color:var(--pseudo-element-background-image);content:var(--tw-content)}.before\:bg-\[length\:200\%_100\%\]:before{background-size:200% 100%;content:var(--tw-content)}.after\:content-\[\'\'\]:after,.before\:content-\[\'\'\]:before{--tw-content:"";content:var(--tw-content)}.after\:-left-\[var\(--border-size\)\]:after{content:var(--tw-content);left:calc(var(--border-size)*-1)}.after\:-top-\[var\(--border-size\)\]:after{content:var(--tw-content);top:calc(var(--border-size)*-1)}.after\:w-\[var\(--pseudo-element-width\)\]:after{content:var(--tw-content);width:var(--pseudo-element-width)}@keyframes b{0%{background-position:top;content:var(--tw-content)}to{background-position:bottom;content:var(--tw-content)}}.after\:rounded-\[var\(--border-radius\)\]:after{border-radius:var(--border-radius);content:var(--tw-content)}.after\:bg-\[linear-gradient\(0deg\2c var\(--neon-first-color\)\2c var\(--neon-second-color\)\2c var\(--neon-third-color\)\)\]:after{background-image:linear-gradient(0deg,var(--neon-first-color),var(--neon-second-color),var(--neon-third-color));content:var(--tw-content)}.after\:bg-\[length\:100\%_200\%\]:after{background-size:100% 200%;content:var(--tw-content)}.after\:opacity-80:after{content:var(--tw-content);opacity:.8}.after\:blur-\[var\(--after-blur\)\]:after{content:var(--tw-content);--tw-blur:blur(var(--after-blur))}.hover\:bg-neutral-200:hover{--tw-bg-opacity:1;background-color:rgb(229 229 229/var(--tw-bg-opacity))}.hover\:text-neutral-600:hover{--tw-text-opacity:1;color:rgb(82 82 82/var(--tw-text-opacity))}.focus\:text-opacity-80:focus,.hover\:text-opacity-80:hover{--tw-text-opacity:0.8}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover{--tw-shadow:inset 0 -5px 10px #8fdfff3f;--tw-shadow-colored:inset 0 -5px 10px var(--tw-shadow-color)}.group:hover .group-hover\:translate-x-0\.5{--tw-translate-x:0.125rem}.container__nVC{border-radius:6px;contain:content}}.tab-list_aJ1t{display:flex;min-width:100%;overflow-x:scroll;padding:4px 0 8px 8px}.tab_J4Y8{border-bottom:2px solid #0000;margin-bottom:-1px;margin-right:10px;padding:6px 12px;transition:.2s ease-in-out;user-select:none}.tab_J4Y8:last-child{margin-right:0}.selected_erAK{border-color:currentColor}.no-scrollbar_vtMC::-webkit-scrollbar{display:none}.no-scrollbar_vtMC{-ms-overflow-style:none;scrollbar-width:none}.backToTopButton_jRRJ{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_jRRJ:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_AHoy{opacity:1;transform:scale(1);visibility:visible}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;color:var(--docsearch-muted-color);display:flex;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch-Button-Key--pressed{box-shadow:var(--docsearch-key-pressed-shadow);transform:translate3d(0,1px,0)}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a,.sidebarItemLink_KhnB:hover{text-decoration:none}.DocSearch-Hit[aria-selected=true] mark,.content_hAup a{text-decoration:underline}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset,p[data-v-3926b6c7],ul[data-v-3926b6c7]{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards c;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.sidebar_Ap_S,.tableOfContents_b1mW{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}#__docusaurus-base-url-issue-banner-container,.button-placeholder[data-v-3926b6c7],.docSidebarContainer_wnoZ,.loading.hide[data-v-3926b6c7],.navbarSearchContainer_ws2C:empty,.sidebarLogo_XkDA,.themedComponent_qoxx,[data-theme=dark] .lightToggleIcon_mtGR,[data-theme=light] .darkToggleIcon_a9bq,html[data-announcement-bar-initially-dismissed=true] .announcementBar_NAgQ,svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon,.tocCollapsibleContent_UQzg a{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands li,.DocSearch-Commands-Key,.buttons_AeoN{align-items:center;display:flex}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@keyframes c{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container,.skipToContent_SvOr{z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_SvOr{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem}.skipToContent_SvOr:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_U3lQ{line-height:0;padding:0}.content_hAup{font-size:85%;padding:5px 0;text-align:center}.content_hAup a{color:inherit}.announcementBar_NAgQ{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_ZgHP{flex:0 0 10px}.announcementBarClose_iOKh{align-self:stretch;flex:0 0 30px}.toggle_eG47{height:2rem;width:2rem}.toggleButton_SA1E{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_SA1E:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_bPAB{cursor:not-allowed}.darkNavbarColorModeToggle_UyoV:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_kvRy,[data-theme=light] .themedComponent--light_lACA,html:not([data-theme]) .themedComponent--light_lACA{display:initial}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_igfI{display:none;margin:0}.iconExternalLink_rCHH{margin-left:.3rem}.docMainContainer_HtRu,.docRoot_DxwR{display:flex;width:100%}.docsWrapper__6U0{display:flex;flex:1 0 auto}.iconLanguage_muqp{margin-right:5px;vertical-align:text-bottom}.dark{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-divider-color:#2e2e32}.sp_EK1s .sp-link_GRPb.link_ib43:focus,.sp_EK1s .sp-link_GRPb.link_ib43:hover,body:not(.navigation-with-keyboard) :not(input):focus,input[data-v-3926b6c7],input[data-v-3926b6c7]:focus{outline:0}.enter[data-v-3926b6c7]{transition:opacity .2s ease-out}.enter-from[data-v-3926b6c7],.leave-to[data-v-3926b6c7]{opacity:0}.leave[data-v-3926b6c7]{transition:opacity .1s ease-in}.transition-child-ref[data-v-3926b6c7]{bottom:0;left:0;position:fixed;right:0;top:0;transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dialog[data-v-3926b6c7]{background-color:var(--dm-mask-bg-color);bottom:0;left:0;overflow-y:auto;position:fixed;right:0;top:0;z-index:999999}.dialog-container[data-v-3926b6c7]{padding:1rem}.dialog-panel[data-v-3926b6c7]{background-color:var(--dm-modal-bg-color);border-radius:.75rem;box-shadow:0 25px 50px -12px #00000040;margin:0 auto;max-width:36rem;overflow:hidden;transition-duration:.3s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.magnifying-glass-icon[data-v-3926b6c7]{color:var(--dm-text-color);height:1.25rem;left:1rem;pointer-events:none;position:absolute;top:.875rem;width:1.25rem}.chat-input[data-v-3926b6c7]{background-color:initial;border-width:0;border-bottom:1px solid var(--dm-divider-color);box-sizing:border-box;color:var(--dm-text-color);height:3rem;padding-left:2.75rem;padding-right:1rem;width:100%}.chat-input[data-v-3926b6c7]::placeholder{font-size:1rem}.combobox-options[data-v-3926b6c7]{list-style:none;max-height:20rem;min-height:5rem;overflow-y:auto;padding:1rem;scroll-padding-bottom:.5rem;scroll-padding-top:2.5rem}.combobox-option[data-v-3926b6c7]{cursor:pointer;display:flex;padding:.5rem 1rem;-webkit-user-select:none;user-select:none}.combobox-options-container[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;margin-left:-1rem;margin-right:-1rem;margin-top:.5rem}.active[data-v-3926b6c7]{background-color:var(--dm-highlight-color);color:var(--dm-c-white)}.combobox-options-name[data-v-3926b6c7]{flex:1 1 auto;margin-left:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.loading[data-v-3926b6c7]{align-items:center;display:flex;justify-content:left;padding:1rem 1rem 1rem 2.6rem}.loading-spin[data-v-3926b6c7]{animation:1s linear infinite d;height:1.5rem;margin-right:.5rem;width:1.5rem}.option-icon[data-v-3926b6c7]{flex:none;height:1.5rem;width:1.5rem}.question-anwser-section[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;list-style:none;max-height:20rem;scroll-padding-bottom:.5rem;scroll-padding-top:.5rem}.question-anwser-item[data-v-3926b6c7]{padding-bottom:.875rem;padding-top:.875rem}.question-role-user[data-v-3926b6c7]{display:flex;gap:1.2rem}.question-role-icon[data-v-3926b6c7]{display:inline-block;flex:none;height:1.5rem;width:1.5rem}.documate-logo[data-v-3926b6c7]{height:1.4rem;width:1.4rem}.result-not-found[data-v-3926b6c7]{padding:3.5rem 1.5rem;text-align:center}.result-not-found-text[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.85rem;margin-top:.5rem}.anwser-content[data-v-3926b6c7]{display:flex;gap:1.5rem}.markdown-body[data-v-3926b6c7]{border-width:0;color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;list-style:auto;overflow-wrap:break-word}.footer[data-v-3926b6c7]{align-content:center;align-items:center;border-top:1px solid var(--dm-divider-color);color:var(--dm-text-color);display:flex;flex-wrap:wrap;font-size:.75rem;justify-content:space-between;line-height:1rem;padding:.625rem 1rem}.kbd-wrap[data-v-3926b6c7]{align-content:center;display:flex;justify-content:center}.kbd-text[data-v-3926b6c7],.kbd[data-v-3926b6c7]{align-items:center;display:flex;justify-content:center}.kbd[data-v-3926b6c7]{border-radius:.25rem;border-width:1px;font-weight:600;height:1.25rem;margin-left:.25rem;margin-right:.25rem;width:1.25rem}.esc[data-v-3926b6c7]{width:2rem}.powered-by[data-v-3926b6c7]{align-items:center;color:var(--dm-text-color);display:flex;gap:.25rem;justify-content:center;text-decoration:none}@keyframes d{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.dark .hljs{background:#0d1117;color:#c9d1d9}.dark .hljs-doctag,.dark .hljs-keyword,.dark .hljs-meta .hljs-keyword,.dark .hljs-template-tag,.dark .hljs-template-variable,.dark .hljs-type,.dark .hljs-variable.language_{color:#ff7b72}.dark .hljs-title,.dark .hljs-title.class_,.dark .hljs-title.class_.inherited__,.dark .hljs-title.function_{color:#d2a8ff}.dark .hljs-attr,.dark .hljs-attribute,.dark .hljs-literal,.dark .hljs-meta,.dark .hljs-number,.dark .hljs-operator,.dark .hljs-selector-attr,.dark .hljs-selector-class,.dark .hljs-selector-id,.dark .hljs-variable{color:#79c0ff}.dark .hljs-meta .hljs-string,.dark .hljs-regexp,.dark .hljs-string{color:#a5d6ff}.dark .hljs-built_in,.dark .hljs-symbol{color:#ffa657}.dark .hljs-code,.dark .hljs-comment,.dark .hljs-formula{color:#8b949e}.dark .hljs-name,.dark .hljs-quote,.dark .hljs-selector-pseudo,.dark .hljs-selector-tag{color:#7ee787}.dark .hljs-subst{color:#c9d1d9}.dark .hljs-section{color:#1f6feb;font-weight:700}.dark .hljs-bullet{color:#f2cc60}.dark .hljs-emphasis{color:#c9d1d9;font-style:italic}.dark .hljs-strong{color:#c9d1d9;font-weight:700}.dark .hljs-addition{background-color:#033a16;color:#aff5b4}.dark .hljs-deletion{background-color:#67060c;color:#ffdcd7}.documate-button[data-v-956ba6e9]{align-items:center;cursor:pointer;display:flex;height:var(--dm-button-height);justify-content:flex-start;padding-left:.75rem;padding-right:.75rem;transition:border-color .25s ease-in-out}.navbarHideable_sTax{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_E1Ry{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_xnf4{color:red;white-space:pre-wrap}.errorBoundaryFallback_SyQ8{color:red;padding:.55rem}.anchorWithStickyNavbar_poOM{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_jxQw{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_DIHR{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.searchQueryInput_oi46,.searchVersionInput_th2q{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_oi46:focus,.searchVersionInput_th2q:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_oi46::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_cM4p{font-size:.9rem;font-weight:700}.algoliaLogo_Xo7j{max-width:150px}.algoliaLogoPathFill_GjF2{fill:var(--ifm-font-color-base)}.searchResultItem_FT2J{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_xbdO{font-weight:400;margin-bottom:0}.searchResultItemPath_H63Z{color:var(--ifm-color-content-secondary);font-size:.8rem;--ifm-breadcrumb-separator-size-multiplier:1}.searchResultItemSummary_v8kB{font-style:italic;margin:.5rem 0 0}.loadingSpinner_vBIe{animation:1s linear infinite e;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes e{to{transform:rotate(1turn)}}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}.card-container_mQSC:after,.card_L8bV{background:var(--ifm-f-white-soft);border-radius:10px;box-shadow:0 1px 4px #00000029;width:100%;transition:background-position .35s}.features_t9lD{align-items:center;display:flex;padding:2rem 0;width:100%}.item_fAv5{margin:0 auto;width:100%}.card_L8bV{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;padding:2rem .5rem 0;position:relative;z-index:2}.backgroundImage_M6A8{background:linear-gradient(-45deg,#e67ac6 50%,#47caff 0);border-radius:50%;filter:blur(36px)}.card-container_mQSC{cursor:pointer;justify-content:center;position:relative}.card-container_mQSC:hover:before{animation:16s linear infinite f;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;border-radius:10px;content:"";filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;position:absolute;top:-2px;transition:opacity .3s ease-in-out;width:calc(100% + 4px);z-index:-1000}.card-container_mQSC:after{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;content:"";height:100%;left:0;position:absolute;top:0;z-index:100}.card-container-content_HPWq{position:relative;transition:background-position .35s;z-index:1000}@keyframes f{0%,to{background-position:0 0}50%{background-position:400% 0}}.progress-bar-container_Btve{border:1px solid var(--farm--border);border-radius:4px;box-sizing:initial;height:25px;padding:4px;width:50vw}.progress-bar-inner-container_RjNy{background:#9f1a8f;border-radius:2px;height:25px}.progress-bar_MQ9H{background:linear-gradient(90deg,#c026d3,#d2269e);border-radius:2px;height:100%}.font-mono_qmiE{font-family:Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace}}.main_Gz2F{border:2px solid #272727;border-radius:5px;cursor:pointer;height:50px;overflow:hidden;position:relative;width:200px}.container_GXFn,.layer,canvas{height:100%}.fill_bMTX{background:#ff69b4}.content__pcr,.fill_bMTX{height:100%;left:0;position:absolute;top:0;width:100%}.content__pcr{color:#272727}.container_GXFn,.content__pcr{align-items:center;display:flex;justify-content:center}.tabs_FETH{align-items:center;display:flex;flex-direction:column;justify-content:center;width:100%}canvas{margin:0;padding:0;width:100%}.layer{bottom:0;left:0;width:100%}.layer,span.header{pointer-events:none;position:absolute}span.header{display:inline-block;font-size:9em;font-weight:700;left:50px;line-height:.9em;top:350px;transform:translate3d(0,-50%,0);width:500px}.heroBanner_qdFl{overflow:hidden;padding:3rem 0;position:relative;text-align:center}.banner_IlVB,.banner_d9gt{background:linear-gradient(45deg,#711a5f,#fda7df 70%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:#0000;color:#0000}.farmButton2_X03M,.farmButton_siNL{color:#fff;height:50px;outline:0;z-index:0;cursor:pointer}.btn_bvfa{border-radius:8px;border-width:2px;font-family:Open Sans;font-size:1rem;font-style:normal;font-weight:600;line-height:1.5rem;min-width:130px;padding:12px 20px}.farmButton_siNL{background:#111;border:none;border-radius:10px;position:relative}.farmButton_siNL:before{animation:120s linear infinite g;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .5s ease-in-out;width:calc(100% + 4px)}.farmButton2_X03M:after,.farmButton2_X03M:before,.farmButton_siNL:after,.farmButton_siNL:before{border-radius:10px;content:"";position:absolute;z-index:-1}.farmButton2_X03M:after,.farmButton_siNL:after{background:#111;height:100%;left:0;top:0;width:100%}.fKVWgc_SGll{inset:0;-webkit-mask-image:linear-gradient(#000,#0000);mask-image:linear-gradient(#000,#0000);position:absolute}.farmButton2_X03M{background:#171717;border:none;border-radius:10px;position:relative}.farmButton2_X03M:before{animation:100s linear infinite g;background:linear-gradient(45deg,#ffaa40,#9f1a8f,#ffaa40,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .2s ease-in-out;width:calc(100% + 4px)}@keyframes g{0%,to{background-position:0 0}30%{background-position:400% 0}}.gradientText_nNG0{background:linear-gradient(to bottom right,#000,gray 40%,#fff);-webkit-background-clip:text;color:#0000}.sidebar_Ap_S{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.card-main_mTfv,.teamMembersItem_XVAE{height:100%;overflow:hidden;width:100%}.sidebarItemTitle_Yqc5{font-size:var(--ifm-h3-font-size);font-weight:var(--ifm-font-weight-bold)}.container_qnDr,.sidebarItemList_Blx1{font-size:.9rem}.sidebarItem_EDKM{margin-top:.7rem}.sidebarItemLink_KhnB{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_BKqy{color:var(--ifm-color-primary)!important}.authorCol_lAQD{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_Hnn6{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_YwkJ{margin-left:.3rem;margin-right:.3rem}.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(130px,1fr))}.container_hhjZ{display:grid;gap:40px;margin:0 auto;width:100%}.card-main_mTfv{align-items:center;display:flex;justify-content:center}.card_sVd9{border-radius:8px;transition:box-shadow .5s;will-change:transform}.teamMembersItem_XVAE{border-radius:12px;display:flex;flex-direction:column;gap:2px}.teamMembersItem_XVAE .profile_WQFr{padding:10px}.teamMembersItem_XVAE .avatar_B5t7{cursor:pointer;height:64px;transition:.2s ease-in-out;width:64px}.teamMembersItem_XVAE .name_LD5w{font-size:16px;line-height:24px}.teamMembersItem_XVAE .org_o4tg{font-size:14px;line-height:24px}.teamMembersItem_XVAE .affiliation_rzqG{font-size:14px;line-height:20px;padding-top:4px}.teamMembersItem_XVAE .desc_pfHu{font-size:14px;line-height:20px;padding-top:12px}.teamMembersItem_XVAE .links_A3uT{margin:0 -16px -20px;padding:10px 0 0}.profile_WQFr{align-items:center;display:flex;flex-direction:column;flex-grow:1;gap:20px}.avatar_B5t7{border-radius:50%;flex-shrink:0;margin:0 auto;position:relative}.avatar-img_PAbF{border-radius:50%;bottom:0;left:0;object-fit:cover;position:absolute;right:0;top:0}.name_LD5w{font-weight:600;margin:0}.affiliation_rzqG{font-weight:500;margin:0}.org_o4tg.link_ib43{transition:color .25s}.desc_pfHu{margin:0 auto}.desc_pfHu :deep(a){font-weight:500;text-decoration-style:dotted;transition:color .25s}.links_A3uT{height:56px}.sp-link_GRPb{align-items:center;background-color:var(--ifm-f-white);font-size:14px;font-weight:500;padding:16px;text-align:center;transition:color .25s,background-color .25s}.buttonGroup_ZDer button,.codeBlockContainer_sxZ3{background:var(--prism-background-color);color:var(--prism-color)}.sp-icon_KrGn{height:16px;margin-right:8px;width:16px;fill:currentColor}.codeBlockContainer_sxZ3{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_PcXS{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_nb7L{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_ebfI{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_nb7L+.codeBlockContent_PcXS .codeBlock_ebfI{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_EHvg{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_eKzc{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup_ZDer{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup_ZDer button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup_ZDer button:focus-visible,.buttonGroup_ZDer button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup_ZDer button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_XYFh{counter-increment:a;display:table-row}.codeLineNumber_tjKH{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_tjKH:before{content:counter(a);opacity:.4}.codeLineContent_lN4y{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_hJ2C{opacity:1!important}.copyButtonIcons_Ct8L{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_GZTQ,.copyButtonSuccessIcon_T5sy{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_T5sy{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_hJ2C .copyButtonIcon_GZTQ{opacity:0;transform:scale(.33)}.copyButtonCopied_hJ2C .copyButtonSuccessIcon_T5sy{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Ci1R{height:1.2rem;width:1.2rem}.tag_JExC{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_JExC:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_MOku{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_FS3W{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_FS3W:after,.tagWithCount_FS3W:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_FS3W:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_FS3W:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_FS3W span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_CtbC{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit__IaR{margin-right:.3em;vertical-align:sub}.details_rMme{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_rMme>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_rMme>summary::-webkit-details-marker{display:none}.details_rMme>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_ytpx{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.lastUpdated_OWKO{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_Sv08{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_Sv08:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_dtI0:after,.tocCollapsibleExpanded_Sf07{transform:none}.tocCollapsible_zMfc{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_UQzg>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_UQzg ul li{margin:.4rem .8rem}.details_KMmw{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_bW6b{list-style:none}.img_JMIO{height:auto}.tableOfContents_b1mW{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.admonition_o2ui{margin-bottom:1em}.admonitionHeading_N477{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);text-transform:uppercase}.admonitionHeading_N477:not(:last-child){margin-bottom:.3rem}.admonitionIcon_F2Ur{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_F2Ur svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.breadcrumbHomeIcon_Jne1{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_mp_f{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:375px){.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}}@media (min-width:640px){.container{max-width:640px}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:block{display:block}.sm\:w-40{width:10rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-6{padding-bottom:1.5rem;padding-top:1.5rem}.sm\:pr-4{padding-right:1rem}.sm\:pt-12{padding-top:3rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}.sm\:text-base{font-size:1rem;line-height:1.5rem}.dialog-container[data-v-3926b6c7]{padding:1.5rem}.chat-input[data-v-3926b6c7]{font-size:.875rem;line-height:1.25rem}.result-not-found[data-v-3926b6c7]{padding-left:3.5rem;padding-right:3.5rem}.kbd[data-v-3926b6c7]{margin-left:.5rem;margin-right:.5rem}}@media (min-width:768px){.container{max-width:768px}.md\:order-1{order:1}.md\:order-2{order:2}.md\:col-span-1{grid-column:span 1/span 1}.md\:mt-0{margin-top:0}.button-placeholder[data-v-3926b6c7],.md\:block{display:block}.md\:w-auto{width:auto}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:gap-x-12{column-gap:3rem}.dialog-container[data-v-3926b6c7]{padding:5rem}.documate-button[data-v-956ba6e9]{background:var(--dm-color-bg-alt);border:1px solid #0000;border-radius:.5rem;color:var(--dm-color-hint);font-size:var(--dm-button-font-size);margin-left:2rem}.documate-button .icon[data-v-956ba6e9]{height:var(--dm-button-font-size);margin-right:.2rem}.documate-button[data-v-956ba6e9]:hover{border-color:var(--dm-color-brand)}}@media (min-width:997px){.collapseSidebarButton_igfI,.expandButton_vGLF{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_iOKh,.announcementBarPlaceholder_ZgHP{flex-basis:50px}.collapseSidebarButton_igfI{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_pubN{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_QmVd,[dir=rtl] .collapseSidebarButtonIcon_pubN{transform:rotate(0)}.collapseSidebarButton_igfI:focus,.collapseSidebarButton_igfI:hover,.expandButton_vGLF:focus,.expandButton_vGLF:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_b_C4{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SxoK{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SxoK{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_gAO5{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_Ivoc{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_WgKC{padding-top:0}.sidebarHidden_pHNJ{opacity:0;visibility:hidden}.sidebarLogo_XkDA{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_XkDA img{height:2rem;margin-right:.5rem}.expandButton_vGLF{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_QmVd{transform:rotate(180deg)}.docSidebarContainer_wnoZ{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_t3U5{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Epar{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_HtRu{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_qW8z{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_snhy{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.navbarSearchContainer_ws2C{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_OWKO{text-align:right}.tocMobile_KbWK{display:none}.docItemCol_qVdH{max-width:75%!important}}@media (min-width:1024px){.container{max-width:1024px}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:row-start-2{grid-row-start:2}.lg\:h-auto{height:auto}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:justify-end{justify-content:flex-end}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-8{padding-bottom:2rem;padding-top:2rem}.lg\:pt-20{padding-top:5rem}.lg\:text-6xl{font-size:3.75rem;line-height:1}.lg\:text-base{font-size:1rem;line-height:1.5rem}.lg\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (min-width:1536px){.container{max-width:1536px}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_QPtE,.footer__link-separator,.navbar__item,.sidebar_Ap_S,.tableOfContents_b1mW{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_ws2C{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_Ji2I{padding:0 .3rem}}@media only screen and (max-width:996px){.searchQueryColumn_D6kq,.searchResultsColumn_cM4p{max-width:60%!important}.searchLogoColumn_f4et,.searchVersionColumn_hUs4{max-width:40%!important}.searchLogoColumn_f4et{padding-left:0!important}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:768px){div[class^=announcementBar_]{height:calc(var(--ifm-announcementBar-height) + 12px)}.navbar__items .documate-button,.navbar__link{display:none!important}.dialog-panel[data-v-3926b6c7]{margin-top:2rem}.powered-by[data-v-3926b6c7]{margin-top:.2rem}.progress-bar-container_Btve,.progress-bar-inner-container_RjNy{height:30px}.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_BZZK{font-size:2rem}}@media screen and (max-width:576px){.searchQueryColumn_D6kq{max-width:100%!important}.searchVersionColumn_hUs4{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@media (max-width:454px){.footer[data-v-3926b6c7]{justify-content:center}}@media (hover:hover){.backToTopButton_jRRJ:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-color-scheme:dark){.dark\:border-white\/5{border-color:#ffffff0d}.dark\:bg-\[rgb\(2\2c 2\2c 2\)\]{--tw-bg-opacity:1;background-color:rgb(2 2 2/var(--tw-bg-opacity))}.dark\:bg-black\/40{background-color:#0006}.dark\:bg-neutral-900{--tw-bg-opacity:1;background-color:rgb(23 23 23/var(--tw-bg-opacity))}.dark\:bg-transparent{background-color:initial}.dark\:via-white\/80{--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#fffc var(--tw-gradient-via-position),var(--tw-gradient-to)}.dark\:text-neutral-400\/50{color:#a3a3a380}.dark\:after\:bg-transparent:after,.dark\:before\:bg-transparent:before{background-color:initial;content:var(--tw-content)}.dark\:hover\:bg-neutral-800:hover{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity))}.hover\:dark\:text-neutral-400:hover{--tw-text-opacity:1;color:rgb(163 163 163/var(--tw-text-opacity))}:root{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-mask-bg-color:#656c85cc;--dm-divider-color:#2e2e32;--dm-highlight-color:var(--dm-color-brand)}.hljs{background:#0d1117;color:#c9d1d9}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{background-color:#033a16;color:#aff5b4}.hljs-deletion{background-color:#67060c;color:#ffdcd7}}@media (prefers-color-scheme:light){.hljs{background:#fff;color:#24292e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{background-color:#f0fff4;color:#22863a}.hljs-deletion{background-color:#ffeef0;color:#b31d28}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_NAgQ,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_KbWK{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_EHvg{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/js/020197f0.43d79d54.js b/assets/js/020197f0.43d79d54.js deleted file mode 100644 index 3d5d22205..000000000 --- a/assets/js/020197f0.43d79d54.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6122],{8604:(s,e,n)=>{n.r(e),n.d(e,{assets:()=>t,contentTitle:()=>c,default:()=>a,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var i=n(6070),r=n(5710);const l={},c="Overview",o={id:"plugins/official-plugins/overview",title:"Overview",description:"Farm officially provides a lot of useful plugins, including Rust plugins and JS plugins. Rust plugins are much faster than Js plugins, we recommend to use Rust plugins whenever possible.",source:"@site/docs/plugins/official-plugins/overview.md",sourceDirName:"plugins/official-plugins",slug:"/plugins/official-plugins/overview",permalink:"/docs/plugins/official-plugins/overview",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/plugins/official-plugins/overview.md",tags:[],version:"current",frontMatter:{},sidebar:"pluginSidebar",next:{title:"@farmfe/plugin-react",permalink:"/docs/plugins/official-plugins/react"}},t={},d=[{value:"Rust Plugins",id:"rust-plugins",level:2},{value:"Js Plugins",id:"js-plugins",level:2},{value:"Community Plugins",id:"community-plugins",level:2}];function u(s){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.R)(),...s.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"overview",children:"Overview"}),"\n",(0,i.jsx)(e.p,{children:"Farm officially provides a lot of useful plugins, including Rust plugins and JS plugins. Rust plugins are much faster than Js plugins, we recommend to use Rust plugins whenever possible."}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["Refer to ",(0,i.jsx)(e.a,{href:"/docs/using-plugins",children:"Using Plugins"})," for how to use plugins in Farm."]})}),"\n",(0,i.jsx)(e.h2,{id:"rust-plugins",children:"Rust Plugins"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./react",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-react"})})}),"\uff1aSupport React ",(0,i.jsx)(e.code,{children:"jsx"})," and ",(0,i.jsx)(e.code,{children:"react-refresh"}),"."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./sass",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-sass"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"sass/scss"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./strip",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-strip"})})}),"\uff1aA Farm rust plugin to remove ",(0,i.jsx)(e.code,{children:"debugger"})," statements and functions like ",(0,i.jsx)(e.code,{children:"assert.equal"})," and ",(0,i.jsx)(e.code,{children:"console.log"})," from your code."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./dsv",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-dsv"})})}),"\uff1aA Farm plugin which converts ",(0,i.jsx)(e.code,{children:".csv"})," and ",(0,i.jsx)(e.code,{children:".tsv"})," files into JavaScript modules."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./yaml",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-yaml"})})}),"\uff1aA Farm plugin which Converts YAML files to ES6 modules."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./virtual",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-virtual"})})}),"\uff1aA rust plugin for farm to easily use virtual module."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./react-components",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-react-components"})})}),"\uff1aOn-demand components auto importing for React."]}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"js-plugins",children:"Js Plugins"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-postcss",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-postcss"})})}),"\uff1aSupport ",(0,i.jsx)(e.code,{children:"postcss"})," in your project."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-less",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-less"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"less"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-svgr",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-svgr"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"svg"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-dts",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-dts"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"*.d.ts"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-sass",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-sass"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"sass/scss"})," files."]}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"community-plugins",children:"Community Plugins"}),"\n",(0,i.jsxs)(e.p,{children:["If official plugins doesn't meet your needs, you can try ",(0,i.jsx)(e.a,{href:"../community-plugins",children:"Community Plugins"})]}),"\n",(0,i.jsxs)(e.p,{children:["And of course check out ",(0,i.jsx)(e.a,{href:"https://github.com/farm-fe/awesome-farm",children:"awesome-farm"})," - you can also submit a PR to list your plugins there."]})]})}function a(s={}){const{wrapper:e}={...(0,r.R)(),...s.components};return e?(0,i.jsx)(e,{...s,children:(0,i.jsx)(u,{...s})}):u(s)}},5710:(s,e,n)=>{n.d(e,{R:()=>c,x:()=>o});var i=n(758);const r={},l=i.createContext(r);function c(s){const e=i.useContext(l);return i.useMemo((function(){return"function"==typeof s?s(e):{...e,...s}}),[e,s])}function o(s){let e;return e=s.disableParentContext?"function"==typeof s.components?s.components(r):s.components||r:c(s.components),i.createElement(l.Provider,{value:e},s.children)}}}]); \ No newline at end of file diff --git a/assets/js/020197f0.9793c73a.js b/assets/js/020197f0.9793c73a.js new file mode 100644 index 000000000..5f25359ca --- /dev/null +++ b/assets/js/020197f0.9793c73a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6122],{119:(s,e,n)=>{n.r(e),n.d(e,{assets:()=>t,contentTitle:()=>c,default:()=>a,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var i=n(6070),r=n(5710);const l={},c="Overview",o={id:"plugins/official-plugins/overview",title:"Overview",description:"Farm officially provides a lot of useful plugins, including Rust plugins and JS plugins. Rust plugins are much faster than Js plugins, we recommend to use Rust plugins whenever possible.",source:"@site/docs/plugins/official-plugins/overview.md",sourceDirName:"plugins/official-plugins",slug:"/plugins/official-plugins/overview",permalink:"/docs/plugins/official-plugins/overview",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/plugins/official-plugins/overview.md",tags:[],version:"current",frontMatter:{},sidebar:"pluginSidebar",next:{title:"@farmfe/plugin-react",permalink:"/docs/plugins/official-plugins/react"}},t={},d=[{value:"Rust Plugins",id:"rust-plugins",level:2},{value:"Js Plugins",id:"js-plugins",level:2},{value:"Community Plugins",id:"community-plugins",level:2}];function u(s){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.R)(),...s.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"overview",children:"Overview"}),"\n",(0,i.jsx)(e.p,{children:"Farm officially provides a lot of useful plugins, including Rust plugins and JS plugins. Rust plugins are much faster than Js plugins, we recommend to use Rust plugins whenever possible."}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["Refer to ",(0,i.jsx)(e.a,{href:"/docs/using-plugins",children:"Using Plugins"})," for how to use plugins in Farm."]})}),"\n",(0,i.jsx)(e.h2,{id:"rust-plugins",children:"Rust Plugins"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./react",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-react"})})}),"\uff1aSupport React ",(0,i.jsx)(e.code,{children:"jsx"})," and ",(0,i.jsx)(e.code,{children:"react-refresh"}),"."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./sass",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-sass"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"sass/scss"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./strip",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-strip"})})}),"\uff1aA Farm rust plugin to remove ",(0,i.jsx)(e.code,{children:"debugger"})," statements and functions like ",(0,i.jsx)(e.code,{children:"assert.equal"})," and ",(0,i.jsx)(e.code,{children:"console.log"})," from your code."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./dsv",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-dsv"})})}),"\uff1aA Farm plugin which converts ",(0,i.jsx)(e.code,{children:".csv"})," and ",(0,i.jsx)(e.code,{children:".tsv"})," files into JavaScript modules."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./yaml",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-yaml"})})}),"\uff1aA Farm plugin which Converts YAML files to ES6 modules."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./virtual",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-virtual"})})}),"\uff1aA rust plugin for farm to easily use virtual module."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./react-components",children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-react-components"})})}),"\uff1aOn-demand components auto importing for React."]}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"js-plugins",children:"Js Plugins"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-postcss",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-postcss"})})}),"\uff1aSupport ",(0,i.jsx)(e.code,{children:"postcss"})," in your project."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-less",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-less"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"less"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-svgr",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-svgr"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"svg"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-dts",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-dts"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"*.d.ts"})," files."]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.a,{href:"./js-sass",children:(0,i.jsx)(e.code,{children:"@farmfe/js-plugin-sass"})})}),"\uff1aSupport compiling ",(0,i.jsx)(e.code,{children:"sass/scss"})," files."]}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"community-plugins",children:"Community Plugins"}),"\n",(0,i.jsxs)(e.p,{children:["If official plugins doesn't meet your needs, you can try ",(0,i.jsx)(e.a,{href:"../community-plugins",children:"Community Plugins"})]}),"\n",(0,i.jsxs)(e.p,{children:["And of course check out ",(0,i.jsx)(e.a,{href:"https://github.com/farm-fe/awesome-farm",children:"awesome-farm"})," - you can also submit a PR to list your plugins there."]})]})}function a(s={}){const{wrapper:e}={...(0,r.R)(),...s.components};return e?(0,i.jsx)(e,{...s,children:(0,i.jsx)(u,{...s})}):u(s)}},5710:(s,e,n)=>{n.d(e,{R:()=>c,x:()=>o});var i=n(758);const r={},l=i.createContext(r);function c(s){const e=i.useContext(l);return i.useMemo((function(){return"function"==typeof s?s(e):{...e,...s}}),[e,s])}function o(s){let e;return e=s.disableParentContext?"function"==typeof s.components?s.components(r):s.components||r:c(s.components),i.createElement(l.Provider,{value:e},s.children)}}}]); \ No newline at end of file diff --git a/assets/js/028ba8ce.8381917d.js b/assets/js/028ba8ce.aa3e167e.js similarity index 99% rename from assets/js/028ba8ce.8381917d.js rename to assets/js/028ba8ce.aa3e167e.js index 9e63d3afc..d3a2837a3 100644 --- a/assets/js/028ba8ce.8381917d.js +++ b/assets/js/028ba8ce.aa3e167e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[7072],{7266:(s,e,n)=>{n.r(e),n.d(e,{assets:()=>t,contentTitle:()=>l,default:()=>p,frontMatter:()=>i,metadata:()=>c,toc:()=>a});var o=n(6070),r=n(5710);const i={},l="Css/Sass/Less",c={id:"features/css",title:"Css/Sass/Less",description:"Farm support Css out of box, just import the css file:",source:"@site/docs/features/css.md",sourceDirName:"features",slug:"/features/css",permalink:"/docs/features/css",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/features/css.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Html",permalink:"/docs/features/html"},next:{title:"TS/TSX",permalink:"/docs/features/script"}},t={},a=[{value:"Css Modules",id:"css-modules",level:2},{value:"Css Pre-Processor",id:"css-pre-processor",level:2},{value:"Sass",id:"sass",level:3},{value:"Less",id:"less",level:3},{value:"Postcss",id:"postcss",level:3},{value:"Css Prefixer",id:"css-prefixer",level:2}];function d(s){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",...(0,r.R)(),...s.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(e.h1,{id:"csssassless",children:"Css/Sass/Less"}),"\n",(0,o.jsx)(e.p,{children:"Farm support Css out of box, just import the css file:"}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-tsx",children:"import './index.css';\n"})}),"\n",(0,o.jsx)(e.p,{children:"Then farm will auto enable HMR for css module, and generating bundled resources for css."}),"\n",(0,o.jsx)(e.h2,{id:"css-modules",children:"Css Modules"}),"\n",(0,o.jsxs)(e.p,{children:["Farm support css modules out of box, the modules end with ",(0,o.jsx)(e.code,{children:".module.css|less|scss|sass"})," will be treated as css modules by default."]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-tsx",metastring:'title="comp.tsx"',children:"// ...\nimport styles from './index.module.css'\n\nexport function Comp() {\n return
Main
\n}\n"})}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-css",metastring:'title="index.module.css"',children:".main {\n color: green;\n}\n"})}),"\n",(0,o.jsxs)(e.p,{children:["You can configuring css modules by ",(0,o.jsx)(e.a,{href:"/docs/config/compilation-options#cssmodules",children:(0,o.jsx)(e.code,{children:"css.modules"})}),". for example you can set ",(0,o.jsx)(e.code,{children:"css.modules.paths"})," to ",(0,o.jsx)(e.code,{children:"['.css|sass|less|scss']"})," then all css files will be treated as css modules."]}),"\n",(0,o.jsx)(e.h2,{id:"css-pre-processor",children:"Css Pre-Processor"}),"\n",(0,o.jsx)(e.p,{children:"Farm provide official sass, less, postcss plugins to support css pre-processor."}),"\n",(0,o.jsx)(e.h3,{id:"sass",children:"Sass"}),"\n",(0,o.jsxs)(e.p,{children:["Farm sass plugin is a Rust Plugin and use ",(0,o.jsx)(e.code,{children:"sass-embeded"}),"(we may migrate to ",(0,o.jsx)(e.a,{href:"https://github.com/connorskees/grass",children:"grass"})," in the future)."]}),"\n",(0,o.jsxs)(e.p,{children:["Steps to compile ",(0,o.jsx)(e.code,{children:"sass/scss"})," modules in Farm."]}),"\n",(0,o.jsxs)(e.ol,{children:["\n",(0,o.jsx)(e.li,{children:"Install dependencies"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-sh",children:"# npm or yarn or pnpm, choose your favorite package manager\npnpm add -D @farmfe/plugin-sass\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"2",children:["\n",(0,o.jsx)(e.li,{children:"Configure the plugin"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n // ...\n plugins: ['@farmfe/plugin-sass'] // to use a rust plugin, just configure its package name as a string\n // if you want to specify options for plugin-sass, use\n // plugins: [\n // ['@farmfe/plugin-sass', { sourceMap: false }]\n // ]\n});\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"3",children:["\n",(0,o.jsx)(e.li,{children:"Import sass module"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import './index.scss';\n"})}),"\n",(0,o.jsxs)(e.p,{children:["To use sass with css modules, change the file name from ",(0,o.jsx)(e.code,{children:"index.scss"})," to ",(0,o.jsx)(e.code,{children:"index.module.scss"}),", see ",(0,o.jsx)(e.a,{href:"/docs/config/farm-config#cssmodules",children:"css modules"}),"."]}),"\n",(0,o.jsxs)(e.p,{children:[(0,o.jsx)(e.code,{children:"@farmfe/plugin-sass"})," supports a lot of options, use the array syntax of ",(0,o.jsx)(e.code,{children:"plugins"})," to specify options for plugin sass:"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n // if you want to specify options for plugin-sass, use\n plugins: [\n [\n '@farmfe/plugin-sass',\n // all supported options as below\n {\n sourceMap: true // bool\n sourceMapIncludeSources: true, // bool\n alertAscii: true, // bool\n alertColor: true, // bool\n charset: true, // bool\n quietDeps: true, // bool\n verbose: false, // bool\n style: 'expanded' | 'compressed' // output code style\n }\n ]\n ]\n});\n"})}),"\n",(0,o.jsx)(e.h3,{id:"less",children:"Less"}),"\n",(0,o.jsxs)(e.p,{children:["Farm less plugin is a Js Plugin. Steps to compile ",(0,o.jsx)(e.code,{children:"less"})," modules in Farm."]}),"\n",(0,o.jsxs)(e.ol,{children:["\n",(0,o.jsx)(e.li,{children:"Install dependencies"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-sh",children:"# npm or yarn or pnpm, choose your favorite package manager\npnpm add -D @farmfe/js-plugin-less\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"2",children:["\n",(0,o.jsx)(e.li,{children:"Configure the plugin"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\nimport less from '@farmfe/js-plugin-less';\n\nexport default defineConfig({\n // ...\n plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options\n});\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"3",children:["\n",(0,o.jsx)(e.li,{children:"Import sass module"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import './index.less';\n"})}),"\n",(0,o.jsxs)(e.p,{children:["To use sass with css modules, change the file name from ",(0,o.jsx)(e.code,{children:"index.less"})," to ",(0,o.jsx)(e.code,{children:"index.module.less"}),", see ",(0,o.jsx)(e.a,{href:"/docs/config/farm-config#cssmodules",children:"css modules"})]}),"\n",(0,o.jsx)(e.h3,{id:"postcss",children:"Postcss"}),"\n",(0,o.jsx)(e.p,{children:"The Farm postcss plugin is a JS plugin. The steps to introduce postcss in Farm are as follows:"}),"\n",(0,o.jsxs)(e.ol,{children:["\n",(0,o.jsx)(e.li,{children:"Install dependencies"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-sh",children:"# npm or yarn or pnpm, choose your favorite package manager\npnpm add -D @farmfe/js-plugin-postcss\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"2",children:["\n",(0,o.jsx)(e.li,{children:"Configure the plugin"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\nimport postcss from '@farmfe/js-plugin-postcss';\n\nexport default defineConfig({\n //...\n plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options\n});\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"3",children:["\n",(0,o.jsxs)(e.li,{children:["Configure ",(0,o.jsx)(e.code,{children:"postcss.config.js"})," and import the required postcss plugins"]}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-js",metastring:"title=postcss.config.js",children:"module.exports = {\n plugins: [\n require('postcss-pxtorem')({\n rootValue: 16,\n propList: ['*'],\n }),\n require('tailwindcss'),\n ]\n}\n"})}),"\n",(0,o.jsx)(e.h2,{id:"css-prefixer",children:"Css Prefixer"}),"\n",(0,o.jsxs)(e.p,{children:["Farm supports css prefixer out of box, you can configure it using ",(0,o.jsx)(e.code,{children:"compilation.css.prefixer"}),"."]}),"\n",(0,o.jsx)(e.admonition,{type:"note",children:(0,o.jsxs)(e.p,{children:[(0,o.jsx)(e.code,{children:"css.prefix.targets"})," will be set automatically when ",(0,o.jsx)(e.a,{href:"/docs/config/compilation-options#output-targetenv",children:(0,o.jsx)(e.code,{children:"output.targetEnv"})}),". Normally set ",(0,o.jsx)(e.a,{href:"/docs/config/compilation-options#output-targetenv",children:(0,o.jsx)(e.code,{children:"output.targetEnv"})})," would be enough."]})}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n css: {\n prefix: {\n targets: ['ie >= 10']\n }\n },\n },\n});\n"})}),"\n",(0,o.jsx)(e.p,{children:"Then for input code:"}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-css",children:"div {\n display: flex;\n}\n"})}),"\n",(0,o.jsx)(e.p,{children:"output code:"}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-css",children:"div{display:-ms-flexbox;display:flex}\n"})})]})}function p(s={}){const{wrapper:e}={...(0,r.R)(),...s.components};return e?(0,o.jsx)(e,{...s,children:(0,o.jsx)(d,{...s})}):d(s)}},5710:(s,e,n)=>{n.d(e,{R:()=>l,x:()=>c});var o=n(758);const r={},i=o.createContext(r);function l(s){const e=o.useContext(i);return o.useMemo((function(){return"function"==typeof s?s(e):{...e,...s}}),[e,s])}function c(s){let e;return e=s.disableParentContext?"function"==typeof s.components?s.components(r):s.components||r:l(s.components),o.createElement(i.Provider,{value:e},s.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[7072],{4655:(s,e,n)=>{n.r(e),n.d(e,{assets:()=>t,contentTitle:()=>l,default:()=>p,frontMatter:()=>i,metadata:()=>c,toc:()=>a});var o=n(6070),r=n(5710);const i={},l="Css/Sass/Less",c={id:"features/css",title:"Css/Sass/Less",description:"Farm support Css out of box, just import the css file:",source:"@site/docs/features/css.md",sourceDirName:"features",slug:"/features/css",permalink:"/docs/features/css",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/features/css.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Html",permalink:"/docs/features/html"},next:{title:"TS/TSX",permalink:"/docs/features/script"}},t={},a=[{value:"Css Modules",id:"css-modules",level:2},{value:"Css Pre-Processor",id:"css-pre-processor",level:2},{value:"Sass",id:"sass",level:3},{value:"Less",id:"less",level:3},{value:"Postcss",id:"postcss",level:3},{value:"Css Prefixer",id:"css-prefixer",level:2}];function d(s){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",...(0,r.R)(),...s.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(e.h1,{id:"csssassless",children:"Css/Sass/Less"}),"\n",(0,o.jsx)(e.p,{children:"Farm support Css out of box, just import the css file:"}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-tsx",children:"import './index.css';\n"})}),"\n",(0,o.jsx)(e.p,{children:"Then farm will auto enable HMR for css module, and generating bundled resources for css."}),"\n",(0,o.jsx)(e.h2,{id:"css-modules",children:"Css Modules"}),"\n",(0,o.jsxs)(e.p,{children:["Farm support css modules out of box, the modules end with ",(0,o.jsx)(e.code,{children:".module.css|less|scss|sass"})," will be treated as css modules by default."]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-tsx",metastring:'title="comp.tsx"',children:"// ...\nimport styles from './index.module.css'\n\nexport function Comp() {\n return
Main
\n}\n"})}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-css",metastring:'title="index.module.css"',children:".main {\n color: green;\n}\n"})}),"\n",(0,o.jsxs)(e.p,{children:["You can configuring css modules by ",(0,o.jsx)(e.a,{href:"/docs/config/compilation-options#cssmodules",children:(0,o.jsx)(e.code,{children:"css.modules"})}),". for example you can set ",(0,o.jsx)(e.code,{children:"css.modules.paths"})," to ",(0,o.jsx)(e.code,{children:"['.css|sass|less|scss']"})," then all css files will be treated as css modules."]}),"\n",(0,o.jsx)(e.h2,{id:"css-pre-processor",children:"Css Pre-Processor"}),"\n",(0,o.jsx)(e.p,{children:"Farm provide official sass, less, postcss plugins to support css pre-processor."}),"\n",(0,o.jsx)(e.h3,{id:"sass",children:"Sass"}),"\n",(0,o.jsxs)(e.p,{children:["Farm sass plugin is a Rust Plugin and use ",(0,o.jsx)(e.code,{children:"sass-embeded"}),"(we may migrate to ",(0,o.jsx)(e.a,{href:"https://github.com/connorskees/grass",children:"grass"})," in the future)."]}),"\n",(0,o.jsxs)(e.p,{children:["Steps to compile ",(0,o.jsx)(e.code,{children:"sass/scss"})," modules in Farm."]}),"\n",(0,o.jsxs)(e.ol,{children:["\n",(0,o.jsx)(e.li,{children:"Install dependencies"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-sh",children:"# npm or yarn or pnpm, choose your favorite package manager\npnpm add -D @farmfe/plugin-sass\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"2",children:["\n",(0,o.jsx)(e.li,{children:"Configure the plugin"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n // ...\n plugins: ['@farmfe/plugin-sass'] // to use a rust plugin, just configure its package name as a string\n // if you want to specify options for plugin-sass, use\n // plugins: [\n // ['@farmfe/plugin-sass', { sourceMap: false }]\n // ]\n});\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"3",children:["\n",(0,o.jsx)(e.li,{children:"Import sass module"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import './index.scss';\n"})}),"\n",(0,o.jsxs)(e.p,{children:["To use sass with css modules, change the file name from ",(0,o.jsx)(e.code,{children:"index.scss"})," to ",(0,o.jsx)(e.code,{children:"index.module.scss"}),", see ",(0,o.jsx)(e.a,{href:"/docs/config/farm-config#cssmodules",children:"css modules"}),"."]}),"\n",(0,o.jsxs)(e.p,{children:[(0,o.jsx)(e.code,{children:"@farmfe/plugin-sass"})," supports a lot of options, use the array syntax of ",(0,o.jsx)(e.code,{children:"plugins"})," to specify options for plugin sass:"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n // if you want to specify options for plugin-sass, use\n plugins: [\n [\n '@farmfe/plugin-sass',\n // all supported options as below\n {\n sourceMap: true // bool\n sourceMapIncludeSources: true, // bool\n alertAscii: true, // bool\n alertColor: true, // bool\n charset: true, // bool\n quietDeps: true, // bool\n verbose: false, // bool\n style: 'expanded' | 'compressed' // output code style\n }\n ]\n ]\n});\n"})}),"\n",(0,o.jsx)(e.h3,{id:"less",children:"Less"}),"\n",(0,o.jsxs)(e.p,{children:["Farm less plugin is a Js Plugin. Steps to compile ",(0,o.jsx)(e.code,{children:"less"})," modules in Farm."]}),"\n",(0,o.jsxs)(e.ol,{children:["\n",(0,o.jsx)(e.li,{children:"Install dependencies"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-sh",children:"# npm or yarn or pnpm, choose your favorite package manager\npnpm add -D @farmfe/js-plugin-less\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"2",children:["\n",(0,o.jsx)(e.li,{children:"Configure the plugin"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\nimport less from '@farmfe/js-plugin-less';\n\nexport default defineConfig({\n // ...\n plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options\n});\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"3",children:["\n",(0,o.jsx)(e.li,{children:"Import sass module"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import './index.less';\n"})}),"\n",(0,o.jsxs)(e.p,{children:["To use sass with css modules, change the file name from ",(0,o.jsx)(e.code,{children:"index.less"})," to ",(0,o.jsx)(e.code,{children:"index.module.less"}),", see ",(0,o.jsx)(e.a,{href:"/docs/config/farm-config#cssmodules",children:"css modules"})]}),"\n",(0,o.jsx)(e.h3,{id:"postcss",children:"Postcss"}),"\n",(0,o.jsx)(e.p,{children:"The Farm postcss plugin is a JS plugin. The steps to introduce postcss in Farm are as follows:"}),"\n",(0,o.jsxs)(e.ol,{children:["\n",(0,o.jsx)(e.li,{children:"Install dependencies"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-sh",children:"# npm or yarn or pnpm, choose your favorite package manager\npnpm add -D @farmfe/js-plugin-postcss\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"2",children:["\n",(0,o.jsx)(e.li,{children:"Configure the plugin"}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\nimport postcss from '@farmfe/js-plugin-postcss';\n\nexport default defineConfig({\n //...\n plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options\n});\n"})}),"\n",(0,o.jsxs)(e.ol,{start:"3",children:["\n",(0,o.jsxs)(e.li,{children:["Configure ",(0,o.jsx)(e.code,{children:"postcss.config.js"})," and import the required postcss plugins"]}),"\n"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-js",metastring:"title=postcss.config.js",children:"module.exports = {\n plugins: [\n require('postcss-pxtorem')({\n rootValue: 16,\n propList: ['*'],\n }),\n require('tailwindcss'),\n ]\n}\n"})}),"\n",(0,o.jsx)(e.h2,{id:"css-prefixer",children:"Css Prefixer"}),"\n",(0,o.jsxs)(e.p,{children:["Farm supports css prefixer out of box, you can configure it using ",(0,o.jsx)(e.code,{children:"compilation.css.prefixer"}),"."]}),"\n",(0,o.jsx)(e.admonition,{type:"note",children:(0,o.jsxs)(e.p,{children:[(0,o.jsx)(e.code,{children:"css.prefix.targets"})," will be set automatically when ",(0,o.jsx)(e.a,{href:"/docs/config/compilation-options#output-targetenv",children:(0,o.jsx)(e.code,{children:"output.targetEnv"})}),". Normally set ",(0,o.jsx)(e.a,{href:"/docs/config/compilation-options#output-targetenv",children:(0,o.jsx)(e.code,{children:"output.targetEnv"})})," would be enough."]})}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n css: {\n prefix: {\n targets: ['ie >= 10']\n }\n },\n },\n});\n"})}),"\n",(0,o.jsx)(e.p,{children:"Then for input code:"}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-css",children:"div {\n display: flex;\n}\n"})}),"\n",(0,o.jsx)(e.p,{children:"output code:"}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-css",children:"div{display:-ms-flexbox;display:flex}\n"})})]})}function p(s={}){const{wrapper:e}={...(0,r.R)(),...s.components};return e?(0,o.jsx)(e,{...s,children:(0,o.jsx)(d,{...s})}):d(s)}},5710:(s,e,n)=>{n.d(e,{R:()=>l,x:()=>c});var o=n(758);const r={},i=o.createContext(r);function l(s){const e=o.useContext(i);return o.useMemo((function(){return"function"==typeof s?s(e):{...e,...s}}),[e,s])}function c(s){let e;return e=s.disableParentContext?"function"==typeof s.components?s.components(r):s.components||r:l(s.components),o.createElement(i.Provider,{value:e},s.children)}}}]); \ No newline at end of file diff --git a/assets/js/04848b18.dae9c2f3.js b/assets/js/04848b18.b41ee959.js similarity index 94% rename from assets/js/04848b18.dae9c2f3.js rename to assets/js/04848b18.b41ee959.js index 64b3096c0..0480230b8 100644 --- a/assets/js/04848b18.dae9c2f3.js +++ b/assets/js/04848b18.b41ee959.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[8682],{2232:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>d,contentTitle:()=>c,default:()=>h,frontMatter:()=>i,metadata:()=>u,toc:()=>p});var t=n(6070),r=n(5710),l=n(6792),o=n(3916),a=n(9329);const i={},c="@farmfe/js-plugin-postcss",u={id:"plugins/official-plugins/js-postcss",title:"@farmfe/js-plugin-postcss",description:"Support postcss for Farm.",source:"@site/docs/plugins/official-plugins/js-postcss.mdx",sourceDirName:"plugins/official-plugins",slug:"/plugins/official-plugins/js-postcss",permalink:"/docs/plugins/official-plugins/js-postcss",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/plugins/official-plugins/js-postcss.mdx",tags:[],version:"current",frontMatter:{},sidebar:"pluginSidebar",previous:{title:"@farmfe/plugin-react-components",permalink:"/docs/plugins/official-plugins/react-components"},next:{title:"@farmfe/js-plugin-less",permalink:"/docs/plugins/official-plugins/js-less"}},d={},p=[{value:"Installation",id:"installation",level:2},{value:"Usage",id:"usage",level:2},{value:"Options",id:"options",level:2},{value:"postcssLoadConfig",id:"postcssloadconfig",level:3},{value:"filters",id:"filters",level:3},{value:"implementation",id:"implementation",level:3}];function f(e){const s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.h1,{id:"farmfejs-plugin-postcss",children:"@farmfe/js-plugin-postcss"}),"\n",(0,t.jsxs)(s.p,{children:["Support ",(0,t.jsx)(s.code,{children:"postcss"})," for Farm."]}),"\n",(0,t.jsx)(s.h2,{id:"installation",children:"Installation"}),"\n",(0,t.jsxs)(o.A,{children:[(0,t.jsx)(a.A,{value:"npm",label:"npm",children:(0,t.jsx)(l.A,{children:"npm install @farmfe/js-plugin-postcss postcss"})}),(0,t.jsx)(a.A,{value:"yarn",label:"yarn",children:(0,t.jsx)(l.A,{children:"yarn add @farmfe/js-plugin-postcss postcss"})}),(0,t.jsx)(a.A,{value:"pnpm",label:"pnpm",children:(0,t.jsx)(l.A,{children:"pnpm add @farmfe/js-plugin-postcss postcss"})})]}),"\n",(0,t.jsx)(s.h2,{id:"usage",children:"Usage"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",metastring:"{2,6}",children:"import { UserConfig } from '@farmfe/core';\nimport farmJsPluginPostcss from '@farmfe/js-plugin-postcss';\n\nconst config: UserConfig = {\n plugins: [\n farmJsPluginPostcss({ /* options */ })\n ]\n}\n"})}),"\n",(0,t.jsx)(s.h2,{id:"options",children:"Options"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",children:"export type PostcssPluginOptions = {\n /**\n * @default undefined\n * postcss-load-config options. path default to farm.config.js root.\n */\n postcssLoadConfig?: {\n ctx?: postcssLoadConfig.ConfigContext;\n path?: string;\n options?: Parameters[2];\n };\n filters?: {\n resolvedPaths?: string[];\n moduleTypes?: string[];\n };\n implementation?: string;\n};\n\n"})}),"\n",(0,t.jsx)(s.h3,{id:"postcssloadconfig",children:"postcssLoadConfig"}),"\n",(0,t.jsxs)(s.p,{children:["Farm uses ",(0,t.jsx)(s.code,{children:"postcss-load-config"})," to load ",(0,t.jsx)(s.code,{children:"postcss"})," config, so you can use ",(0,t.jsx)(s.code,{children:"postcss-load-config"}),"'s options. Refer to ",(0,t.jsx)(s.a,{href:"https://github.com/postcss/postcss-load-config",children:"postcss-load-config"}),"."]}),"\n",(0,t.jsx)(s.p,{children:"Example:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",children:"import path from 'node:path';\nimport { UserConfig } from '@farmfe/core';\nimport farmJsPluginPostcss from '@farmfe/js-plugin-postcss';\n\nconst config: UserConfig = {\n plugins: [\n farmJsPluginPostcss({\n postcssLoadConfig: {\n // load config from client/postcss.config.js\n path: path.join(process.cwd(), 'client')\n }\n })\n ]\n}\n\nexport default config;\n"})}),"\n",(0,t.jsx)(s.h3,{id:"filters",children:"filters"}),"\n",(0,t.jsxs)(s.p,{children:["Which files should be processed by ",(0,t.jsx)(s.code,{children:"postcss"}),". default to ",(0,t.jsx)(s.code,{children:"{ moduleTypes: ['css'] }"}),"."]}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"resolvedPaths"}),": Only files under these paths will be processed. Support regex."]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"moduleTypes"}),": Only files with these module types will be processed. note that less/sass files should be processed by ",(0,t.jsx)(s.code,{children:"@farmfe/js-plugin-less"}),"/",(0,t.jsx)(s.code,{children:"@farmfe/plugin-sass"})," first."]}),"\n"]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"resolvedPaths"})," and ",(0,t.jsx)(s.code,{children:"moduleTypes"})," are unioned, which means files match any of them will be processed."]}),"\n",(0,t.jsx)(s.p,{children:"Example:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",children:"import { UserConfig } from '@farmfe/core';\nimport farmJsPluginPostcss from '@farmfe/js-plugin-postcss';\n\nconst config: UserConfig = {\n plugins: [\n farmJsPluginPostcss({\n filters: {\n // all files end with .custom-css will be processed\n resolvedPaths: ['\\\\.custom-css$'],\n moduleTypes: ['css']\n }\n })\n ]\n}\n\nexport default config;\n"})}),"\n",(0,t.jsx)(s.h3,{id:"implementation",children:"implementation"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"implementation"})," package name of ",(0,t.jsx)(s.code,{children:"postcss"}),". Default to ",(0,t.jsx)(s.code,{children:"postcss"}),"."]})]})}function h(e={}){const{wrapper:s}={...(0,r.R)(),...e.components};return s?(0,t.jsx)(s,{...e,children:(0,t.jsx)(f,{...e})}):f(e)}},9329:(e,s,n)=>{n.d(s,{A:()=>o});n(758);var t=n(3526);const r={tabItem:"tabItem_iV9q"};var l=n(6070);function o(e){let{children:s,hidden:n,className:o}=e;return(0,l.jsx)("div",{role:"tabpanel",className:(0,t.A)(r.tabItem,o),hidden:n,children:s})}},3916:(e,s,n)=>{n.d(s,{A:()=>w});var t=n(758),r=n(3526),l=n(5841),o=n(5557),a=n(2044),i=n(6906),c=n(7299),u=n(1040);function d(e){return t.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,t.isValidElement)(e)&&function(e){const{props:s}=e;return!!s&&"object"==typeof s&&"value"in s}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function p(e){const{values:s,children:n}=e;return(0,t.useMemo)((()=>{const e=s??function(e){return d(e).map((e=>{let{props:{value:s,label:n,attributes:t,default:r}}=e;return{value:s,label:n,attributes:t,default:r}}))}(n);return function(e){const s=(0,c.X)(e,((e,s)=>e.value===s.value));if(s.length>0)throw new Error(`Docusaurus error: Duplicate values "${s.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[s,n])}function f(e){let{value:s,tabValues:n}=e;return n.some((e=>e.value===s))}function h(e){let{queryString:s=!1,groupId:n}=e;const r=(0,o.W6)(),l=function(e){let{queryString:s=!1,groupId:n}=e;if("string"==typeof s)return s;if(!1===s)return null;if(!0===s&&!n)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:s,groupId:n});return[(0,i.aZ)(l),(0,t.useCallback)((e=>{if(!l)return;const s=new URLSearchParams(r.location.search);s.set(l,e),r.replace({...r.location,search:s.toString()})}),[l,r])]}function m(e){const{defaultValue:s,queryString:n=!1,groupId:r}=e,l=p(e),[o,i]=(0,t.useState)((()=>function(e){let{defaultValue:s,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the component requires at least one children component");if(s){if(!f({value:s,tabValues:n}))throw new Error(`Docusaurus error: The has a defaultValue "${s}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return s}const t=n.find((e=>e.default))??n[0];if(!t)throw new Error("Unexpected error: 0 tabValues");return t.value}({defaultValue:s,tabValues:l}))),[c,d]=h({queryString:n,groupId:r}),[m,g]=function(e){let{groupId:s}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(s),[r,l]=(0,u.Dv)(n);return[r,(0,t.useCallback)((e=>{n&&l.set(e)}),[n,l])]}({groupId:r}),j=(()=>{const e=c??m;return f({value:e,tabValues:l})?e:null})();(0,a.A)((()=>{j&&i(j)}),[j]);return{selectedValue:o,selectValue:(0,t.useCallback)((e=>{if(!f({value:e,tabValues:l}))throw new Error(`Can't select invalid tab value=${e}`);i(e),d(e),g(e)}),[d,g,l]),tabValues:l}}var g=n(5736);const j={tabList:"tabList_DbQE",tabItem:"tabItem_h4wM"};var b=n(6070);function x(e){let{className:s,block:n,selectedValue:t,selectValue:o,tabValues:a}=e;const i=[],{blockElementScrollPositionUntilNextRender:c}=(0,l.a_)(),u=e=>{const s=e.currentTarget,n=i.indexOf(s),r=a[n].value;r!==t&&(c(s),o(r))},d=e=>{let s=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{const n=i.indexOf(e.currentTarget)+1;s=i[n]??i[0];break}case"ArrowLeft":{const n=i.indexOf(e.currentTarget)-1;s=i[n]??i[i.length-1];break}}s?.focus()};return(0,b.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":n},s),children:a.map((e=>{let{value:s,label:n,attributes:l}=e;return(0,b.jsx)("li",{role:"tab",tabIndex:t===s?0:-1,"aria-selected":t===s,ref:e=>i.push(e),onKeyDown:d,onClick:u,...l,className:(0,r.A)("tabs__item",j.tabItem,l?.className,{"tabs__item--active":t===s}),children:n??s},s)}))})}function v(e){let{lazy:s,children:n,selectedValue:r}=e;const l=(Array.isArray(n)?n:[n]).filter(Boolean);if(s){const e=l.find((e=>e.props.value===r));return e?(0,t.cloneElement)(e,{className:"margin-top--md"}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:l.map(((e,s)=>(0,t.cloneElement)(e,{key:s,hidden:e.props.value!==r})))})}function y(e){const s=m(e);return(0,b.jsxs)("div",{className:(0,r.A)("tabs-container",j.tabList),children:[(0,b.jsx)(x,{...s,...e}),(0,b.jsx)(v,{...s,...e})]})}function w(e){const s=(0,g.A)();return(0,b.jsx)(y,{...e,children:d(e.children)},String(s))}}}]); \ No newline at end of file +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[8682],{3405:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>d,contentTitle:()=>c,default:()=>h,frontMatter:()=>i,metadata:()=>u,toc:()=>p});var t=n(6070),r=n(5710),l=n(3907),o=n(2688),a=n(7070);const i={},c="@farmfe/js-plugin-postcss",u={id:"plugins/official-plugins/js-postcss",title:"@farmfe/js-plugin-postcss",description:"Support postcss for Farm.",source:"@site/docs/plugins/official-plugins/js-postcss.mdx",sourceDirName:"plugins/official-plugins",slug:"/plugins/official-plugins/js-postcss",permalink:"/docs/plugins/official-plugins/js-postcss",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/plugins/official-plugins/js-postcss.mdx",tags:[],version:"current",frontMatter:{},sidebar:"pluginSidebar",previous:{title:"@farmfe/plugin-react-components",permalink:"/docs/plugins/official-plugins/react-components"},next:{title:"@farmfe/js-plugin-less",permalink:"/docs/plugins/official-plugins/js-less"}},d={},p=[{value:"Installation",id:"installation",level:2},{value:"Usage",id:"usage",level:2},{value:"Options",id:"options",level:2},{value:"postcssLoadConfig",id:"postcssloadconfig",level:3},{value:"filters",id:"filters",level:3},{value:"implementation",id:"implementation",level:3}];function f(e){const s={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.h1,{id:"farmfejs-plugin-postcss",children:"@farmfe/js-plugin-postcss"}),"\n",(0,t.jsxs)(s.p,{children:["Support ",(0,t.jsx)(s.code,{children:"postcss"})," for Farm."]}),"\n",(0,t.jsx)(s.h2,{id:"installation",children:"Installation"}),"\n",(0,t.jsxs)(o.A,{children:[(0,t.jsx)(a.A,{value:"npm",label:"npm",children:(0,t.jsx)(l.A,{children:"npm install @farmfe/js-plugin-postcss postcss"})}),(0,t.jsx)(a.A,{value:"yarn",label:"yarn",children:(0,t.jsx)(l.A,{children:"yarn add @farmfe/js-plugin-postcss postcss"})}),(0,t.jsx)(a.A,{value:"pnpm",label:"pnpm",children:(0,t.jsx)(l.A,{children:"pnpm add @farmfe/js-plugin-postcss postcss"})})]}),"\n",(0,t.jsx)(s.h2,{id:"usage",children:"Usage"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",metastring:"{2,6}",children:"import { UserConfig } from '@farmfe/core';\nimport farmJsPluginPostcss from '@farmfe/js-plugin-postcss';\n\nconst config: UserConfig = {\n plugins: [\n farmJsPluginPostcss({ /* options */ })\n ]\n}\n"})}),"\n",(0,t.jsx)(s.h2,{id:"options",children:"Options"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",children:"export type PostcssPluginOptions = {\n /**\n * @default undefined\n * postcss-load-config options. path default to farm.config.js root.\n */\n postcssLoadConfig?: {\n ctx?: postcssLoadConfig.ConfigContext;\n path?: string;\n options?: Parameters[2];\n };\n filters?: {\n resolvedPaths?: string[];\n moduleTypes?: string[];\n };\n implementation?: string;\n};\n\n"})}),"\n",(0,t.jsx)(s.h3,{id:"postcssloadconfig",children:"postcssLoadConfig"}),"\n",(0,t.jsxs)(s.p,{children:["Farm uses ",(0,t.jsx)(s.code,{children:"postcss-load-config"})," to load ",(0,t.jsx)(s.code,{children:"postcss"})," config, so you can use ",(0,t.jsx)(s.code,{children:"postcss-load-config"}),"'s options. Refer to ",(0,t.jsx)(s.a,{href:"https://github.com/postcss/postcss-load-config",children:"postcss-load-config"}),"."]}),"\n",(0,t.jsx)(s.p,{children:"Example:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",children:"import path from 'node:path';\nimport { UserConfig } from '@farmfe/core';\nimport farmJsPluginPostcss from '@farmfe/js-plugin-postcss';\n\nconst config: UserConfig = {\n plugins: [\n farmJsPluginPostcss({\n postcssLoadConfig: {\n // load config from client/postcss.config.js\n path: path.join(process.cwd(), 'client')\n }\n })\n ]\n}\n\nexport default config;\n"})}),"\n",(0,t.jsx)(s.h3,{id:"filters",children:"filters"}),"\n",(0,t.jsxs)(s.p,{children:["Which files should be processed by ",(0,t.jsx)(s.code,{children:"postcss"}),". default to ",(0,t.jsx)(s.code,{children:"{ moduleTypes: ['css'] }"}),"."]}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"resolvedPaths"}),": Only files under these paths will be processed. Support regex."]}),"\n",(0,t.jsxs)(s.li,{children:[(0,t.jsx)(s.code,{children:"moduleTypes"}),": Only files with these module types will be processed. note that less/sass files should be processed by ",(0,t.jsx)(s.code,{children:"@farmfe/js-plugin-less"}),"/",(0,t.jsx)(s.code,{children:"@farmfe/plugin-sass"})," first."]}),"\n"]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"resolvedPaths"})," and ",(0,t.jsx)(s.code,{children:"moduleTypes"})," are unioned, which means files match any of them will be processed."]}),"\n",(0,t.jsx)(s.p,{children:"Example:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ts",children:"import { UserConfig } from '@farmfe/core';\nimport farmJsPluginPostcss from '@farmfe/js-plugin-postcss';\n\nconst config: UserConfig = {\n plugins: [\n farmJsPluginPostcss({\n filters: {\n // all files end with .custom-css will be processed\n resolvedPaths: ['\\\\.custom-css$'],\n moduleTypes: ['css']\n }\n })\n ]\n}\n\nexport default config;\n"})}),"\n",(0,t.jsx)(s.h3,{id:"implementation",children:"implementation"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"implementation"})," package name of ",(0,t.jsx)(s.code,{children:"postcss"}),". Default to ",(0,t.jsx)(s.code,{children:"postcss"}),"."]})]})}function h(e={}){const{wrapper:s}={...(0,r.R)(),...e.components};return s?(0,t.jsx)(s,{...e,children:(0,t.jsx)(f,{...e})}):f(e)}},7070:(e,s,n)=>{n.d(s,{A:()=>o});n(758);var t=n(3526);const r={tabItem:"tabItem_FKkE"};var l=n(6070);function o(e){let{children:s,hidden:n,className:o}=e;return(0,l.jsx)("div",{role:"tabpanel",className:(0,t.A)(r.tabItem,o),hidden:n,children:s})}},2688:(e,s,n)=>{n.d(s,{A:()=>w});var t=n(758),r=n(3526),l=n(2317),o=n(5557),a=n(1349),i=n(2895),c=n(3908),u=n(7235);function d(e){return t.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,t.isValidElement)(e)&&function(e){const{props:s}=e;return!!s&&"object"==typeof s&&"value"in s}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function p(e){const{values:s,children:n}=e;return(0,t.useMemo)((()=>{const e=s??function(e){return d(e).map((e=>{let{props:{value:s,label:n,attributes:t,default:r}}=e;return{value:s,label:n,attributes:t,default:r}}))}(n);return function(e){const s=(0,c.X)(e,((e,s)=>e.value===s.value));if(s.length>0)throw new Error(`Docusaurus error: Duplicate values "${s.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[s,n])}function f(e){let{value:s,tabValues:n}=e;return n.some((e=>e.value===s))}function h(e){let{queryString:s=!1,groupId:n}=e;const r=(0,o.W6)(),l=function(e){let{queryString:s=!1,groupId:n}=e;if("string"==typeof s)return s;if(!1===s)return null;if(!0===s&&!n)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:s,groupId:n});return[(0,i.aZ)(l),(0,t.useCallback)((e=>{if(!l)return;const s=new URLSearchParams(r.location.search);s.set(l,e),r.replace({...r.location,search:s.toString()})}),[l,r])]}function m(e){const{defaultValue:s,queryString:n=!1,groupId:r}=e,l=p(e),[o,i]=(0,t.useState)((()=>function(e){let{defaultValue:s,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the component requires at least one children component");if(s){if(!f({value:s,tabValues:n}))throw new Error(`Docusaurus error: The has a defaultValue "${s}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return s}const t=n.find((e=>e.default))??n[0];if(!t)throw new Error("Unexpected error: 0 tabValues");return t.value}({defaultValue:s,tabValues:l}))),[c,d]=h({queryString:n,groupId:r}),[m,g]=function(e){let{groupId:s}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(s),[r,l]=(0,u.Dv)(n);return[r,(0,t.useCallback)((e=>{n&&l.set(e)}),[n,l])]}({groupId:r}),j=(()=>{const e=c??m;return f({value:e,tabValues:l})?e:null})();(0,a.A)((()=>{j&&i(j)}),[j]);return{selectedValue:o,selectValue:(0,t.useCallback)((e=>{if(!f({value:e,tabValues:l}))throw new Error(`Can't select invalid tab value=${e}`);i(e),d(e),g(e)}),[d,g,l]),tabValues:l}}var g=n(3639);const j={tabList:"tabList_u0Lq",tabItem:"tabItem_jY3I"};var b=n(6070);function x(e){let{className:s,block:n,selectedValue:t,selectValue:o,tabValues:a}=e;const i=[],{blockElementScrollPositionUntilNextRender:c}=(0,l.a_)(),u=e=>{const s=e.currentTarget,n=i.indexOf(s),r=a[n].value;r!==t&&(c(s),o(r))},d=e=>{let s=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{const n=i.indexOf(e.currentTarget)+1;s=i[n]??i[0];break}case"ArrowLeft":{const n=i.indexOf(e.currentTarget)-1;s=i[n]??i[i.length-1];break}}s?.focus()};return(0,b.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":n},s),children:a.map((e=>{let{value:s,label:n,attributes:l}=e;return(0,b.jsx)("li",{role:"tab",tabIndex:t===s?0:-1,"aria-selected":t===s,ref:e=>i.push(e),onKeyDown:d,onClick:u,...l,className:(0,r.A)("tabs__item",j.tabItem,l?.className,{"tabs__item--active":t===s}),children:n??s},s)}))})}function v(e){let{lazy:s,children:n,selectedValue:r}=e;const l=(Array.isArray(n)?n:[n]).filter(Boolean);if(s){const e=l.find((e=>e.props.value===r));return e?(0,t.cloneElement)(e,{className:"margin-top--md"}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:l.map(((e,s)=>(0,t.cloneElement)(e,{key:s,hidden:e.props.value!==r})))})}function y(e){const s=m(e);return(0,b.jsxs)("div",{className:(0,r.A)("tabs-container",j.tabList),children:[(0,b.jsx)(x,{...s,...e}),(0,b.jsx)(v,{...s,...e})]})}function w(e){const s=(0,g.A)();return(0,b.jsx)(y,{...e,children:d(e.children)},String(s))}}}]); \ No newline at end of file diff --git a/assets/js/0572f99d.91ed7efa.js b/assets/js/0572f99d.7cd4cd2a.js similarity index 98% rename from assets/js/0572f99d.91ed7efa.js rename to assets/js/0572f99d.7cd4cd2a.js index 6e3593b75..e455a0ee9 100644 --- a/assets/js/0572f99d.91ed7efa.js +++ b/assets/js/0572f99d.7cd4cd2a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6565],{5248:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var t=s(6070),i=s(5710);const a={},r="Tree Shake",l={id:"features/tree-shake",title:"Tree Shake",description:"Farm supports Tree Shake, which is automatically enabled in the default Production environment. It can be turned on or off by the compilation.treeShake option.",source:"@site/versioned_docs/version-0.x/features/tree-shake.md",sourceDirName:"features",slug:"/features/tree-shake",permalink:"/docs/0.x/features/tree-shake",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/versioned_docs/version-0.x/features/tree-shake.md",tags:[],version:"0.x",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Source Map",permalink:"/docs/0.x/features/sourcemap"},next:{title:"Minification",permalink:"/docs/0.x/features/minification"}},o={},c=[{value:"Configuring Tree Shake",id:"configuring-tree-shake",level:2},{value:"Deal With Side Effects",id:"deal-with-side-effects",level:2}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"tree-shake",children:"Tree Shake"}),"\n",(0,t.jsxs)(n.p,{children:["Farm supports Tree Shake, which is automatically enabled in the default Production environment. It can be turned on or off by the ",(0,t.jsx)(n.code,{children:"compilation.treeShake"})," option."]}),"\n",(0,t.jsx)(n.p,{children:"During Tree Shake, the sideEffects field in package.json will be automatically read, and modules with sideEffects will not perform Tree Shake."}),"\n",(0,t.jsx)(n.admonition,{type:"note",children:(0,t.jsx)(n.p,{children:"Farm will treat all circularly dependent modules as sideEffects and will not perform Tree Shake. Please try to avoid circular dependencies in your project."})}),"\n",(0,t.jsx)(n.p,{children:"Tree shake example:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1, b2 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\nexport b2 = "B2";\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"a.js"})," is entry and it imports ",(0,t.jsx)(n.code,{children:"b.js"}),", after tree shaking, the result is:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"b2"})," is not used and will be removed in both ",(0,t.jsx)(n.code,{children:"a.js"})," and ",(0,t.jsx)(n.code,{children:"b.js"})]}),"\n",(0,t.jsx)(n.h2,{id:"configuring-tree-shake",children:"Configuring Tree Shake"}),"\n",(0,t.jsxs)(n.p,{children:["Tree Shake is enabled in production mode by default, to disable tree shake, use ",(0,t.jsx)(n.code,{children:"compilation.treeShake"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default {\n compilation: {\n treeShake: false,\n },\n};\n"})}),"\n",(0,t.jsx)(n.h2,{id:"deal-with-side-effects",children:"Deal With Side Effects"}),"\n",(0,t.jsxs)(n.p,{children:["When a module contains ",(0,t.jsx)(n.code,{children:"side effects"}),", Farm won't apply tree shake for it, and all of its imported and exports are treated as used. Farm will think following modules have ",(0,t.jsx)(n.code,{children:"side effects"}),":"]}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsx)(n.li,{children:"CommonJs modules always have side effects."}),"\n",(0,t.jsxs)(n.li,{children:["A module contains ",(0,t.jsx)(n.code,{children:"self-executed"})," statement at global scope has side effects"]}),"\n",(0,t.jsx)(n.li,{children:"Modules that contains cyclic dependencies has side effects"}),"\n",(0,t.jsxs)(n.li,{children:["Modules matches ",(0,t.jsx)(n.code,{children:"sideEffects"})," config in its closest ",(0,t.jsx)(n.code,{children:"package.json"})]}),"\n",(0,t.jsx)(n.li,{children:"Entry modules are always has side effects."}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Example 1:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"const a = require('./')\nmodule.exports = a;\n"})}),"\n",(0,t.jsx)(n.p,{children:"CommonJs module are always has side effects."}),"\n",(0,t.jsx)(n.p,{children:"Example 2:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"import a from './';\n\na();\n"})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"a()"})," is executed at global scope and we treat it as side effect."]}),"\n",(0,t.jsx)(n.p,{children:"Example 3:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"// a.js\nimport b from './b.js'\n\n// b.js\nimport a from './a.js'\n"})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"a"}),", ",(0,t.jsx)(n.code,{children:"b"})," are cyclic dependencies, so they will be treated as side effects too."]}),"\n",(0,t.jsx)(n.p,{children:"Example 4:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",metastring:'title="package.json"',children:'{\n "name": "my-package",\n "sideEffects": [\n "./global/**.ts"\n ]\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["all ts modules under ",(0,t.jsx)(n.code,{children:"global/"})," are treat as side effects."]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},5710:(e,n,s)=>{s.d(n,{R:()=>r,x:()=>l});var t=s(758);const i={},a=t.createContext(i);function r(e){const n=t.useContext(a);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6565],{7683:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var t=s(6070),i=s(5710);const a={},r="Tree Shake",l={id:"features/tree-shake",title:"Tree Shake",description:"Farm supports Tree Shake, which is automatically enabled in the default Production environment. It can be turned on or off by the compilation.treeShake option.",source:"@site/versioned_docs/version-0.x/features/tree-shake.md",sourceDirName:"features",slug:"/features/tree-shake",permalink:"/docs/0.x/features/tree-shake",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/versioned_docs/version-0.x/features/tree-shake.md",tags:[],version:"0.x",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Source Map",permalink:"/docs/0.x/features/sourcemap"},next:{title:"Minification",permalink:"/docs/0.x/features/minification"}},o={},c=[{value:"Configuring Tree Shake",id:"configuring-tree-shake",level:2},{value:"Deal With Side Effects",id:"deal-with-side-effects",level:2}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"tree-shake",children:"Tree Shake"}),"\n",(0,t.jsxs)(n.p,{children:["Farm supports Tree Shake, which is automatically enabled in the default Production environment. It can be turned on or off by the ",(0,t.jsx)(n.code,{children:"compilation.treeShake"})," option."]}),"\n",(0,t.jsx)(n.p,{children:"During Tree Shake, the sideEffects field in package.json will be automatically read, and modules with sideEffects will not perform Tree Shake."}),"\n",(0,t.jsx)(n.admonition,{type:"note",children:(0,t.jsx)(n.p,{children:"Farm will treat all circularly dependent modules as sideEffects and will not perform Tree Shake. Please try to avoid circular dependencies in your project."})}),"\n",(0,t.jsx)(n.p,{children:"Tree shake example:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1, b2 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\nexport b2 = "B2";\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"a.js"})," is entry and it imports ",(0,t.jsx)(n.code,{children:"b.js"}),", after tree shaking, the result is:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"b2"})," is not used and will be removed in both ",(0,t.jsx)(n.code,{children:"a.js"})," and ",(0,t.jsx)(n.code,{children:"b.js"})]}),"\n",(0,t.jsx)(n.h2,{id:"configuring-tree-shake",children:"Configuring Tree Shake"}),"\n",(0,t.jsxs)(n.p,{children:["Tree Shake is enabled in production mode by default, to disable tree shake, use ",(0,t.jsx)(n.code,{children:"compilation.treeShake"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default {\n compilation: {\n treeShake: false,\n },\n};\n"})}),"\n",(0,t.jsx)(n.h2,{id:"deal-with-side-effects",children:"Deal With Side Effects"}),"\n",(0,t.jsxs)(n.p,{children:["When a module contains ",(0,t.jsx)(n.code,{children:"side effects"}),", Farm won't apply tree shake for it, and all of its imported and exports are treated as used. Farm will think following modules have ",(0,t.jsx)(n.code,{children:"side effects"}),":"]}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsx)(n.li,{children:"CommonJs modules always have side effects."}),"\n",(0,t.jsxs)(n.li,{children:["A module contains ",(0,t.jsx)(n.code,{children:"self-executed"})," statement at global scope has side effects"]}),"\n",(0,t.jsx)(n.li,{children:"Modules that contains cyclic dependencies has side effects"}),"\n",(0,t.jsxs)(n.li,{children:["Modules matches ",(0,t.jsx)(n.code,{children:"sideEffects"})," config in its closest ",(0,t.jsx)(n.code,{children:"package.json"})]}),"\n",(0,t.jsx)(n.li,{children:"Entry modules are always has side effects."}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Example 1:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"const a = require('./')\nmodule.exports = a;\n"})}),"\n",(0,t.jsx)(n.p,{children:"CommonJs module are always has side effects."}),"\n",(0,t.jsx)(n.p,{children:"Example 2:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"import a from './';\n\na();\n"})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"a()"})," is executed at global scope and we treat it as side effect."]}),"\n",(0,t.jsx)(n.p,{children:"Example 3:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"// a.js\nimport b from './b.js'\n\n// b.js\nimport a from './a.js'\n"})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"a"}),", ",(0,t.jsx)(n.code,{children:"b"})," are cyclic dependencies, so they will be treated as side effects too."]}),"\n",(0,t.jsx)(n.p,{children:"Example 4:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",metastring:'title="package.json"',children:'{\n "name": "my-package",\n "sideEffects": [\n "./global/**.ts"\n ]\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["all ts modules under ",(0,t.jsx)(n.code,{children:"global/"})," are treat as side effects."]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},5710:(e,n,s)=>{s.d(n,{R:()=>r,x:()=>l});var t=s(758);const i={},a=t.createContext(i);function r(e){const n=t.useContext(a);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/07c371a9.3bc108df.js b/assets/js/07c371a9.0d396445.js similarity index 99% rename from assets/js/07c371a9.3bc108df.js rename to assets/js/07c371a9.0d396445.js index 38e995609..b4c8a1e57 100644 --- a/assets/js/07c371a9.3bc108df.js +++ b/assets/js/07c371a9.0d396445.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[4764],{9986:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>a});var i=t(6070),s=t(5710);const r={sidebar_position:1},o="Html",l={id:"features/html",title:"Html",description:"Basic Usage",source:"@site/versioned_docs/version-0.x/features/html.md",sourceDirName:"features",slug:"/features/html",permalink:"/docs/0.x/features/html",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/versioned_docs/version-0.x/features/html.md",tags:[],version:"0.x",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Build For Production",permalink:"/docs/0.x/tutorials/build"},next:{title:"Css",permalink:"/docs/0.x/features/css"}},c={},a=[{value:"Basic Usage",id:"basic-usage",level:2},{value:"Multi Page App",id:"multi-page-app",level:2},{value:"Inherit html template",id:"inherit-html-template",level:2}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"html",children:"Html"}),"\n",(0,i.jsx)(n.h2,{id:"basic-usage",children:"Basic Usage"}),"\n",(0,i.jsxs)(n.p,{children:["Farm support compile Html out of box, ",(0,i.jsx)(n.strong,{children:"and you should use Html as entry when build a web project"}),", for example:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'import type { defineConfig } from "@farmfe/core";\n\nexport default defineConfig({\n input: {\n index: "./index.html", // using ./index.html as entry\n },\n});\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["If the input is not specified, default to ",(0,i.jsx)(n.code,{children:"{ index: 'index.html' }"}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["and in ",(0,i.jsx)(n.code,{children:"./index.html"}),", a ",(0,i.jsx)(n.code,{children:' - + + + - + \ No newline at end of file diff --git a/blog/atom.xml b/blog/atom.xml index 5665e83dc..107fb75cd 100644 --- a/blog/atom.xml +++ b/blog/atom.xml @@ -2,7 +2,7 @@ https://farmfe.org/blog Farm Blog - 2024-07-23T01:07:06.000Z + 2024-07-29T06:04:31.000Z https://github.com/jpmonette/feed Farm Blog @@ -11,8 +11,8 @@ <![CDATA[Blob]]> https://farmfe.org/blog/index - 2024-07-23T01:07:06.000Z + 2024-07-29T06:04:31.000Z - 2024]]> + 2024]]> \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index 62614ed6f..63eaceff0 100644 --- a/blog/index.html +++ b/blog/index.html @@ -3,16 +3,16 @@ -Blog | Farm +Blog | Farm - - - + + + -

Blob

· One min read

2024

+

Blob

· One min read

2024

\ No newline at end of file diff --git a/blog/index/index.html b/blog/index/index.html index a312a137b..48443b10a 100644 --- a/blog/index/index.html +++ b/blog/index/index.html @@ -3,16 +3,16 @@ -Blob | Farm +Blob | Farm - - - + + + -

Blob

· One min read

2024

+

Blob

· One min read

2024

\ No newline at end of file diff --git a/blog/rss.xml b/blog/rss.xml index 9a26af829..015ab747a 100644 --- a/blog/rss.xml +++ b/blog/rss.xml @@ -4,7 +4,7 @@ Farm Blog https://farmfe.org/blog Farm Blog - Tue, 23 Jul 2024 01:07:06 GMT + Mon, 29 Jul 2024 06:04:31 GMT https://validator.w3.org/feed/docs/rss2.html https://github.com/jpmonette/feed en @@ -12,9 +12,9 @@ <![CDATA[Blob]]> https://farmfe.org/blog/index https://farmfe.org/blog/index - Tue, 23 Jul 2024 01:07:06 GMT + Mon, 29 Jul 2024 06:04:31 GMT - 2024]]> + 2024]]> \ No newline at end of file diff --git a/data/index.html b/data/index.html index ec86f7a11..661667edd 100644 --- a/data/index.html +++ b/data/index.html @@ -8,9 +8,9 @@ - - - + + +
diff --git a/docs/0.x/api/hmr-api/index.html b/docs/0.x/api/hmr-api/index.html index d12c20bbb..e2d892300 100644 --- a/docs/0.x/api/hmr-api/index.html +++ b/docs/0.x/api/hmr-api/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/docs/0.x/api/javascript-api/index.html b/docs/0.x/api/javascript-api/index.html index 3c7a3a134..6992f45f6 100644 --- a/docs/0.x/api/javascript-api/index.html +++ b/docs/0.x/api/javascript-api/index.html @@ -8,11 +8,11 @@ - - - + + + -
+
\ No newline at end of file diff --git a/docs/0.x/api/js-plugin-api/index.html b/docs/0.x/api/js-plugin-api/index.html index c9eb65d8a..42ab3934c 100644 --- a/docs/0.x/api/js-plugin-api/index.html +++ b/docs/0.x/api/js-plugin-api/index.html @@ -8,11 +8,11 @@ - - - + + + -
+
\ No newline at end of file diff --git a/docs/0.x/api/rust-api/index.html b/docs/0.x/api/rust-api/index.html index 2c5fd146c..e39bca3eb 100644 --- a/docs/0.x/api/rust-api/index.html +++ b/docs/0.x/api/rust-api/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/docs/0.x/api/rust-plugin-api/index.html b/docs/0.x/api/rust-plugin-api/index.html index 86a09a543..0507ace61 100644 --- a/docs/0.x/api/rust-plugin-api/index.html +++ b/docs/0.x/api/rust-plugin-api/index.html @@ -8,11 +8,11 @@ - - - + + + -
Version: 0.15

Rust Plugin Api

+
Version: 0.15

Rust Plugin Api

\ No newline at end of file diff --git a/docs/0.x/benchmark/index.html b/docs/0.x/benchmark/index.html index 3d9626fd2..ed769ba05 100644 --- a/docs/0.x/benchmark/index.html +++ b/docs/0.x/benchmark/index.html @@ -8,24 +8,24 @@ - - - + + + -
Version: 0.15

Benchmarks

-

Introduction

+
Version: 0.15

Benchmarks

+

Introduction

Using Turbopack's bench cases (1000 React components), see https://turbo.build/pack/docs/benchmarks.

-

Run this benchmark yourself

+

Run this benchmark yourself

Test Repo:https://github.com/farm-fe/performance-compare

Test Machine(Linux Mint 21.1 Cinnamon, 11th Gen Intel© Core™ i5-11400 @ 2.60GHz × 6, 15.5 GiB)

-
# Install dependencies
pnpm install

# run benchmark
pnpm benchmark
-

Data

+
# Install dependencies
pnpm install

# run benchmark
pnpm benchmark
+

Data

StartupHMR (Root)HMR (Leaf)Production Build
Webpack8035ms345ms265ms11321ms
Vite3078ms35ms18ms2266ms
Rspack831ms104ms96ms724ms
Farm403ms11ms10ms288ms

-

metrics

+

metrics

  • Cold StartUp Time: The time it takes to develop a build without caching

    @@ -51,13 +51,13 @@

    metricsBenchmark for all metrics

    +

    Benchmark for all metrics

    -

    Benchmark of HMR

    +

    Benchmark of HMR

    -

    Benchmark of Startup

    +

    Benchmark of Startup

    -

    Benchmark of Production Build

    -
+

Benchmark of Production Build

+
\ No newline at end of file diff --git a/docs/0.x/cli/cli-api/index.html b/docs/0.x/cli/cli-api/index.html index 3e6776886..938663aaf 100644 --- a/docs/0.x/cli/cli-api/index.html +++ b/docs/0.x/cli/cli-api/index.html @@ -8,31 +8,31 @@ - - - + + + -
Version: 0.15

Farm CLI

+
Version: 0.15

Farm CLI

The Farm CLI allows you to start, build, preview, and watch your application.

To get a list of cli available to Farm, run the following command inside your command

-
Terminal
npx farm -h
+
Terminal
npx farm -h

The output look like this:

-
Terminal
farm/0.5.11

Usage:
$ farm [root]

Commands:
[root] Compile the project in dev mode and serve it with farm dev server
build compile the project in production mode
watch watch file change
preview compile the project in watch mode
clean [path] Clean up the cache built incrementally
plugin [command] Commands for manage plugins

For more info, run any command with the `--help` flag:
$ farm --help
$ farm build --help
$ farm watch --help
$ farm preview --help
$ farm clean --help
$ farm plugin --help

Options:
-l, --lazy lazyCompilation
--host <host> specify host
--port <port> specify port
--open open browser on server start
--hmr enable hot module replacement
--cors enable cors
--strictPort specified port is already in use, exit with error
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
-v, --version Display version number
-

Start

+
Terminal
farm/0.5.11

Usage:
$ farm [root]

Commands:
[root] Compile the project in dev mode and serve it with farm dev server
build compile the project in production mode
watch watch file change
preview compile the project in watch mode
clean [path] Clean up the cache built incrementally
plugin [command] Commands for manage plugins

For more info, run any command with the `--help` flag:
$ farm --help
$ farm build --help
$ farm watch --help
$ farm preview --help
$ farm clean --help
$ farm plugin --help

Options:
-l, --lazy lazyCompilation
--host <host> specify host
--port <port> specify port
--open open browser on server start
--hmr enable hot module replacement
--cors enable cors
--strictPort specified port is already in use, exit with error
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
-v, --version Display version number
+

Start

farm start The command is used to start the development server and compile the code in the development environment

-
Terminal
Usage:
$ farm [root]

Options:
-l, --lazy lazyCompilation
--host <host> specify host
--port <port> specify port
--open open browser on server start
--hmr enable hot module replacement
--cors enable cors
--strictPort specified port is already in use, exit with error
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-

Build

+
Terminal
Usage:
$ farm [root]

Options:
-l, --lazy lazyCompilation
--host <host> specify host
--port <port> specify port
--open open browser on server start
--hmr enable hot module replacement
--cors enable cors
--strictPort specified port is already in use, exit with error
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
+

Build

farm build The command builds the products that can be used in the production environment in the default dist directory.

-
Terminal
Usage:
$ farm build

Options:
-o, --outDir <dir> output directory
-i, --input <file> input file path
-w, --watch watch file change
--targetEnv <target> transpile targetEnv node, browser
--format <format> transpile format esm, commonjs
--sourcemap output source maps for build
--treeShaking Eliminate useless code without side effects
--minify code compression at build time
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
-

Preview

+
Terminal
Usage:
$ farm build

Options:
-o, --outDir <dir> output directory
-i, --input <file> input file path
-w, --watch watch file change
--targetEnv <target> transpile targetEnv node, browser
--format <format> transpile format esm, commonjs
--sourcemap output source maps for build
--treeShaking Eliminate useless code without side effects
--minify code compression at build time
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
+

Preview

farm preview the command for locally previewing the products built in your production environment, you need to execute farm build in advance to build the products in the production environment.

-
Terminal
Usage:
$ farm preview

Options:
--open [url] Whether to open the page in the browser at startup
--port <port> Set the port number for Server snooping
--host <host> Specify the host to listen to when Server starts
-c --config <config> Specify the profile path
-h, --help Show command help
-

Watch

+
Terminal
Usage:
$ farm preview

Options:
--open [url] Whether to open the page in the browser at startup
--port <port> Set the port number for Server snooping
--host <host> Specify the host to listen to when Server starts
-c --config <config> Specify the profile path
-h, --help Show command help
+

Watch

farm watch the command generally listen for file changes and rebuild in node environment

-
Terminal

Usage:
$ farm watch

Options:
--format <format> transpile format esm, commonjs
-o, --outDir <dir> output directory
-i, --input <file> input file path
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
-

Clean

+
Terminal

Usage:
$ farm watch

Options:
--format <format> transpile format esm, commonjs
-o, --outDir <dir> output directory
-i, --input <file> input file path
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
+

Clean

farm clean Because the incremental build provided by farm generates the cache file locally, you may need to clean up the cache file under certain circumstances (unpredictable compilation errors)

-
Terminal
Usage:
$ farm clean [path]

Options:
--recursive Recursively search for node_modules directories and clean them
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
+
Terminal
Usage:
$ farm clean [path]

Options:
--recursive Recursively search for node_modules directories and clean them
-c, --config <file> use specified config file
-m, --mode <mode> set env mode
--base <path> public base path
--clearScreen allow/disable clear screen when logging
-h, --help Display this message
\ No newline at end of file diff --git a/docs/0.x/concepts/index.html b/docs/0.x/concepts/index.html index 4ea893c2b..bdd011929 100644 --- a/docs/0.x/concepts/index.html +++ b/docs/0.x/concepts/index.html @@ -8,12 +8,12 @@ - - - + + + -
Version: 0.15

Concepts

+
Version: 0.15

Concepts

Farm is a build tool to transform and bundle your input to deployable resources. Farm will search modules start from the input, then construct a module graph and bundle these modules into several resources

Main Concepts:

    @@ -21,6 +21,6 @@
  • Output
  • Plugins
  • Partial Bundling
  • -
+
\ No newline at end of file diff --git a/docs/0.x/config/cli/index.html b/docs/0.x/config/cli/index.html index 04d5bad3f..5fb90f84d 100644 --- a/docs/0.x/config/cli/index.html +++ b/docs/0.x/config/cli/index.html @@ -8,27 +8,27 @@ - - - + + + -
Version: 0.15

CLI Options

-

create

+
Version: 0.15

CLI Options

+

create

Create a new Farm project.

-
pnpm create farm
# or npm create farm
# or yarn create farm
# choose your favorite package manager
+
pnpm create farm
# or npm create farm
# or yarn create farm
# choose your favorite package manager

Other commands are provided by package @farmfe/cli:

-

start

+

start

Start a dev server, compile the Farm project in development mode and watch file changes.

-
farm start
-

build

+
farm start
+

build

Build a Farm project in production mode

-
farm build
-

preview

+
farm build
+

preview

Preview the result of build command.

-
farm build && farm preview
-

watch

+
farm build && farm preview
+

watch

Watch is usually used to compile a library project, it works Like start command but it does not launch a dev server.

-
farm build
+
farm build
\ No newline at end of file diff --git a/docs/0.x/config/compilation-options/index.html b/docs/0.x/config/compilation-options/index.html index 0bffe604f..1a62fff91 100644 --- a/docs/0.x/config/compilation-options/index.html +++ b/docs/0.x/config/compilation-options/index.html @@ -8,29 +8,29 @@ - - - + + + -
Version: 0.15

Configuration Reference

+
Version: 0.15

Configuration Reference

By default, Farm reads the configuration from the farm.config.ts|js|mjs file in the project root directory, an example configuration file:

-
farm.config.ts
import { defineConfig } from "@farmfe/core";
export default defineConfig({
root: process.cwd(), // compiled root directory
// compile options
compilation: {
//...
},
// Dev Server options
server: {
hmr: true,
//...
},
// plugin configuration
plugins: [],
});
-

Compilation options - compilation

+
farm.config.ts
import { defineConfig } from "@farmfe/core";
export default defineConfig({
root: process.cwd(), // compiled root directory
// compile options
compilation: {
//...
},
// Dev Server options
server: {
hmr: true,
//...
},
// plugin configuration
plugins: [],
});
+

Compilation options - compilation

All compilation-related configuration is under the compilation field.

-

input

+

input

  • type: Record<string, string>

The entry point for the project. Input files can be html, ts/js/tsx/jsx, css or other files supported by plugins.

-
import { defineConfig } from "@farmfe/core";

export default defineConfig({
compilation: {
input: {
index: "./index.html",
about: "./about.html",
},
},
// ..
};
-

output

+
import { defineConfig } from "@farmfe/core";

export default defineConfig({
compilation: {
input: {
index: "./index.html",
about: "./about.html",
},
},
// ..
};
+

output

  • type: OutputOptions
-
interface OutputOptions {
// After partial bundling, the file name configuration of the resource where the entry file is located
entryFilename?: string;
// After partial bundling, other resources except the entry resource input file name configuration
filename?: string;
// output directory
path?: string;
// public path: resource loading prefix
publicPath?: string;
// Static resource file name configuration
assetsFilename?: string;
// Target execution environment, browser or Node
targetEnv?: "browser" | "node";
// output module format
format?: "cjs" | "esm";
}
-
note

We call the compiled result a resource

-

output.entryFilename

+
interface OutputOptions {
// After partial bundling, the file name configuration of the resource where the entry file is located
entryFilename?: string;
// After partial bundling, other resources except the entry resource input file name configuration
filename?: string;
// output directory
path?: string;
// public path: resource loading prefix
publicPath?: string;
// Static resource file name configuration
assetsFilename?: string;
// Target execution environment, browser or Node
targetEnv?: "browser" | "node";
// output module format
format?: "cjs" | "esm";
}
+
note

We call the compiled result a resource

+

output.entryFilename

  • default: "[entryName].[ext]"
@@ -41,7 +41,7 @@

ou
  • [contentHash]: The content hash of the resource.
  • [ext]: The extension of the resource, js for js/jsx/ts/tsx, css for css/scss/less.
  • -

    output.filename

    +

    output.filename

    • Default value: "[resourceName].[ext]"
    @@ -51,136 +51,136 @@

    output.
  • [contentHash]: The content hash of the resource.
  • [ext]: The extension of the resource, js for js/jsx/ts/tsx, css for css/scss/less.
  • -

    output.path

    +

    output.path

    • default: "dist"

    directory of output resources

    -

    output.publicPath

    +

    output.publicPath

    • Default value: "/"

    The resource url load prefix. For example URL https://xxxx, or a absolute path /xxx/.

    -

    output.assetsFileName

    +

    output.assetsFileName

    • Default value: "[resourceName].[ext]"

    The filename configuration for static resource output, the placeholder is the same as output.filename.

    -

    output. targetEnv

    +

    output. targetEnv

    • default: "browser"

    Configure the execution environment of the product, which can be "browser" or "node".

    -

    output. format

    +

    output. format

    • default: "esm"

    The format of the configuration product, which can be "esm" or "cjs".

    -
    note

    This option is only valid for Js products

    -

    resolve

    +
    note

    This option is only valid for Js products

    +

    resolve

    • type: ResolveOptions
    -
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    -

    resolve. extensions

    +
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    +

    resolve. extensions

    • default: ["tsx", "ts", "jsx", "js", "mjs", "json", "html", "css"]

    Configure the suffix when parsing dependencies. For example, when parsing ./index, if it is not resolved, the suffix parsing will be automatically added, such as trying ./index.tsx, ./index.css, etc.

    -

    resolve.alias

    +

    resolve.alias

    • Default value: {}

    Configure parsing alias, example:

    -
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });
    +
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });

    alias is prefix replacement, for the above example /@/pages will be replaced by /root/src/pages.

    If you want an exact match, you can add $, for example stream$ will only replace stream, but not stream/xxx.

    If you want to use regex, you can use $__farm_regex:, for example $__farm_regex:^/(utils)$ will replace /utils to /root/src/utils.

    -

    resolve. mainFields

    +

    resolve. mainFields

    • default: ["exports", "browser", "module", "main"]

    When parsing dependencies under node_modules, the fields and order configured in mainFields will be parsed from package.json. For package.json

    -
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }
    +
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }

    Will use es/index.js first (if the path exists), and will continue to search backwards if it does not exist.

    -

    resolve.conditions

    +

    resolve.conditions

    Configuration is not currently supported.

    - +
    • default: true

    When parsing a file, whether to track the real directory corresponding to the symlink, and start parsing the next dependency from the real directory. If pnpm is used to manage dependencies, this option must be configured as true.

    -

    resolve. strictExports

    +

    resolve. strictExports

    • default: false

    Whether to strictly follow the exports defined in exports in package.json. If set to true, when exports is defined in package.json, but exports does not define the corresponding export, an error will be reported directly. If set to true, it will continue to try other entries according to mainFields.

    -

    define

    +

    define

    • Default value: {}

    Global variable injection, the configured variable name and value will be injected into the product at compile time. Farm injects process.env.NODE_ENV and some variables used by Farm itself such as FARM_HMR_PORT by default

    -
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123,
    },
    },
    });
    -
    note
      +
      export default defineConfig({
      compilation: {
      define: {
      MY_VAR: 123,
      },
      },
      });
      +
      note
      1. In order to enhance performance, define uses the injection form of global variables, which means that variables in the form of objects cannot be injected, for example, variables in the form of process.env.XXX cannot be injected, and only variables in the form of XXX can be configured .
      2. If multiple Farm projects are mounted under the same window, the defines with the same name in multiple projects will overwrite each other.
      3. The injection is a string. If it needs to be converted to another type, it needs to be manually converted in the runtime code, such as Number(MY_VAR)
      -

      external

      +

      external

      • default: []

      Configure the imports that are external, and the imports that are external will not appear in the compiled product. However, the corresponding import statement will not be deleted. You need to customize how to deal with external, otherwise an error will be reported at runtime. If targetEnv is an external module under node, it will automatically try to require the module.

      It needs to be configured in a regular way, for example:

      -
      export default defineConfig({
      compilation: {
      external: ["^stream$"],
      },
      });
      -

      mode

      +
      export default defineConfig({
      compilation: {
      external: ["^stream$"],
      },
      });
      +

      mode

      • default: development for start, watch commands, production for build commands

      Configure the compilation mode. In order to optimize the performance during development, if there is no manual configuration of production optimization related options (minify, tree shake, etc.), the production environment optimization such as compression and tree shake will be disabled by default under development. In production mode enabled.

      -

      root

      +

      root

      • default: process.cwd()

      Configure the root directory for project compilation. This option will affect the search path of the default configuration file, the search of compiled module dependencies, etc.

      -

      runtime

      +

      runtime

      Configure Farm runtime capabilities. The types are as follows:

      -
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      -

      runtime.path

      +
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      +

      runtime.path

      • Default value: The path of Farm's built-in runtime

      Customize a Runtime to replace Farm's built-in Runtime.

      -
      warning

      It is not recommended to configure this option under normal circumstances, because once this option is configured, the pointed runtime needs all

      -

      runtime.plugins

      +
      warning

      It is not recommended to configure this option under normal circumstances, because once this option is configured, the pointed runtime needs all

      +

      runtime.plugins

      • Default value: The path of Farm's built-in runtime-plugin-hmr

      Configure the Runtime plug-in, through the Runtime plug-in, you can intervene in Runtime behavior, such as module loading, resource loading, etc. For details, please refer to: WIP.

      -

      runtime.namespace

      +

      runtime.namespace

      • default: name field of project package.json

      Configure the namespace of Farm Runtime to ensure that the execution of different products under the same window or global can be isolated from each other. By default, the name field of the project package.json is used as the namespace.

      -

      assets

      -

      assets.include

      +

      assets

      +

      assets.include

      • default: []

      Additional file suffixes that are regarded as static resources, such as the following example, txt will be regarded as posture resources, and will be treated as static resources when importing txt files:

      -
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"],
      },
      },
      });
      -

      script

      -

      script.target

      +
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"],
      },
      },
      });
      +

      script

      +

      script.target

      • Default value: esnext (dynamically adjusted according to the iteration of Farm)

      Configure Farm to parse the AST of js/jsx/ts/tsx and support the ES syntax version when generating code. Possible values: es5, es6, es2015 - es2023, esnext

      -

      script.parser

      +

      script.parser

      • default: same as SWC

      Configure the behavior of SWC when parsing AST, configuration item reference: https://swc.rs/docs/configuration/compilation#jscparser

      -

      script.plugins

      +

      script.plugins

      • default: []
      @@ -191,9 +191,9 @@

      script.pa
    1. filters: Which modules to execute the plug-in, must be configured, support resolvedPaths and moduleTypes these two filter items, if both are specified at the same time, take the union.
    2. An example of a configuration that supports JSX for a Vue project is as follows:

      -
      import jsPluginVue from "@farmfe/js-plugin-vue";

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [
      {
      name: "swc-plugin-vue-jsx",
      options: {
      transformOn: true,
      optimize: true,
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ["tsx", "jsx"],
      },
      },
      ],
      },
      },
      plugins: [jsPluginVue()],
      };
      -

      script.decorators

      -
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * The version of the decorator proposal to use. 2021-12 or 2022-03
      * @default 2021-12
      */
      decoratorVersion: "2021-12" | "2022-03" | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }
      +
      import jsPluginVue from "@farmfe/js-plugin-vue";

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [
      {
      name: "swc-plugin-vue-jsx",
      options: {
      transformOn: true,
      optimize: true,
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ["tsx", "jsx"],
      },
      },
      ],
      },
      },
      plugins: [jsPluginVue()],
      };
      +

      script.decorators

      +
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * The version of the decorator proposal to use. 2021-12 or 2022-03
      * @default 2021-12
      */
      decoratorVersion: "2021-12" | "2022-03" | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }

      It's recommended to use default decorators configuration of Farm, unless you want to improve performance, you can set includes and excludes.

      Options:

        @@ -203,36 +203,36 @@

        scrip
      • includes: default to []. If you want to include modules that are excluded, you can set this option. Regex supported.
      • excludes: default to ['node_modules/']. Modules under these paths are ignored when transform decorators. Regex supported
      -

      css

      -

      css.modules

      +

      css

      +

      css.modules

      Configure Farm CSS Modules.

      -
      interface FarmCssModulesConfig {
      // Configure which paths will be processed as css modules, using regular strings
      // defaults to `.module.css` or `.module.scss` or `.module.less`
      paths?: string[];
      // configure the generated css class name, the default is `[name]-[hash]`
      indentName?: string;
      }
      -
      css.modules.paths
      +
      interface FarmCssModulesConfig {
      // Configure which paths will be processed as css modules, using regular strings
      // defaults to `.module.css` or `.module.scss` or `.module.less`
      paths?: string[];
      // configure the generated css class name, the default is `[name]-[hash]`
      indentName?: string;
      }
      +
      css.modules.paths
      • default: ["\\.module\\.(css|scss|sass|less)"]

      Configure which paths correspond to modules that will be treated as CSS Modules. A regular string needs to be configured. Defaults to files ending in .module.(css|scss|sass|less).

      -
      css.modules.identName
      +
      css.modules.identName
      • default: [name]-[hash]

      Configure the generated CSS Modules class name, the default is [name]-[hash], [name], [hash] are placeholders (also all currently supported placeholders). [name] means the original class name, [hash] means the hash of the modified css file id.

      -

      css.prefixer

      +

      css.prefixer

      Configure CSS compatibility prefixes, such as -webkit-.

      -
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | "chrome"
      | "opera"
      | "edge"
      | "firefox"
      | "safari"
      | "ie"
      | "ios"
      | "android"
      | "node"
      | "electron",
      string
      >
      > & { [key: string]: string };
      -
      css.prefixer.targets
      +
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | "chrome"
      | "opera"
      | "edge"
      | "firefox"
      | "safari"
      | "ie"
      | "ios"
      | "android"
      | "node"
      | "electron",
      string
      >
      > & { [key: string]: string };
      +
      css.prefixer.targets
      • Default value: undefined

      Configure which target browsers or browser versions to enable, for example:

      -
      import { defineConfig } from "@farmfe/core";

      function defineConfig(config: UserConfig) {
      return config;
      }

      export default defineConfig({
      compilation: {
      css: {
      prefix: {
      targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
      },
      },
      },
      });
      -

      html

      -

      html.base

      +
      import { defineConfig } from "@farmfe/core";

      function defineConfig(config: UserConfig) {
      return config;
      }

      export default defineConfig({
      compilation: {
      css: {
      prefix: {
      targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
      },
      },
      },
      });
      +

      html

      +

      html.base

      • Default value: undefined

      All HTML entries will inherit html.base, for details, refer to Guide - HTML

      -

      sourcemap

      +

      sourcemap

      • default: true
      @@ -244,25 +244,25 @@

      sourcemapall: generate sourcemap for all files, and generate a separate sourcemap file
    3. all-inline: Generate sourcemaps for all files, and inline sourcemaps into the product, do not generate separate files
    4. -

      partialBundling

      +

      partialBundling

      Configure the behavior of Farm's partial bundling. For details, please refer to Partial Bundling

      -
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: "mutable" | "immutable";
      resourceType?: "all" | "initial" | "async";
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      }
      -

      partialBundling.targetConcurrentRequests

      +
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: "mutable" | "immutable";
      resourceType?: "all" | "initial" | "async";
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      }
      +

      partialBundling.targetConcurrentRequests

      • default: 25

      Farm tries to generate resource numbers as closer as possible to this config value for initial resource loading or a dynamic resource loading.

      -

      partialBundling.targetMinSize

      +

      partialBundling.targetMinSize

      • default: 20 * 1024 bytes, 20 KB

      The minimum size of each generated resources before minify and gzip. Note that targetMinSize will not be satisfied if ModuleBucket's size is less than targetMinSize, ModuleBucket will be given priority. Config enforceTargetMinSize can be used to enforce size.

      -

      partialBundling.targetMaxSize

      +

      partialBundling.targetMaxSize

      • default: 1500 * 1024 bytes, 1500 KB

      The maximum size of generated resources before minify and gzip.

      -

      partialBundling.groups

      +

      partialBundling.groups

      • default: []
      @@ -274,8 +274,8 @@

    5. groupType: mutable or immutable, this group only applies to the specified type of modules.
    6. resourceType: all, initial or async, this group only applies to the specified type of resources.
    7. -
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: "vendor-react",
      test: ["node_modules/"],
      },
      ],
      },
      },
      });
      -

      partialBundling.enforceResources

      +
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: "vendor-react",
      test: ["node_modules/"],
      },
      ],
      },
      },
      });
      +

      partialBundling.enforceResources

      • default: []
      @@ -285,90 +285,90 @@

      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      enforceResources: [
      {
      name: "index",
      test: [".+"],
      },
      ],
      },
      },
      });

    -
    warning

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    -

    partialBundling.enforceTargetConcurrentRequests

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: "index",
    test: [".+"],
    },
    ],
    },
    },
    });
    +
    warning

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    +

    partialBundling.enforceTargetConcurrentRequests

    • default: false

    Enforce target concurrent requests for every resource loading, when true, smaller resource will be merged into bigger resource to meet the target concurrent requests. this may cause issue for css resource, be careful to use this option.

    -

    partialBundling.enforceTargetMinSize

    +

    partialBundling.enforceTargetMinSize

    • default: false

    Enforce target min size for every resource, when tue, smaller resource will be merged into bigger resource to meet the target concurrent requests. this may cause issue for css resource, be careful to use this option

    -

    partialBundling.immutableModules

    +

    partialBundling.immutableModules

    • default: ['node_modules']

    Regex array to match the immutable modules.

    -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });
    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });

    Immutable module can affect bundling and incoming persistent cache, be careful if you want to change it.

    -

    partialBundling.immutableModulesWeight

    +

    partialBundling.immutableModulesWeight

    • default: 0.8

    默认为0.8,不可变模块将拥有 80%的请求数。 例如,如果targetConcurrentRequest为 25,则默认情况下不可变资源将采用25 * 80% = 20。 该选项是为了确保可变模块和不可变模块是隔离的,如果更改您的业务代码,node_modules 下的代码不会受到影响。

    -

    lazyCompilation

    +

    lazyCompilation

    • default: true in development mode, false in build mode

    Whether to enable lazy compilation, configure to false to close. See lazy compilation.

    -

    treeShaking

    +

    treeShaking

    • default: false in development mode, true in build mode

    Whether to enable tree shake, set to false to close. See Tree Shake.

    -

    minify

    +

    minify

    • default: false in development mode, true in build mode

    Whether to enable compression, the product will be compressed and confused after it is turned on. See Compression.

    -

    presetEnv

    +

    presetEnv

    • default: false in development mode, true in build mode
    -
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };
    +
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };

    By default, polyfills will not be injected into modules under node_modules, if necessary, please use include to add polyfills.

    -

    presetEnv.include

    +

    presetEnv.include

    • default: []

    Include additional modules that require polyfill, configure regular strings, for example include: ['node_modules/(es6-package|my-package)/']

    -

    presetEnv. exclude

    +

    presetEnv. exclude

    • default: ['node_modules/']

    Configure modules that do not require polyfill, and configure regular strings, such as exclude: ['custom-path/(es5-package|my-package)/']. By default node_modules is excluded, if you need to include excluded modules, it is recommended to use include

    -

    presetEnv.options

    +

    presetEnv.options

    • default: downgrade to ES5

    Options passed to swc preset env, see https://swc.rs/docs/configuration/compilation#env.

    -

    persistentCache

    +

    persistentCache

    • default: true

    Options for Persistent Cache. Configuring it false to disable cache.

    -
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    -

    persistentCache.namespace

    +
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    +

    persistentCache.namespace

    • default: farm-cache

    Namespace for the cache, caches under different namespace will be isolated.

    -

    persistentCache.cacheDir

    +

    persistentCache.cacheDir

    • default: node_modules/.farm/cache

    Cache store directory.

    -

    persistentCache.buildDependencies

    +

    persistentCache.buildDependencies

    • default: farm.config.ts and all its deep dependencies

    File path or package name that may affect the compilation, for example, plugins. By default, farm.config.ts/js/mjs and all of its deep dependencies will be treated as build dependencies, if any of these files changed, all cache will be invalidated.

    it can be a file path or a package name, for example:

    -
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    -

    persistentCache.moduleCacheKeyStrategy

    +
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    +

    persistentCache.moduleCacheKeyStrategy

    • default: { timestamp: true, hash: true }
    @@ -377,10 +377,10 @@

    persistentCache.envs

    +

    persistentCache.envs

    -

    Envs used to invalidate cache, if the configured env changed, then all cache will be invalidated.

    +

    Envs used to invalidate cache, if the configured env changed, then all cache will be invalidated.

    \ No newline at end of file diff --git a/docs/0.x/config/dev-server/index.html b/docs/0.x/config/dev-server/index.html index 70afed41d..6a7167b4e 100644 --- a/docs/0.x/config/dev-server/index.html +++ b/docs/0.x/config/dev-server/index.html @@ -8,45 +8,45 @@ - - - + + + -
    Version: 0.15

    Dev Server

    -

    DevServer Options - server

    +
    Version: 0.15

    Dev Server

    +

    DevServer Options - server

    Configure the behavior of Farm Dev Server. Example:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    server: {
    port: 9000,
    //...
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    server: {
    port: 9000,
    //...
    },
    });

    type:

    -
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: "http" | "https";
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    //whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    -

    port

    +
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: "http" | "https";
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    //whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    +

    port

    • default: 9000

    The port the DevServer listens on.

    -

    hmr

    +

    hmr

    • default: true for start command, false for other commands

    Enable HMR. After enabling the HMR capability, it will monitor the changes of the modules involved in the compilation process. When the modules change, it will automatically trigger recompilation and push the results to Farm Runtime for update. HMR can also be configured through an object, for example:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    hmr: {
    // Configure the port for web socket listening
    port: 9802
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    -

    hmr.port

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    hmr: {
    // Configure the port for web socket listening
    port: 9802
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    +

    hmr.port

    • default: 9801

    The port the Web Socket server listens on

    -

    hmr.host

    +

    hmr.host

    • default: localhost

    Host on which the Web Socket server listens

    -

    proxy

    +

    proxy

    • Default value: undefined

    Configure server proxy. farm uses http-proxy as a proxy for the development server. Based on http-proxy implementation, specific options refer to its documentation, example:

    -
    import { defineConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    -

    open

    +
    import { defineConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    +

    open

    • default: false
    @@ -56,12 +56,12 @@

    openplugins

    +

    plugins

    • default: []

    Configure the Dev Server plug-in of Farm, through the Dev Server plug-in, you can extend the context of DevServer, add middleware, etc. A plugin is a function. Examples of plugins are as follows:

    -
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host,
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(
    devServer.getCompiler(),
    devServer,
    logger
    );
    }
    }
    -

    Then configure the plugin into server.plugins.

    +
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host,
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(
    devServer.getCompiler(),
    devServer,
    logger
    );
    }
    }
    +

    Then configure the plugin into server.plugins.

    \ No newline at end of file diff --git a/docs/0.x/config/environment-variable/index.html b/docs/0.x/config/environment-variable/index.html index ebbe9bb26..60c5d7c88 100644 --- a/docs/0.x/config/environment-variable/index.html +++ b/docs/0.x/config/environment-variable/index.html @@ -8,25 +8,25 @@ - - - + + + -
    Version: 0.15

    Environment variable

    +
    Version: 0.15

    Environment variable

    Farm distinguishes between development and production environments through Farm process.env.NODE_ ENV`.

    In different environments, environment variables are replaced statically, so use static constants to represent environment variables instead of dynamic expressions.

    -

    .env file

    +

    .env file

    Farm uses dotenv to load your additional environment variables, such as .env files.

    -
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0
    +
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0

    Farm loads the file .env via dotenv, and loads it into process.env and finally injects it into define.

    -
    warning

    In order to ensure the security of the client, preventing the environment variables in the current system from being exposed to the client Farm will only identify some important environment variables that start with FARM_VITE_ (In order to better compatible with vite and its ecological environment).

    +
    warning

    In order to ensure the security of the client, preventing the environment variables in the current system from being exposed to the client Farm will only identify some important environment variables that start with FARM_VITE_ (In order to better compatible with vite and its ecological environment).

    Farm expands environment variables through dotenv-expand

    If you want to customize the prefix of env variables, you can configure envPrefix.

    -

    envPrefix

    +

    envPrefix

    • default value: FARM_VITE_
    -

    Customize the prefix of the env variable by configuring envPrefix.

    +

    Customize the prefix of the env variable by configuring envPrefix.

    \ No newline at end of file diff --git a/docs/0.x/config/farm-config/index.html b/docs/0.x/config/farm-config/index.html index ea73cd68b..5377db66b 100644 --- a/docs/0.x/config/farm-config/index.html +++ b/docs/0.x/config/farm-config/index.html @@ -8,29 +8,29 @@ - - - + + + -
    Version: 0.15

    Configuration Reference

    +
    Version: 0.15

    Configuration Reference

    By default, Farm reads the configuration from the farm.config.ts|js|mjs file in the project root directory, an example configuration file:

    -
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: Config) {
    return config;
    }

    export default defineConfig({
    root: process.cwd(), // compiled root directory
    // compile options
    compilation: {
    //...
    },
    // Dev Server options
    server: {
    hmr: true,
    //...
    },
    // plugin configuration
    plugins: []
    });
    -

    Compilation options - compilation

    +
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: Config) {
    return config;
    }

    export default defineConfig({
    root: process.cwd(), // compiled root directory
    // compile options
    compilation: {
    //...
    },
    // Dev Server options
    server: {
    hmr: true,
    //...
    },
    // plugin configuration
    plugins: []
    });
    +

    Compilation options - compilation

    All compilation-related configuration is under the compilation field.

    -

    input

    +

    input

    • type: Record<string, string>

    The entry point for the project. Input files can be html, ts/js/tsx/jsx, css or other files supported by plugins.

    -
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    compilation: {
    input: {
    index: './index.html',
    about: './about.html'
    },
    }
    // ..
    }
    -

    output

    +
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    compilation: {
    input: {
    index: './index.html',
    about: './about.html'
    },
    }
    // ..
    }
    +

    output

    • type: OutputOptions
    -
    interface OutputOptions {
    // After partial bundling, the file name configuration of the resource where the entry file is located
    entryFilename?: string;
    // After partial bundling, other resources except the entry resource input file name configuration
    filename?: string;
    // output directory
    path?: string;
    // public path: resource loading prefix
    publicPath?: string;
    // Static resource file name configuration
    assetsFilename?: string;
    // Target execution environment, browser or Node
    targetEnv?: 'browser' | 'node';
    // output module format
    format?: 'cjs' | 'esm';
    }
    -
    note

    We call the compiled result a resource

    -

    output.entryFilename

    +
    interface OutputOptions {
    // After partial bundling, the file name configuration of the resource where the entry file is located
    entryFilename?: string;
    // After partial bundling, other resources except the entry resource input file name configuration
    filename?: string;
    // output directory
    path?: string;
    // public path: resource loading prefix
    publicPath?: string;
    // Static resource file name configuration
    assetsFilename?: string;
    // Target execution environment, browser or Node
    targetEnv?: 'browser' | 'node';
    // output module format
    format?: 'cjs' | 'esm';
    }
    +
    note

    We call the compiled result a resource

    +

    output.entryFilename

    • default: "[entryName].[ext]"
    @@ -41,7 +41,7 @@

    ou
  • [contentHash]: The content hash of the resource.
  • [ext]: The extension of the resource, js for js/jsx/ts/tsx, css for css/scss/less.
  • -

    output.filename

    +

    output.filename

    • Default value: "[resourceName].[ext]"
    @@ -51,136 +51,136 @@

    output.
  • [contentHash]: The content hash of the resource.
  • [ext]: The extension of the resource, js for js/jsx/ts/tsx, css for css/scss/less.
  • -

    output.path

    +

    output.path

    • default: "dist"

    directory of output resources

    -

    output.publicPath

    +

    output.publicPath

    • Default value: "/"

    The resource url load prefix. For example URL https://xxxx, or a absolute path /xxx/.

    -

    output.assetsFileName

    +

    output.assetsFileName

    • Default value: "[resourceName].[ext]"

    The filename configuration for static resource output, the placeholder is the same as output.filename.

    -

    output. targetEnv

    +

    output. targetEnv

    • default: "browser"

    Configure the execution environment of the product, which can be "browser" or "node".

    -

    output. format

    +

    output. format

    • default: "esm"

    The format of the configuration product, which can be "esm" or "cjs".

    -
    note

    This option is only valid for Js products

    -

    resolve

    +
    note

    This option is only valid for Js products

    +

    resolve

    • type: ResolveOptions
    -
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    };
    -

    resolve. extensions

    +
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    };
    +

    resolve. extensions

    • default: ["tsx", "ts", "jsx", "js", "mjs", "json", "html", "css"]

    Configure the suffix when parsing dependencies. For example, when parsing ./index, if it is not resolved, the suffix parsing will be automatically added, such as trying ./index.tsx, ./index.css, etc.

    -

    resolve.alias

    +

    resolve.alias

    • Default value: {}

    Configure parsing alias, example:

    -
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '/@': path. join(process. cwd(), 'src'),
    "stream$": "readable-stream"
    }
    }
    },
    });
    +
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '/@': path. join(process. cwd(), 'src'),
    "stream$": "readable-stream"
    }
    }
    },
    });

    alias is prefix replacement, for the above example /@/pages will be replaced by /root/src/pages.

    If you want an exact match, you can add $, for example stream$ will only replace stream, but not stream/xxx.

    If you want to use regex, you can use $__farm_regex:, for example $__farm_regex:^/(utils)$ will replace /utils to /root/src/utils.

    -

    resolve. mainFields

    +

    resolve. mainFields

    • default: ["exports", "browser", "module", "main"]

    When parsing dependencies under node_modules, the fields and order configured in mainFields will be parsed from package.json. For package.json

    -
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }
    +
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }

    Will use es/index.js first (if the path exists), and will continue to search backwards if it does not exist.

    -

    resolve.conditions

    +

    resolve.conditions

    Configuration is not currently supported.

    - +
    • default: true

    When parsing a file, whether to track the real directory corresponding to the symlink, and start parsing the next dependency from the real directory. If pnpm is used to manage dependencies, this option must be configured as true.

    -

    resolve. strictExports

    +

    resolve. strictExports

    • default: false

    Whether to strictly follow the exports defined in exports in package.json. If set to true, when exports is defined in package.json, but exports does not define the corresponding export, an error will be reported directly. If set to true, it will continue to try other entries according to mainFields.

    -

    define

    +

    define

    • Default value: {}

    Global variable injection, the configured variable name and value will be injected into the product at compile time. Farm injects process.env.NODE_ENV and some variables used by Farm itself such as FARM_HMR_PORT by default

    -
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123
    }
    },
    });
    -
    note
      +
      export default defineConfig({
      compilation: {
      define: {
      MY_VAR: 123
      }
      },
      });
      +
      note
      1. In order to enhance performance, define uses the injection form of global variables, which means that variables in the form of objects cannot be injected, for example, variables in the form of process.env.XXX cannot be injected, and only variables in the form of XXX can be configured .
      2. If multiple Farm projects are mounted under the same window, the defines with the same name in multiple projects will overwrite each other.
      3. The injection is a string. If it needs to be converted to another type, it needs to be manually converted in the runtime code, such as Number(MY_VAR)
      -

      external

      +

      external

      • default: []

      Configure the imports that are external, and the imports that are external will not appear in the compiled product. However, the corresponding import statement will not be deleted. You need to customize how to deal with external, otherwise an error will be reported at runtime. If targetEnv is an external module under node, it will automatically try to require the module.

      It needs to be configured in a regular way, for example:

      -
      export default defineConfig({
      compilation: {
      external: ["^stream$"]
      },
      });
      -

      mode

      +
      export default defineConfig({
      compilation: {
      external: ["^stream$"]
      },
      });
      +

      mode

      • default: development for start, watch commands, production for build commands

      Configure the compilation mode. In order to optimize the performance during development, if there is no manual configuration of production optimization related options (minify, tree shake, etc.), the production environment optimization such as compression and tree shake will be disabled by default under development. In production mode enabled.

      -

      root

      +

      root

      • default: process.cwd()

      Configure the root directory for project compilation. This option will affect the search path of the default configuration file, the search of compiled module dependencies, etc.

      -

      runtime

      +

      runtime

      Configure Farm runtime capabilities. The types are as follows:

      -
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      -

      runtime.path

      +
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      +

      runtime.path

      • Default value: The path of Farm's built-in runtime

      Customize a Runtime to replace Farm's built-in Runtime.

      -
      warning

      It is not recommended to configure this option under normal circumstances, because once this option is configured, the pointed runtime needs all

      -

      runtime.plugins

      +
      warning

      It is not recommended to configure this option under normal circumstances, because once this option is configured, the pointed runtime needs all

      +

      runtime.plugins

      • Default value: The path of Farm's built-in runtime-plugin-hmr

      Configure the Runtime plug-in, through the Runtime plug-in, you can intervene in Runtime behavior, such as module loading, resource loading, etc. For details, please refer to: WIP.

      -

      runtime.namespace

      +

      runtime.namespace

      • default: name field of project package.json

      Configure the namespace of Farm Runtime to ensure that the execution of different products under the same window or global can be isolated from each other. By default, the name field of the project package.json is used as the namespace.

      -

      assets

      -

      assets.include

      +

      assets

      +

      assets.include

      • default: []

      Additional file suffixes that are regarded as static resources, such as the following example, txt will be regarded as posture resources, and will be treated as static resources when importing txt files:

      -
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"]
      }
      },
      });
      -

      script

      -

      script.target

      +
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"]
      }
      },
      });
      +

      script

      +

      script.target

      • Default value: esnext (dynamically adjusted according to the iteration of Farm)

      Configure Farm to parse the AST of js/jsx/ts/tsx and support the ES syntax version when generating code. Possible values: es5, es6, es2015 - es2023, esnext

      -

      script.parser

      +

      script.parser

      • default: same as SWC

      Configure the behavior of SWC when parsing AST, configuration item reference: https://swc.rs/docs/configuration/compilation#jscparser

      -

      script.plugins

      +

      script.plugins

      • default: []
      @@ -191,9 +191,9 @@

      script.p
    1. filters: Which modules to execute the plug-in, must be configured, support resolvedPaths and moduleTypes these two filter items, if both are specified at the same time, take the union.
    2. An example of a configuration that supports JSX for a Vue project is as follows:

      -
      import jsPluginVue from '@farmfe/js-plugin-vue';

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [{
      name: 'swc-plugin-vue-jsx',
      options: {
      "transformOn": true,
      "optimize": true
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ['tsx', 'jsx'],
      }
      }]
      }
      },
      plugins: [jsPluginVue()],
      };
      -

      script.decorators

      -
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * The version of the decorator proposal to use. 2021-12 or 2022-03
      * @default 2021-12
      */
      decoratorVersion: '2021-12' | '2022-03' | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }
      +
      import jsPluginVue from '@farmfe/js-plugin-vue';

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [{
      name: 'swc-plugin-vue-jsx',
      options: {
      "transformOn": true,
      "optimize": true
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ['tsx', 'jsx'],
      }
      }]
      }
      },
      plugins: [jsPluginVue()],
      };
      +

      script.decorators

      +
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * The version of the decorator proposal to use. 2021-12 or 2022-03
      * @default 2021-12
      */
      decoratorVersion: '2021-12' | '2022-03' | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }

      It's recommended to use default decorators configuration of Farm, unless you want to improve performance, you can set includes and excludes.

      Options:

        @@ -203,36 +203,36 @@

        scrip
      • includes: default to []. If you want to include modules that are excluded, you can set this option. Regex supported.
      • excludes: default to ['node_modules/']. Modules under these paths are ignored when transform decorators. Regex supported
      -

      css

      -

      css.modules

      +

      css

      +

      css.modules

      Configure Farm CSS Modules.

      -
      interface FarmCssModulesConfig {
      // Configure which paths will be processed as css modules, using regular strings
      // defaults to `.module.css` or `.module.scss` or `.module.less`
      paths?: string[];
      // configure the generated css class name, the default is `[name]-[hash]`
      indentName?: string;
      }
      -
      css.modules.paths
      +
      interface FarmCssModulesConfig {
      // Configure which paths will be processed as css modules, using regular strings
      // defaults to `.module.css` or `.module.scss` or `.module.less`
      paths?: string[];
      // configure the generated css class name, the default is `[name]-[hash]`
      indentName?: string;
      }
      +
      css.modules.paths
      • default: ["\\.module\\.(css|scss|sass|less)"]

      Configure which paths correspond to modules that will be treated as CSS Modules. A regular string needs to be configured. Defaults to files ending in .module.(css|scss|sass|less).

      -
      css.modules.identName
      +
      css.modules.identName
      • default: [name]-[hash]

      Configure the generated CSS Modules class name, the default is [name]-[hash], [name], [hash] are placeholders (also all currently supported placeholders). [name] means the original class name, [hash] means the hash of the modified css file id.

      -

      css.prefixer

      +

      css.prefixer

      Configure CSS compatibility prefixes, such as -webkit-.

      -
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | 'chrome'
      | 'opera'
      | 'edge'
      | 'firefox'
      | 'safari'
      | 'ie'
      | 'ios'
      | 'android'
      | 'node'
      | 'electron',
      string
      >
      > & { [key: string]: string };
      -
      css.prefixer.targets
      +
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | 'chrome'
      | 'opera'
      | 'edge'
      | 'firefox'
      | 'safari'
      | 'ie'
      | 'ios'
      | 'android'
      | 'node'
      | 'electron',
      string
      >
      > & { [key: string]: string };
      +
      css.prefixer.targets
      • Default value: undefined

      Configure which target browsers or browser versions to enable, for example:

      -
      import type { UserConfig } from '@farmfe/core';

      function defineConfig(config: UserConfig) {
      return config;
      }

      export default defineConfig({
      compilation: {
      css: {
      prefix: {
      targets: ['last 2 versions', 'Firefox ESR', '> 1%', 'ie >= 11']
      }
      },
      },
      });
      -

      html

      -

      html.base

      +
      import type { UserConfig } from '@farmfe/core';

      function defineConfig(config: UserConfig) {
      return config;
      }

      export default defineConfig({
      compilation: {
      css: {
      prefix: {
      targets: ['last 2 versions', 'Firefox ESR', '> 1%', 'ie >= 11']
      }
      },
      },
      });
      +

      html

      +

      html.base

      • Default value: undefined

      All HTML entries will inherit html.base, for details, refer to Guide - HTML

      -

      sourcemap

      +

      sourcemap

      • default: true
      @@ -244,25 +244,25 @@

      sourcemapall: generate sourcemap for all files, and generate a separate sourcemap file
    3. all-inline: Generate sourcemaps for all files, and inline sourcemaps into the product, do not generate separate files
    4. -

      partialBundling

      +

      partialBundling

      Configure the behavior of Farm's partial bundling. For details, please refer to Partial Bundling

      -
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: 'mutable' | 'immutable',
      resourceType?: 'all' | 'initial' | 'async'
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      };
      -

      partialBundling.targetConcurrentRequests

      +
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: 'mutable' | 'immutable',
      resourceType?: 'all' | 'initial' | 'async'
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      };
      +

      partialBundling.targetConcurrentRequests

      • default: 25

      Farm tries to generate resource numbers as closer as possible to this config value for initial resource loading or a dynamic resource loading.

      -

      partialBundling.targetMinSize

      +

      partialBundling.targetMinSize

      • default: 20 * 1024 bytes, 20 KB

      The minimum size of each generated resources before minify and gzip. Note that targetMinSize will not be satisfied if ModuleBucket's size is less than targetMinSize, ModuleBucket will be given priority. Config enforceTargetMinSize can be used to enforce size.

      -

      partialBundling.targetMaxSize

      +

      partialBundling.targetMaxSize

      • default: 1500 * 1024 bytes, 1500 KB

      The maximum size of generated resources before minify and gzip.

      -

      partialBundling.groups

      +

      partialBundling.groups

      • default: []
      @@ -274,8 +274,8 @@

    5. groupType: mutable or immutable, this group only applies to the specified type of modules.
    6. resourceType: all, initial or async, this group only applies to the specified type of resources.
    7. -
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: 'vendor-react',
      test: ['node_modules/'],
      }
      ]
      },
      },
      });
      -

      partialBundling.enforceResources

      +
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: 'vendor-react',
      test: ['node_modules/'],
      }
      ]
      },
      },
      });
      +

      partialBundling.enforceResources

      • default: []
      @@ -285,90 +285,90 @@

      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      enforceResources: [
      {
      name: 'index',
      test: ['.+'],
      }
      ]
      },
      },
      });

    -
    warning

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    -

    partialBundling.enforceTargetConcurrentRequests

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: 'index',
    test: ['.+'],
    }
    ]
    },
    },
    });
    +
    warning

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    +

    partialBundling.enforceTargetConcurrentRequests

    • default: false

    Enforce target concurrent requests for every resource loading, when true, smaller resource will be merged into bigger resource to meet the target concurrent requests. this may cause issue for css resource, be careful to use this option.

    -

    partialBundling.enforceTargetMinSize

    +

    partialBundling.enforceTargetMinSize

    • default: false

    Enforce target min size for every resource, when tue, smaller resource will be merged into bigger resource to meet the target concurrent requests. this may cause issue for css resource, be careful to use this option

    -

    partialBundling.immutableModules

    +

    partialBundling.immutableModules

    • default: ['node_modules']

    Regex array to match the immutable modules.

    -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ['node_modules/', '/global-constants']
    },
    },
    });
    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ['node_modules/', '/global-constants']
    },
    },
    });

    Immutable module can affect bundling and incoming persistent cache, be careful if you want to change it.

    -

    partialBundling.immutableModulesWeight

    +

    partialBundling.immutableModulesWeight

    • default: 0.8

    默认为0.8,不可变模块将拥有80%的请求数。 例如,如果targetConcurrentRequest为 25,则默认情况下不可变资源将采用25 * 80% = 20。 该选项是为了确保可变模块和不可变模块是隔离的,如果更改您的业务代码,node_modules下的代码不会受到影响。

    -

    lazyCompilation

    +

    lazyCompilation

    • default: true in development mode, false in build mode

    Whether to enable lazy compilation, configure to false to close. See lazy compilation.

    -

    treeShaking

    +

    treeShaking

    • default: false in development mode, true in build mode

    Whether to enable tree shake, set to false to close. See Tree Shake.

    -

    minify

    +

    minify

    • default: false in development mode, true in build mode

    Whether to enable compression, the product will be compressed and confused after it is turned on. See Compression.

    -

    presetEnv

    +

    presetEnv

    • default: false in development mode, true in build mode
    -
    type FarmPresetEnvConfig = boolean | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };
    +
    type FarmPresetEnvConfig = boolean | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };

    By default, polyfills will not be injected into modules under node_modules, if necessary, please use include to add polyfills.

    -

    presetEnv.include

    +

    presetEnv.include

    • default: []

    Include additional modules that require polyfill, configure regular strings, for example include: ['node_modules/(es6-package|my-package)/']

    -

    presetEnv. exclude

    +

    presetEnv. exclude

    • default: ['node_modules/']

    Configure modules that do not require polyfill, and configure regular strings, such as exclude: ['custom-path/(es5-package|my-package)/']. By default node_modules is excluded, if you need to include excluded modules, it is recommended to use include

    -

    presetEnv.options

    +

    presetEnv.options

    • default: downgrade to ES5

    Options passed to swc preset env, see https://swc.rs/docs/configuration/compilation#env.

    -

    persistentCache

    +

    persistentCache

    • default: true

    Options for Persistent Cache. Configuring it false to disable cache.

    -
    export type PersistentCache = boolean | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean,
    hash?: boolean,
    }
    };
    -

    persistentCache.namespace

    +
    export type PersistentCache = boolean | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean,
    hash?: boolean,
    }
    };
    +

    persistentCache.namespace

    • default: farm-cache

    Namespace for the cache, caches under different namespace will be isolated.

    -

    persistentCache.cacheDir

    +

    persistentCache.cacheDir

    • default: node_modules/.farm/cache

    Cache store directory.

    -

    persistentCache.buildDependencies

    +

    persistentCache.buildDependencies

    • default: farm.config.ts and all its deep dependencies

    File path or package name that may affect the compilation, for example, plugins. By default, farm.config.ts/js/mjs and all of its deep dependencies will be treated as build dependencies, if any of these files changed, all cache will be invalidated.

    it can be a file path or a package name, for example:

    -
    import { defineConfig } from '@farmfe/core';
    import path from 'node:path';

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), './plugins/my-plugin.js'),
    // a package name, note that this package must expose package.json
    'farm-plugin-custom-xxx'
    ]
    }
    })
    -

    persistentCache.moduleCacheKeyStrategy

    +
    import { defineConfig } from '@farmfe/core';
    import path from 'node:path';

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), './plugins/my-plugin.js'),
    // a package name, note that this package must expose package.json
    'farm-plugin-custom-xxx'
    ]
    }
    })
    +

    persistentCache.moduleCacheKeyStrategy

    • default: { timestamp: true, hash: true }
    @@ -377,44 +377,44 @@

    persistentCache.envs

    +

    persistentCache.envs

    Envs used to invalidate cache, if the configured env changed, then all cache will be invalidated.

    -

    DevServer Options - server

    +

    DevServer Options - server

    Configure the behavior of Farm Dev Server. Example:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    port: 9000,
    //...
    }
    });
    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    port: 9000,
    //...
    }
    });

    type:

    -
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: 'http' | 'https';
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors. Options;
    //whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    -

    port

    +
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: 'http' | 'https';
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors. Options;
    //whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    +

    port

    • default: 9000

    The port the DevServer listens on.

    -

    hmr

    +

    hmr

    • default: true for start command, false for other commands

    Enable HMR. After enabling the HMR capability, it will monitor the changes of the modules involved in the compilation process. When the modules change, it will automatically trigger recompilation and push the results to Farm Runtime for update. HMR can also be configured through an object, for example:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    hmr: {
    // Configure the port for web socket listening
    port: 9802
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    -

    hmr.port

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    hmr: {
    // Configure the port for web socket listening
    port: 9802
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    +

    hmr.port

    • default: 9801

    The port the Web Socket server listens on

    -

    hmr.host

    +

    hmr.host

    • default: localhost

    Host on which the Web Socket server listens

    -

    proxy

    +

    proxy

    • Default value: undefined

    Configure server proxy. farm uses http-proxy as a proxy for the development server. Based on http-proxy implementation, specific options refer to its documentation, example:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    -

    open

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    +

    open

    • default: false
    @@ -424,41 +424,41 @@

    openplugins

    +

    plugins

    • default: []

    Configure the Dev Server plug-in of Farm, through the Dev Server plug-in, you can extend the context of DevServer, add middleware, etc. A plugin is a function. Examples of plugins are as follows:

    -
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config. hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(devServer.getCompiler(), devServer, logger);
    }
    }
    +
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config. hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(devServer.getCompiler(), devServer, logger);
    }
    }

    Then configure the plugin into server.plugins.

    -

    Environment variable

    +

    Environment variable

    Farm distinguishes between development and production environments through Farm process.env.NODE_ ENV`.

    In different environments, environment variables are replaced statically, so use static constants to represent environment variables instead of dynamic expressions.

    -

    .env file

    +

    .env file

    Farm uses dotenv to load your additional environment variables, such as .env files.

    -
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0
    +
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0

    Farm loads the file .env via dotenv, and loads it into process.env and finally injects it into define.

    -
    warning

    In order to ensure the security of the client, preventing the environment variables in the current system from being exposed to the client Farm will only identify some important environment variables that start with FARM_VITE_ (In order to better compatible with vite and its ecological environment).

    +
    warning

    In order to ensure the security of the client, preventing the environment variables in the current system from being exposed to the client Farm will only identify some important environment variables that start with FARM_VITE_ (In order to better compatible with vite and its ecological environment).

    Farm expands environment variables through dotenv-expand

    If you want to customize the prefix of env variables, you can configure envPrefix.

    -

    envPrefix

    +

    envPrefix

    • default value: FARM_VITE_

    Customize the prefix of the env variable by configuring envPrefix.

    -

    Plugins Options

    +

    Plugins Options

    Configure Farm's plug-ins, support Rust plug-ins or Js plug-ins, examples are as follows:

    -
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass', less()],
    });
    -

    Rust Plugins

    +
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass', less()],
    });
    +

    Rust Plugins

    • default: []

    Rust plugins are configured via plugin name or [plugin name, configuration option], as follows:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: [['@farmfe/plugin-react', { /* options here */}], '@farmfe/plugin-sass'],
    });
    -

    Js Plugins

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: [['@farmfe/plugin-react', { /* options here */}], '@farmfe/plugin-sass'],
    });
    +

    Js Plugins

    • default: []
    -

    Js plugin is an object, for details, please refer to Js plugin

    +

    Js plugin is an object, for details, please refer to Js plugin

    \ No newline at end of file diff --git a/docs/0.x/config/plugins-options/index.html b/docs/0.x/config/plugins-options/index.html index 27ff84b43..5e9c6941c 100644 --- a/docs/0.x/config/plugins-options/index.html +++ b/docs/0.x/config/plugins-options/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 0.15

    Plugins Options

    +
    Version: 0.15

    Plugins Options

    Configure Farm's plug-ins, support Rust plug-ins or Js plug-ins, examples are as follows:

    -
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass', less()],
    });
    -

    Rust Plugins

    +
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass', less()],
    });
    +

    Rust Plugins

    • default: []

    Rust plugins are configured via plugin name or [plugin name, configuration option], as follows:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: [['@farmfe/plugin-react', { /* options here */}], '@farmfe/plugin-sass'],
    });
    -

    Js Plugins

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: [['@farmfe/plugin-react', { /* options here */}], '@farmfe/plugin-sass'],
    });
    +

    Js Plugins

    • default: []
    -

    Js plugin is an object, for details, please refer to Js plugin

    +

    Js plugin is an object, for details, please refer to Js plugin

    \ No newline at end of file diff --git a/docs/0.x/features/css/index.html b/docs/0.x/features/css/index.html index 0bcfc524a..5fc1ce0e7 100644 --- a/docs/0.x/features/css/index.html +++ b/docs/0.x/features/css/index.html @@ -8,75 +8,75 @@ - - - + + + -
    Version: 0.15

    Css

    +
    Version: 0.15

    Css

    Farm support Css out of box, just import the css file:

    -
    import './index.css';
    +
    import './index.css';

    Then farm will auto enable HMR for css module, and generating bundled resources for css.

    -

    Css Modules

    +

    Css Modules

    Farm support css modules out of box, the modules end with .module.css|less|scss|sass will be treated as css modules by default.

    -
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    -
    index.module.css
    .main {
    color: green;
    }
    +
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    +
    index.module.css
    .main {
    color: green;
    }

    You can configuring css modules by css.modules. for example you can set css.modules.paths to ['.css|sass|less|scss'] then all css files will be treated as css modules.

    -

    Css Pre-Processor

    +

    Css Pre-Processor

    Farm provide official sass, less, postcss plugins to support css pre-processor.

    -

    Sass

    +

    Sass

    Farm sass plugin is a Rust Plugin and use sass-embeded(we may migrate to grass in the feature).

    Steps to compile sass/scss modules in Farm.

    1. Install dependencies
    -
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/plugin-sass
    +
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/plugin-sass
    1. Configure the plugin
    -
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: ['@farmfe/plugin-sass'] // to use a rust plugin, just configure its package name as a string
    // if you want to specify options for plugin-sass, use
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    };
    +
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: ['@farmfe/plugin-sass'] // to use a rust plugin, just configure its package name as a string
    // if you want to specify options for plugin-sass, use
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    };
    1. Import sass module
    -
    import './index.scss';
    +
    import './index.scss';

    To use sass with css modules, change the file name from index.scss to index.module.scss, see css modules.

    @farmfe/plugin-sass supports a lot of options, use the array syntax of plugins to specify options for plugin sass:

    -
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // if you want to specify options for plugin-sass, use
    plugins: [
    [
    '@farmfe/plugin-sass',
    // all supported options as below
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    };
    -

    Less

    +
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // if you want to specify options for plugin-sass, use
    plugins: [
    [
    '@farmfe/plugin-sass',
    // all supported options as below
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    };
    +

    Less

    Farm less plugin is a Js Plugin. Steps to compile less modules in Farm.

    1. Install dependencies
    -
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-less
    +
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-less
    1. Configure the plugin
    -
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default <UserConfig> {
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    +
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default <UserConfig> {
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    1. Import sass module
    -
    import './index.less';
    +
    import './index.less';

    To use sass with css modules, change the file name from index.less to index.module.less, see css modules

    -

    Postcss

    +

    Postcss

    The Farm postcss plugin is a JS plugin. The steps to introduce postcss in Farm are as follows:

    1. Install dependencies
    -
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-postcss
    +
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-postcss
    1. Configure the plugin
    -
    import type { UserConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default <UserConfig> {
    //...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    +
    import type { UserConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default <UserConfig> {
    //...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    1. Configure postcss.config.js and import the required postcss plugins
    -
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    -

    Css Prefixer

    +
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    +

    Css Prefixer

    Farm supports css prefixer out of box, you can configure it using compilation.css.prefixer.

    -
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });
    +
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });

    Then for input code:

    -
    div {
    display: flex;
    }
    +
    div {
    display: flex;
    }

    output code:

    -
    div{display:-ms-flexbox;display:flex}
    +
    div{display:-ms-flexbox;display:flex}
    \ No newline at end of file diff --git a/docs/0.x/features/html/index.html b/docs/0.x/features/html/index.html index e3799de95..94a7772ea 100644 --- a/docs/0.x/features/html/index.html +++ b/docs/0.x/features/html/index.html @@ -8,31 +8,31 @@ - - - + + + -
    Version: 0.15

    Html

    -

    Basic Usage

    +
    Version: 0.15

    Html

    +

    Basic Usage

    Farm support compile Html out of box, and you should use Html as entry when build a web project, for example:

    -
    farm.config.ts
    import type { defineConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    -
    note

    If the input is not specified, default to { index: 'index.html' }.

    +
    farm.config.ts
    import type { defineConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    +
    note

    If the input is not specified, default to { index: 'index.html' }.

    and in ./index.html, a <script src="./xxx"> should be used to refer to your script entry.

    -
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>
    +
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>

    and you can also use <link href="./xxx"> to refer to your global css.

    Farm will transform these scripts and links to final production resources when compiling. Note that you have to use relative path when you want to refer to a local module, for example <script src="./index.tsx"></script> will refer to a local module and compile it, but <script src="/index.tsx"></script> or <script src="https://xxx.com/index.tsx"></script> would not.

    -
    tip

    The script and link can refer to any module types that farm support, for example, js, jsx, ts, tsx, or other module types supported by plugins. You can use as many scripts or links as you want.

    -

    Multi Page App

    +
    tip

    The script and link can refer to any module types that farm support, for example, js, jsx, ts, tsx, or other module types supported by plugins. You can use as many scripts or links as you want.

    +

    Multi Page App

    If you are building a Multi Page Application, just configure multiple html input, for example:

    -
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    },
    });
    +
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    },
    });

    Farm will compile these pages in parallel, and all dependencies of these pages will be shared too.

    -

    Inherit html template

    +

    Inherit html template

    Farm supports inherit html template by using html.base config, which is helpful when building a multi-page application with html shared.

    -
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });
    +
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });

    Then add a base.html, placeholder {{children}} will be replaced by children's content.

    -
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- using children placeholder and it will be replaced -->
    {{children}}
    </body>
    </html>
    +
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- using children placeholder and it will be replaced -->
    {{children}}
    </body>
    </html>

    Inherit ./base.html:

    -
    ./src/home.html
    <!-- Other fields are inherit from ../base.html -->
    <script src="./index.tsx"></script>
    +
    ./src/home.html
    <!-- Other fields are inherit from ../base.html -->
    <script src="./index.tsx"></script>
    \ No newline at end of file diff --git a/docs/0.x/features/lazy-compilation/index.html b/docs/0.x/features/lazy-compilation/index.html index b74c31ced..19a6985fd 100644 --- a/docs/0.x/features/lazy-compilation/index.html +++ b/docs/0.x/features/lazy-compilation/index.html @@ -8,25 +8,25 @@ - - - + + + -
    Version: 0.15

    Lazy Compilation

    +
    Version: 0.15

    Lazy Compilation

    When comes to a big project, you may want to split them into small pieces and load on demand. This can be achieved by dynamic imports.

    -
    const page = React.lazy(() => import('./page')); // lazy load page
    +
    const page = React.lazy(() => import('./page')); // lazy load page

    By default, Farm will lazy compile these dynamic imports in development, only compile them when the module is really executed. Lazy compilation can really speedup the compiling of a large project.

    -
    note

    Lazy Compilation are always disabled for production build.

    +
    note

    Lazy Compilation are always disabled for production build.

    Note that it is important to use the dynamic import properly to make lazy compilation work better. For example, if one of your page has a big dependencies, but this dependencies won't be used until this page rendered, then it is necessary to make sure that this big dependencies are dynamic imported, so it won't be compiled util the page rendered.

    -

    Configuring Lazy Compilation

    +

    Configuring Lazy Compilation

    Using compilation.lazyCompilation to enable or disable it:

    -
    farm.config.ts
    export default {
    compilation: {
    lazyCompilation: true,
    },
    };
    -

    How Lazy Compilation Work

    +
    farm.config.ts
    export default {
    compilation: {
    lazyCompilation: true,
    },
    };
    +

    How Lazy Compilation Work

    When lazy compilation is enabled, Farm will analyze all of your dynamic import first, for example:

    -
    const page = React.lazy(() => import('./page'));
    +
    const page = React.lazy(() => import('./page'));

    Farm will treat ./page as a module that should be lazy compiled and won't compile it, instead, Farm will return a virtual placeholder module for ./page like:

    -
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // return a promise, this promise will be resolved when lazy compilation finished.
    let promise = Promise.resolve();

    // it has lazy been lazy compiling
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // request the dev server for lazy compilation
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    -

    Above example illustrated a basic structure of that virtual placeholder module. When the placeholder executed, it will request the dev server to compile this module and its dependencies. After getting the lazy compiled result from dev server, the placeholder module will patch these changes to Farm's runtime module system.

    +
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // return a promise, this promise will be resolved when lazy compilation finished.
    let promise = Promise.resolve();

    // it has lazy been lazy compiling
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // request the dev server for lazy compilation
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    +

    Above example illustrated a basic structure of that virtual placeholder module. When the placeholder executed, it will request the dev server to compile this module and its dependencies. After getting the lazy compiled result from dev server, the placeholder module will patch these changes to Farm's runtime module system.

    \ No newline at end of file diff --git a/docs/0.x/features/minification/index.html b/docs/0.x/features/minification/index.html index bd8c0656a..4d7daa5d5 100644 --- a/docs/0.x/features/minification/index.html +++ b/docs/0.x/features/minification/index.html @@ -8,20 +8,20 @@ - - - + + + -
    Version: 0.15

    Minification

    +
    Version: 0.15

    Minification

    Farm supports production minify out of box, which is automatically enabled in production by default. It can be enable or disable via the compilation.minify option.

    Using compilation.minify to configure:

    -
    farm.config.ts
    export default {
    compilation: {
    minify: true
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    minify: true
    },
    };

    If minify is enabled:

    • for js/ts modules, it will be minified and mangled, all the blank characters will be removed and the variables will be compressed.
    • for css and html modules, all spaces will be removed.
    -
    note

    Farm use swc minifier under the hood, all options of swc minifier can be used in Farm.

    +
    note

    Farm use swc minifier under the hood, all options of swc minifier can be used in Farm.

    \ No newline at end of file diff --git a/docs/0.x/features/partial-bundling/index.html b/docs/0.x/features/partial-bundling/index.html index f82f679b7..bb5ee496f 100644 --- a/docs/0.x/features/partial-bundling/index.html +++ b/docs/0.x/features/partial-bundling/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 0.15

    Partial Bundling

    +
    Version: 0.15

    Partial Bundling

    Partial Bundling is a strategy that Farm uses to bundle modules, similar to what other bundlers do but the goal of Farm's Partial Bundling is different.

    Unlike other bundlers, Farm will not trying to bundle everything together and then split them out using optimizations like splitChunks, on the opposite, Farm will bundle projects into several output files directly. For example, if there are hundreds of modules needed to launch a html page, Farm will try to bundle them into 20-30 output files directly. Farm calls this behavior Partial Bundling.

    Farm's goal of Partial Bundling is to:

    @@ -22,8 +22,8 @@
  • Increase cache hit rate: When a modules changed, makes sure that only a few output files are affected, so more cache can be used for a online project.
  • For traditional bundlers, we may have a hard time to configure complex splitChunks or manualChunks to achieve the goal above, but in Farm, it is supported natively through Partial Bundling.

    -
    tip

    Refer to RFC-003 Partial Bundling to get more technical details.

    -

    Motivation

    +
    tip

    Refer to RFC-003 Partial Bundling to get more technical details.

    +

    Motivation

    There are two main methods of handling modules in web build tools now: Bundling or native ESM. But they both have drawbacks:

    • For bundling, bundlers aim to bundle everything together and then split them out for optimization, but splitting is often hard to configure and is hard to balance resources loading performance and cache hit rate manually.
    • @@ -33,14 +33,14 @@

      Motivation

      I renamed Module Merging to Partial Bundling later because I think Partial Bundling can expresses more accurately what I was thinking.

      -

      Partial Bundling Rules

      +

      Partial Bundling Rules

      In this section, we will introduce the basic rules that Partial Bundling uses by examples.

      First we look into a basic react project example. For a basic react project like below, we only import react and react-dom in the entry script:

      -
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );
      +
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );

      The bundling result will looks like:

      -
      ./dist/
      ├── index_9c07.49b83356.js # contains react-dom
      ├── index_a35f.0ac21082.js # contains ./index.tsx
      ├── index_b7e0.7ab9ca2d.js # contains react and its dependencies
      ├── index_ce26.7f833381.css $ contains ./index.scss
      └── index.html # contains ./index.html
      +
      ./dist/
      ├── index_9c07.49b83356.js # contains react-dom
      ├── index_a35f.0ac21082.js # contains ./index.tsx
      ├── index_b7e0.7ab9ca2d.js # contains react and its dependencies
      ├── index_ce26.7f833381.css $ contains ./index.scss
      └── index.html # contains ./index.html

      Farm will bundle your project into 5 files by default:

      • 2 js files are from node_modules and contains react, react-dom and their dependencies.
      • @@ -57,7 +57,7 @@

        Parti
      • Output files should be of similar size and min resource size should be greater than 20KB by default: Because react-dom is the largest and more than 100KB, it is in a separate file, and react and its dependencies are smaller than 20KB, there are merged into the same output file.
      • Now we have familiar with Partial Bundling's basic rules, if met problems with partial bundling, using above rules to debug your project. Next we'll cover how to configure partial bundling.

        -

        Configuring Partial Bundling

        +

        Configuring Partial Bundling

        Partial Bundling supports a lot of options to let users customize its behavior. All the options are as below:

        1. targetConcurrentRequests: Farm tries to generate resource numbers as closer as possible to this config value for initial resource loading or a dynamic resource loading.
        2. @@ -82,27 +82,27 @@

          immutableModules: Regex array to match the immutable modules
        3. immutableModulesWeight: Default to 0.8, immutable module will have 80% request numbers. For example, if targetConcurrentRequest is 25, then immutable resources will take 25 * 80% = 20 by default. This option is to make sure that mutable and immutable modules are isolate, if change your business code, code under node_modules won't be affected.
        -
        note

        In general, you can use targetConcurrentRequests, targetMinSize and targetMaxSize to control the default behavior of Partial Bundling. The default value set by Farm is based on best practice, so make sure it's necessary when you want to change the default value.

        -

        Grouping Modules

        +
        note

        In general, you can use targetConcurrentRequests, targetMinSize and targetMaxSize to control the default behavior of Partial Bundling. The default value set by Farm is based on best practice, so make sure it's necessary when you want to change the default value.

        +

        Grouping Modules

        you can use groups to group modules together, for above basic react project example, using following configuration to make modules under node_modules are bundled together:

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });

        we add a group item with name and test to group react and react-dom together. The bundle result is:

        -
        ./dist/
        ├── index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules
        ├── index_a35f.0ac21082.js # contains `./index.tsx`
        ├── index_ce26.7f833381.css # contains `./index.scss`
        └── index.html # contains `./index.html`
        +
        ./dist/
        ├── index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules
        ├── index_a35f.0ac21082.js # contains `./index.tsx`
        ├── index_ce26.7f833381.css # contains `./index.scss`
        └── index.html # contains `./index.html`

        Now all modules under node_modules are bundled into index_499e.72cf733c.js. Note that groups is not not enforce that all modules matches this group are bundled, a group make produce multiple output file, because:

        1. mutable and immutable module are always in different output files. When both mutable and immutable modules hit this group, they will be in different output.
        2. when comes to a multi page app or dynamic imported entries, there may be shared modules, and these should modules are always in different output files.

        If you need to enforce modules in the same output files, you can use enforceResources

        -

        Using enforceResources

        +

        Using enforceResources

        To group all modules together and ignore all other conditions, you can use enforceResources, for example:

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });

        will produce:

        -
        ./dist/
        ├── index.7f833381.css # all css modules are bundled together
        ├── index.ba5550d9.js # all script modules are bundled together
        └── index.html
        -
        warning

        enforceResources will ignore all Farm's internal optimization, be careful when you use it.

        -

        Configuring immutable modules

        +
        ./dist/
        ├── index.7f833381.css # all css modules are bundled together
        ├── index.ba5550d9.js # all script modules are bundled together
        └── index.html
        +
        warning

        enforceResources will ignore all Farm's internal optimization, be careful when you use it.

        +

        Configuring immutable modules

        Using immutableModules to configure immutable modules, by default, Farm set it to node_modules/.

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        immutableModules: ['node_modules/', '/global-constants']
        },
        },
        });
        -

        Immutable module can affect bundling and incoming persistent cache, be careful if you want to change it.

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ['node_modules/', '/global-constants']
    },
    },
    });
    +

    Immutable module can affect bundling and incoming persistent cache, be careful if you want to change it.

    \ No newline at end of file diff --git a/docs/0.x/features/persistent-cache/index.html b/docs/0.x/features/persistent-cache/index.html index 0a630177f..271f10353 100644 --- a/docs/0.x/features/persistent-cache/index.html +++ b/docs/0.x/features/persistent-cache/index.html @@ -8,22 +8,22 @@ - - - + + + -
    Version: 0.15

    Incremental Building

    -
    tip

    Farm supports incremental build by persistent cache since v0.14.0

    +
    Version: 0.15

    Incremental Building

    +
    tip

    Farm supports incremental build by persistent cache since v0.14.0

    Since v0.14.0, Farm supports cache the compiled result to disk, which can greatly speed up the compilation for hot start/hot build. When persistentCache is enabled, the compilation time can reduce up to 80%.

    Performance compare between cold start(without cache) and hot start(with cache) using examples/argo-pro:

    Cold(without cache)Hot(with cache)diff
    start1519ms371msreduced 75%
    build3582ms562msreduced 84%
    -

    Using Cache

    +

    Using Cache

    Using compilation.persistentCache to enable/disable Cache:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    persistentCache: true,
    },
    });
    -
    note

    persistentCache: true is equal to:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: "node_modules/.farm/cache",
    // namespace of the cache
    namespace: "farm-cache",
    buildDependencies: [
    "farm.config.ts",
    "@farmfe/core",
    "@farmfe/plugin-react",
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    },
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    persistentCache: true,
    },
    });
    +
    note

    persistentCache: true is equal to:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: "node_modules/.farm/cache",
    // namespace of the cache
    namespace: "farm-cache",
    buildDependencies: [
    "farm.config.ts",
    "@farmfe/core",
    "@farmfe/plugin-react",
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    },
    },
    });

    Configuring persistentCache to false to disable cache.

    -

    Cache Validation

    +

    Cache Validation

    Cache will be validated when trying to reuse it by following conditions, if any of following conditions changed, all cache will be invalidated:

    • @@ -40,20 +40,20 @@

      Cache Valid
    • Internal Cache Version: Farm maintains a cache version internally, if Farm itself changed, for example, render optimization that affects the output between versions of Farm, Farm will bump the cache version and all cache will be invalidated.

    If your cache does not work, check out above conditions to figure out the reason. If the cache is broken, you can also delete node_modules/.farm/cache to remove cache manually.

    -

    Build Dependencies

    +

    Build Dependencies

    Build dependencies is dependencies that can affect the compilation process or compiled output, for examples, plugins or config files. If any of these dependencies changed, all cache will be invalidated.

    Build dependencies can be a file path for a package name, for example:

    -
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    -
    note

    By default, all config files and its dependencies are included. But if you want to add some additional files or dependencies to invalidate the cache, you can using buildDependencies once these files changed, all cache will be invalidated.

    -

    Module Cache Key Strategy

    +
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    +
    note

    By default, all config files and its dependencies are included. But if you want to add some additional files or dependencies to invalidate the cache, you can using buildDependencies once these files changed, all cache will be invalidated.

    +

    Module Cache Key Strategy

    Farm provides 2 strategies to control how to generate module cache key:

    • timestamp: whether check timestamp of the module, if the update timestamp does not change, the build of this module will be skipped, which has the best performance.
    • hash: whether check content hash after load and transform, if the content does not change, the left build of this module will be skipped.

    By default timestamp and hash are both enabled.

    -

    Caveats For Plugins

    +

    Caveats For Plugins

    when timestamp is enabled, all build stages hooks like load and transform won't be called. So if the plugin relies load and transform and it does not implement plugin_cache_loaded and write_plugin_cache hook, it may not work as expected. For example, if a plugin collect information in load and transform, all emit them at finish hook, it should implement plugin_cache_loaded and write_plugin_cache hook to load and write cache, otherwise it will not work as expected.

    -

    Farm will set timestamp to false when output.targetEnv is node.

    +

    Farm will set timestamp to false when output.targetEnv is node.

    \ No newline at end of file diff --git a/docs/0.x/features/polyfill/index.html b/docs/0.x/features/polyfill/index.html index e28468a67..1fd35fac4 100644 --- a/docs/0.x/features/polyfill/index.html +++ b/docs/0.x/features/polyfill/index.html @@ -8,21 +8,21 @@ - - - + + + -
    Version: 0.15

    Syntax Downgrade and Polyfill

    +
    Version: 0.15

    Syntax Downgrade and Polyfill

    By default, Farm will downgrade to ES5 and inject polyfills automatically in production mode.

    -
    note

    By default, Farm won't do transformation and inject polyfills for modules under node_modules/, if you need to downgrade syntax and inject polyfills for node_modules/ you can use compilation.presetEnv.include.

    -

    Configuring presetEnv

    +
    note

    By default, Farm won't do transformation and inject polyfills for modules under node_modules/, if you need to downgrade syntax and inject polyfills for node_modules/ you can use compilation.presetEnv.include.

    +

    Configuring presetEnv

    You can use compilation.presetEnv to custom syntax downgrade and polyfill. Using include to add external modules that need to be polyfilled.s

    -
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "Chrome >= 48"
    }
    }
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "Chrome >= 48"
    }
    }
    },
    };

    By default, Farm will set targets to > 0.25%, not dead. If your project does not require browser compatibility, you can use set a looser value for targets, then less polyfills will be injected and output sizes will be smaller.

    Refer to compilation.presetEnv for more options.

    -

    With script.target

    +

    With script.target

    script.target can also control the target env when generate code. If you want to downgrade your project to ES5, you should set both:

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5'
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "> 0.25%, not dead"
    }
    }
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5'
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "> 0.25%, not dead"
    }
    }
    },
    };
    \ No newline at end of file diff --git a/docs/0.x/features/script/index.html b/docs/0.x/features/script/index.html index 10f80c7ad..f60ceae14 100644 --- a/docs/0.x/features/script/index.html +++ b/docs/0.x/features/script/index.html @@ -8,54 +8,54 @@ - - - + + + -
    Version: 0.15

    Script

    +
    Version: 0.15

    Script

    Farm support compiling Js/Jsx/Ts/Tsx out of box, and compile Jsx/Tsx to React by default.

    -
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }
    +
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }

    Farm using SWC to compile scripts, and Farm has set reasonable default configurations for script compilation. Also, you can use compilation.script to configure how to compile your script file. see compilation.script for details.

    -

    Configuring Swc Parser

    +

    Configuring Swc Parser

    You can configuring the SWC Parser through compilation.script.parser. Refer to https://swc.rs/docs/configuration/compilation#jscparser.

    For example, if you want to enable decorator, you can set compilation.script.parser.esConfig.decorators(or tsConfig.decorators if the module is TS):

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    };

    By default Farm set jsx: true for .jsx|.tsx files. Other field are default to SWC's defaults.

    -

    Configuring Target

    +

    Configuring Target

    Using compilation.script.target to configure your target env when running your project, Farm set it default to ESNext.

    This option can be used along with compilation.presetEnv to gracefully downgrade your project for old browsers. For example, you can set target to ES5 and enable presetEnv, then your project will be fully downgrade to ES5.

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    };

    Refer to Polyfill for more about presetEnv.

    -

    Decorators

    +

    Decorators

    Decorators is disabled by default, you can set compilation.script.parser.tsConfig.decorators to true to enable decorators.

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // support decorators
    decorators: true,
    },
    },
    // configuring decorators
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // support decorators
    decorators: true,
    },
    },
    // configuring decorators
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });

    Farm provide a example for supporting decorators, see https://github.com/farm-fe/farm/tree/main/examples/decorators By default, Farm won't transform decorators for modules under node_modules, refer to compilation.script.decorators.excludes.

    -

    Using SWC Plugins

    +

    Using SWC Plugins

    SWC Plugins can be used directly in Farm, for example, we use swc-plugin-vue-jsx to compiling vue jsx in Farm:

    -
    farm.config.ts
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };
    +
    farm.config.ts
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };

    Refer to Using Plugins for more details.

    -

    Vite-style import.meta.glob

    +

    Vite-style import.meta.glob

    Farm fully support Vite-style import.meta.glob, see glob import.

    for example:

    -
    const modules = import.meta.glob("./dir/*.js");
    +
    const modules = import.meta.glob("./dir/*.js");

    The above will be transformed into the following:

    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };
    +
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };

    Using { eager: true }:

    -
    const modules = import.meta.glob("./dir/*.js", { eager: true });
    +
    const modules = import.meta.glob("./dir/*.js", { eager: true });

    The above will be transformed into the following:

    -
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };
    +
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };

    multiple patterns are supported:

    -
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);
    +
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);

    negative patterns are also supported:

    -
    const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    };
    -
    note
      +
      const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
      +
      // code produced by Farm
      const modules = {
      "./dir/foo.js": () => import("./dir/foo.js"),
      };
      +
      note
      • You should also be aware that all the arguments in the import.meta.glob must be passed as literals. You can NOT use variables or expressions in them.
      • import.meta.glob transformed by Farm in compile time, it does not exist in runtime.
      • -
    +
    \ No newline at end of file diff --git a/docs/0.x/features/sourcemap/index.html b/docs/0.x/features/sourcemap/index.html index 1d7fde7ec..82529018b 100644 --- a/docs/0.x/features/sourcemap/index.html +++ b/docs/0.x/features/sourcemap/index.html @@ -8,16 +8,16 @@ - - - + + + -
    Version: 0.15

    Source Map

    +
    Version: 0.15

    Source Map

    Farm supports Source Map, which is automatically enabled by default. It can be enable or disable sourcemap via the compilation.sourcemap option.

    -
    note

    Farm will not generate sourcemap for files under node_modules by default, if you want to generate sourcemap for files under node_modules, configure compilation.sourcemap to all.

    +
    note

    Farm will not generate sourcemap for files under node_modules by default, if you want to generate sourcemap for files under node_modules, configure compilation.sourcemap to all.

    Using compilation.sourcemap to configuring sourcemap generation:

    -
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };

    All options are as below:

    • true: Only generate sourcemap for files not under node_modules, and generate a separate sourcemap file
    • @@ -25,6 +25,6 @@
    • inline: Only generate sourcemap for files not under node_modules, and inline sourcemap into the product, do not generate a separate file
    • all: generate sourcemap for all files, and generate a separate sourcemap file
    • all-inline: Generate sourcemaps for all files, and inline sourcemaps into the product, do not generate separate files
    • -
    +
    \ No newline at end of file diff --git a/docs/0.x/features/static/index.html b/docs/0.x/features/static/index.html index 95b87b563..c3c0cb5ff 100644 --- a/docs/0.x/features/static/index.html +++ b/docs/0.x/features/static/index.html @@ -8,33 +8,33 @@ - - - + + + -
    Version: 0.15

    Static Assets

    +
    Version: 0.15

    Static Assets

    Since v0.4 Farm supports three resource loading methods: url, inline, raw

    -

    url

    +

    url

    Import a image:

    -
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }
    +
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }

    Default to use url method when import a image. When using url methods to import a image, the image will be emitted to the output dir directly, and the image module itself will be compiled to a js module like:

    -
    export default '/rocket.<content hash>.svg'
    +
    export default '/rocket.<content hash>.svg'

    using compilation.output.assetFilename to config your asset name。

    -

    inline

    +

    inline

    Using query ?inline to tell Farm that you want to inline your assets,then the assets will be transformed to base64,for example:

    -
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    -

    raw

    +
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    +

    raw

    Using query ?raw to tell Farm that you want to read the raw string of the assets, for example

    -
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    -

    Configuring Assets

    +
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    +

    Configuring Assets

    • Using compilation.output.assetFileName to control the production file name
    • using compilation.assets.include to treat more kind of files as asset modules.
    -
    export default {
    compilation: {
    output: {
    assetFilename: 'assets/[resourceName].[hash].[ext]', // [] is a placeholder, Farm currently only these three kind of placeholders
    },
    assets: {
    include: ['txt'] // extra static asset extension
    }
    }
    }
    +
    export default {
    compilation: {
    output: {
    assetFilename: 'assets/[resourceName].[hash].[ext]', // [] is a placeholder, Farm currently only these three kind of placeholders
    },
    assets: {
    include: ['txt'] // extra static asset extension
    }
    }
    }
    \ No newline at end of file diff --git a/docs/0.x/features/tree-shake/index.html b/docs/0.x/features/tree-shake/index.html index c9787eb0f..f878d572d 100644 --- a/docs/0.x/features/tree-shake/index.html +++ b/docs/0.x/features/tree-shake/index.html @@ -8,26 +8,26 @@ - - - + + + -
    Version: 0.15

    Tree Shake

    +
    Version: 0.15

    Tree Shake

    Farm supports Tree Shake, which is automatically enabled in the default Production environment. It can be turned on or off by the compilation.treeShake option.

    During Tree Shake, the sideEffects field in package.json will be automatically read, and modules with sideEffects will not perform Tree Shake.

    -
    note

    Farm will treat all circularly dependent modules as sideEffects and will not perform Tree Shake. Please try to avoid circular dependencies in your project.

    +
    note

    Farm will treat all circularly dependent modules as sideEffects and will not perform Tree Shake. Please try to avoid circular dependencies in your project.

    Tree shake example:

    -
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    export b2 = "B2";
    +
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";
    export b2 = "B2";

    a.js is entry and it imports b.js, after tree shaking, the result is:

    -
    a.js
    import { b1 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    +
    a.js
    import { b1 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";

    b2 is not used and will be removed in both a.js and b.js

    -

    Configuring Tree Shake

    +

    Configuring Tree Shake

    Tree Shake is enabled in production mode by default, to disable tree shake, use compilation.treeShake:

    -
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    -

    Deal With Side Effects

    +
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    +

    Deal With Side Effects

    When a module contains side effects, Farm won't apply tree shake for it, and all of its imported and exports are treated as used. Farm will think following modules have side effects:

    1. CommonJs modules always have side effects.
    2. @@ -37,16 +37,16 @@

      Deal
    3. Entry modules are always has side effects.

    Example 1:

    -
    const a = require('./')
    module.exports = a;
    +
    const a = require('./')
    module.exports = a;

    CommonJs module are always has side effects.

    Example 2:

    -
    import a from './';

    a();
    +
    import a from './';

    a();

    a() is executed at global scope and we treat it as side effect.

    Example 3:

    -
    // a.js
    import b from './b.js'

    // b.js
    import a from './a.js'
    +
    // a.js
    import b from './b.js'

    // b.js
    import a from './a.js'

    a, b are cyclic dependencies, so they will be treated as side effects too.

    Example 4:

    -
    package.json
    {
    "name": "my-package",
    "sideEffects": [
    "./global/**.ts"
    ]
    }
    -

    all ts modules under global/ are treat as side effects.

    +
    package.json
    {
    "name": "my-package",
    "sideEffects": [
    "./global/**.ts"
    ]
    }
    +

    all ts modules under global/ are treat as side effects.

    \ No newline at end of file diff --git a/docs/0.x/plugins/community-plugins/index.html b/docs/0.x/plugins/community-plugins/index.html index 0bcc48edd..f5e78335c 100644 --- a/docs/0.x/plugins/community-plugins/index.html +++ b/docs/0.x/plugins/community-plugins/index.html @@ -8,18 +8,18 @@ - - - + + + -
    Version: 0.15

    Community Plugins

    +
    Version: 0.15

    Community Plugins

    Farm support Vite/Rollup plugins out of box. So Vite/Rollup or unplugin plugins can be used in Farm directly.

    -
    tip

    PR welcome if you developed a Farm compatible plugin and you want to list it here.

    +
    tip

    PR welcome if you developed a Farm compatible plugin and you want to list it here.

    Current tested compatible Vite/Rollup/unplugin plugins as below:

    -

    Vite/Rollup Plugins

    +

    Vite/Rollup Plugins

    using vitePlugins in farm.config.ts to configure Vite/Rollup plugins.

    -
    import { UserConfig } from '@farmfe/core';
    import vue from '@vitejs/plugin-vue';
    import vueJsx from '@vitejs/plugin-vue-jsx';

    const config: UserConfig = {
    vitePlugins: [
    vue(),
    vueJsx(),
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import vue from '@vitejs/plugin-vue';
    import vueJsx from '@vitejs/plugin-vue-jsx';

    const config: UserConfig = {
    vitePlugins: [
    vue(),
    vueJsx(),
    ]
    }
    -

    unplugin

    -
    note

    Currently you can use unplugin/vite or unplugin/rollup in Farm. unplugin/farm will be available when this PR are merged into unplugin

    -
    import Icons from 'unplugin-icons/vite';
    import IconsResolver from 'unplugin-icons/resolver';
    import Components from 'unplugin-vue-components/rollup';
    import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
    import { FileSystemIconLoader } from 'unplugin-icons/loaders';

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: 'vue3',
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, svg =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    )
    },
    scale: 1,
    defaultClass: 'inline-block'
    }),
    Components({
    dts: 'src/typings/components.d.ts',
    types: [{ from: 'vue-router', names: ['RouterLink', 'RouterView'] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFIX })
    ]
    })
    ]
    }
    +

    unplugin

    +
    note

    Currently you can use unplugin/vite or unplugin/rollup in Farm. unplugin/farm will be available when this PR are merged into unplugin

    +
    import Icons from 'unplugin-icons/vite';
    import IconsResolver from 'unplugin-icons/resolver';
    import Components from 'unplugin-vue-components/rollup';
    import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
    import { FileSystemIconLoader } from 'unplugin-icons/loaders';

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: 'vue3',
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, svg =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    )
    },
    scale: 1,
    defaultClass: 'inline-block'
    }),
    Components({
    dts: 'src/typings/components.d.ts',
    types: [{ from: 'vue-router', names: ['RouterLink', 'RouterView'] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFIX })
    ]
    })
    ]
    }

    All unplugin are supported in Farm:

    +
    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/js-dts/index.html b/docs/0.x/plugins/official-plugins/js-dts/index.html index 3a233d9d6..8c4eb0032 100644 --- a/docs/0.x/plugins/official-plugins/js-dts/index.html +++ b/docs/0.x/plugins/official-plugins/js-dts/index.html @@ -8,18 +8,18 @@ - - - + + + -
    Version: 0.15

    @farmfe/js-plugin-dts

    +
    Version: 0.15

    @farmfe/js-plugin-dts

    Support Generate .d.ts files for Farm. This plugin is used for building tools and libraries, generate .d.ts for your typescript code.

    -

    Installation

    -
    npm install @farmfe/js-plugin-dts
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    -

    Options

    -
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    +

    Installation

    +
    npm install @farmfe/js-plugin-dts
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    +

    Options

    +
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/js-less/index.html b/docs/0.x/plugins/official-plugins/js-less/index.html index 60b370660..8bab794ac 100644 --- a/docs/0.x/plugins/official-plugins/js-less/index.html +++ b/docs/0.x/plugins/official-plugins/js-less/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 0.15

    @farmfe/js-plugin-less

    +
    Version: 0.15

    @farmfe/js-plugin-less

    Support less for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-less less
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    -

    Options

    -
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    lessOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-less less
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    +

    Options

    +
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    lessOptions

    Less options. See less options.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by less. default to { resolvedPaths: ['\\.less$'] } for load and { moduleTypes: ['less'] } for transform.

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-less$'],
    moduleTypes: ['less']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    implementation package name of less. Default to less.

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    Additional data to be added to every less file. Example:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }

    For less file:

    -
    index.less
    .foo {
    color: @primary-color;
    }
    +
    index.less
    .foo {
    color: @primary-color;
    }

    additionalData will be added to the top of the file:

    -
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }
    +
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }

    Function form:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/js-postcss/index.html b/docs/0.x/plugins/official-plugins/js-postcss/index.html index 080eaa682..2717b4b70 100644 --- a/docs/0.x/plugins/official-plugins/js-postcss/index.html +++ b/docs/0.x/plugins/official-plugins/js-postcss/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 0.15

    @farmfe/js-plugin-postcss

    +
    Version: 0.15

    @farmfe/js-plugin-postcss

    Support postcss for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-postcss postcss
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    -

    Options

    -
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    -

    postcssLoadConfig

    +

    Installation

    +
    npm install @farmfe/js-plugin-postcss postcss
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    +

    Options

    +
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    +

    postcssLoadConfig

    Farm uses postcss-load-config to load postcss config, so you can use postcss-load-config's options. Refer to postcss-load-config.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by postcss. default to { moduleTypes: ['css'] }.

    -

    implementation

    -

    implementation package name of postcss. Default to postcss.

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-css$'],
    moduleTypes: ['css']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    +

    implementation package name of postcss. Default to postcss.

    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/js-sass/index.html b/docs/0.x/plugins/official-plugins/js-sass/index.html index b6e37a8c1..a252d4d1c 100644 --- a/docs/0.x/plugins/official-plugins/js-sass/index.html +++ b/docs/0.x/plugins/official-plugins/js-sass/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 0.15

    @farmfe/js-plugin-sass

    +
    Version: 0.15

    @farmfe/js-plugin-sass

    Support sass for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-sass sass
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    -

    Options

    -
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    sassOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-sass sass
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    +

    Options

    +
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    sassOptions

    Sass options. See sass options for more details.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by sass. Default to { resolvedPaths: ['\\.(s[ac]ss)$'] } for load and { moduleTypes: ['sass'] } for transform.

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-sass$'],
    moduleTypes: ['sass']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    implementation package name of sass. Default to sass. If you want to use sass-embedded, you can set it to sass-embedded.

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    -
    note

    You should install sass-embedded manually.

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    +
    note

    You should install sass-embedded manually.

    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    Additional data to be added to every sass file. Example:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }

    For sass file:

    -
    index.scss
    .foo {
    color: @primary-color;
    }
    +
    index.scss
    .foo {
    color: @primary-color;
    }

    additionalData will be added to the top of the file:

    -
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }
    +
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }

    Function form:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    -

    globals

    -

    Global sass files. These files will be added to the top of every sass file. It's the same as additionalData but more convenient.

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    +

    globals

    +

    Global sass files. These files will be added to the top of every sass file. It's the same as additionalData but more convenient.

    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/js-svgr/index.html b/docs/0.x/plugins/official-plugins/js-svgr/index.html index fc779a193..f1e6632bb 100644 --- a/docs/0.x/plugins/official-plugins/js-svgr/index.html +++ b/docs/0.x/plugins/official-plugins/js-svgr/index.html @@ -8,29 +8,29 @@ - - - + + + -
    Version: 0.15

    @farmfe/js-plugin-svgr

    +
    Version: 0.15

    @farmfe/js-plugin-svgr

    Support React SVG Components for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-svgr
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    -

    Options

    -
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    -

    svgrOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-svgr
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    +

    Options

    +
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    +

    svgrOptions

    See svgr options for more details.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by svgr. Default to { resolvedPaths: ['\\.svg$'] }.

    • resolvedPaths: Only files under these paths will be processed. Support regex.

    Example:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/overview/index.html b/docs/0.x/plugins/official-plugins/overview/index.html index 08a979516..b04f93fb9 100644 --- a/docs/0.x/plugins/official-plugins/overview/index.html +++ b/docs/0.x/plugins/official-plugins/overview/index.html @@ -8,20 +8,20 @@ - - - + + + -
    Version: 0.15

    Overview

    +
    Version: 0.15

    Overview

    Farm officially provides a lot of useful plugins, including Rust plugins and JS plugins. Rust plugins are much faster than Js plugins, we recommend to use Rust plugins whenever possible.

    -
    tip

    Refer to Using Plugins for how to use plugins in Farm.

    -

    Rust Plugins

    +
    tip

    Refer to Using Plugins for how to use plugins in Farm.

    +

    Rust Plugins

    -

    Js Plugins

    +

    Js Plugins

    -
    tip

    If official plugins doesn't meet your needs, you can try Community Plugins

    +
    tip

    If official plugins doesn't meet your needs, you can try Community Plugins

    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/react/index.html b/docs/0.x/plugins/official-plugins/react/index.html index 1c7edc320..268adb4a6 100644 --- a/docs/0.x/plugins/official-plugins/react/index.html +++ b/docs/0.x/plugins/official-plugins/react/index.html @@ -8,19 +8,19 @@ - - - + + + -
    Version: 0.15

    @farmfe/plugin-react

    +
    Version: 0.15

    @farmfe/plugin-react

    Support React Jsx and React Refresh for Farm.

    -

    Installation

    -
    npm install @farmfe/plugin-react
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-react
    +

    Usage

    @farmfe/plugin-react is a Rust plugin, you only need to configure its package name in plugins field in farm.config.ts.

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    -

    Options

    -

    See SWC Transform React Options.

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    +

    Options

    +

    See SWC Transform React Options.

    \ No newline at end of file diff --git a/docs/0.x/plugins/official-plugins/sass/index.html b/docs/0.x/plugins/official-plugins/sass/index.html index 8356a601c..905c715e0 100644 --- a/docs/0.x/plugins/official-plugins/sass/index.html +++ b/docs/0.x/plugins/official-plugins/sass/index.html @@ -8,23 +8,23 @@ - - - + + + -
    Version: 0.15

    @farmfe/plugin-sass

    +
    Version: 0.15

    @farmfe/plugin-sass

    Support Sass for Farm.

    -

    Installation

    -
    npm install @farmfe/plugin-sass
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-sass
    +

    Usage

    @farmfe/plugin-sass is a Rust plugin, you only need to configure its package name in plugins field in farm.config.ts.

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    -

    Options

    -

    additionalData

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    +

    Options

    +

    additionalData

    • Type: string
    -

    Add extra content to the head of each sass file, such as an @import '@/styles/variables.scss'; statement.

    +

    Add extra content to the head of each sass file, such as an @import '@/styles/variables.scss'; statement.

    \ No newline at end of file diff --git a/docs/0.x/plugins/writing-plugins/js-plugin/index.html b/docs/0.x/plugins/writing-plugins/js-plugin/index.html index b5939becb..513b3fa3b 100644 --- a/docs/0.x/plugins/writing-plugins/js-plugin/index.html +++ b/docs/0.x/plugins/writing-plugins/js-plugin/index.html @@ -8,15 +8,15 @@ - - - + + + -
    Version: 0.15

    JavaScript Plugins

    -
    Js Plugins

    A JavaScript plugin is simply a pure JavaScript object.

    -
    // farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    plugins: [
    // a plugin object
    {
    name: "my-resolve-plugin",
    priority: 1000, // the priority of this plugin, the larger the value, the earlier the execution. Normally internal plugins is 100.
    resolve: {
    filters: {
    // Only execute the hook when following conditions satisfied
    sources: ["\\./index.ts"], // a regex array
    importers: ["None"],
    },
    executor: async (param) => {
    // this hook executor
    console.log(param); // resolve params
    // return the resolve result
    return {
    resolvedPath: "virtual:my-module",
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // load, transform are similar to resolve, refer to their types
    ],
    });
    +
    Version: 0.15

    JavaScript Plugins

    +
    Js Plugins

    A JavaScript plugin is simply a pure JavaScript object.

    +
    // farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    plugins: [
    // a plugin object
    {
    name: "my-resolve-plugin",
    priority: 1000, // the priority of this plugin, the larger the value, the earlier the execution. Normally internal plugins is 100.
    resolve: {
    filters: {
    // Only execute the hook when following conditions satisfied
    sources: ["\\./index.ts"], // a regex array
    importers: ["None"],
    },
    executor: async (param) => {
    // this hook executor
    console.log(param); // resolve params
    // return the resolve result
    return {
    resolvedPath: "virtual:my-module",
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // load, transform are similar to resolve, refer to their types
    ],
    });

    If you want to pass args to your plugins,you can use a closure.

    -
    // my-resolve-plugin.ts
    export function myResolvePlugin(options: Options) {
    const { xx } = options;

    return {
    name: "my-resolve-plugin",
    resolve: {
    // ...
    },
    };
    }

    // farm.config.ts
    import { defineConfig } from "@farmfe/core";
    import { myResolvePlugin } from "./myResolvePlugin.ts";

    export default defineConfig({
    // ...
    plugins: [myResolvePlugin({ xx: "xx" })],
    });
    +
    // my-resolve-plugin.ts
    export function myResolvePlugin(options: Options) {
    const { xx } = options;

    return {
    name: "my-resolve-plugin",
    resolve: {
    // ...
    },
    };
    }

    // farm.config.ts
    import { defineConfig } from "@farmfe/core";
    import { myResolvePlugin } from "./myResolvePlugin.ts";

    export default defineConfig({
    // ...
    plugins: [myResolvePlugin({ xx: "xx" })],
    });
    \ No newline at end of file diff --git a/docs/0.x/plugins/writing-plugins/overview/index.html b/docs/0.x/plugins/writing-plugins/overview/index.html index a4961dac3..f6635e887 100644 --- a/docs/0.x/plugins/writing-plugins/overview/index.html +++ b/docs/0.x/plugins/writing-plugins/overview/index.html @@ -8,18 +8,18 @@ - - - + + + -
    Version: 0.15

    Overview

    +
    Version: 0.15

    Overview

    To use a Rust plugin, configuring plugins in farm.config.ts.

    -
    import { defineFarmConfig } from '@farmfe/core/dist/config';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    +
    import { defineFarmConfig } from '@farmfe/core/dist/config';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    Farm support both rust plugins and js plugins:

    +
    \ No newline at end of file diff --git a/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html b/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html index 2f5fd8517..a86844d59 100644 --- a/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html +++ b/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html @@ -8,12 +8,12 @@ - - - + + + -
    +
    \ No newline at end of file diff --git a/docs/0.x/plugins/writing-plugins/rust-plugin/index.html b/docs/0.x/plugins/writing-plugins/rust-plugin/index.html index d0f54d073..8e9eb0d27 100644 --- a/docs/0.x/plugins/writing-plugins/rust-plugin/index.html +++ b/docs/0.x/plugins/writing-plugins/rust-plugin/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 0.15

    Rust Plugins

    -

    Rust Plugins are not stable for now...

    +
    Version: 0.15

    Rust Plugins

    +

    Rust Plugins are not stable for now...

    \ No newline at end of file diff --git a/docs/0.x/quick-start/index.html b/docs/0.x/quick-start/index.html index a645d809e..a1461a415 100644 --- a/docs/0.x/quick-start/index.html +++ b/docs/0.x/quick-start/index.html @@ -8,38 +8,38 @@ - - - + + + -
    Version: 0.15

    Quick Start

    -
    note

    Farm needs Node 16.19.0 and above.

    -

    Online experience

    -

    Edit Farm

    -

    Create a Farm Project

    -
    npm create farm@latest
    -
    Then follow the prompts!

    You can also directly specify the project name and the template you want to use via additional command line options:

    -
    npm create farm@latest my-vue-app --template react
    -

    2. Start the Project

    +
    Version: 0.15

    Quick Start

    +
    note

    Farm needs Node 16.19.0 and above.

    +

    Online experience

    +

    Edit Farm

    +

    Create a Farm Project

    +
    npm create farm@latest
    +
    Then follow the prompts!

    You can also directly specify the project name and the template you want to use via additional command line options:

    +
    npm create farm@latest my-vue-app --template react
    +

    2. Start the Project

    Choose the package manager you like, then the dependencies will be installed automatically. Then, start the project:

    -
    cd farm-project && npm start
    +
    cd farm-project && npm start

    The project will start at http://localhost:9000 by default.

    -

    3. Configuring the Project

    +

    3. Configuring the Project

    The project is configured by farm.config.ts/js/mjs file in the root directory of the project.

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // Options related to the compilation
    compilation: {
    input: {
    // can be a relative path or an absolute path
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Options related to the dev server
    server: {
    port: 9000,
    // ...
    },
    // Additional plugins
    plugins: [],
    });
    -
    note

    Refer to Config Reference for more details of configuring Farm.

    -

    4. Building the project

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // Options related to the compilation
    compilation: {
    input: {
    // can be a relative path or an absolute path
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Options related to the dev server
    server: {
    port: 9000,
    // ...
    },
    // Additional plugins
    plugins: [],
    });
    +
    note

    Refer to Config Reference for more details of configuring Farm.

    +

    4. Building the project

    Build the Farm project as production-ready static files:

    -
    npm run build
    +
    npm run build

    The built product is downgraded to ES5 by default, and the product will be compressed and Tree Shake. If you want to preview the build product locally, you can execute npm run preview or npx farm preview.

    -

    Next Steps

    +

    Next Steps

    +
    \ No newline at end of file diff --git a/docs/0.x/tutorials/build/index.html b/docs/0.x/tutorials/build/index.html index 662047d63..7dcae7a96 100644 --- a/docs/0.x/tutorials/build/index.html +++ b/docs/0.x/tutorials/build/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 0.15

    Build For Production

    +
    Version: 0.15

    Build For Production

    By default, Farm has enabled support for the following features for production builds:

    • Tree Shake: Crop and filter irrelevant modules and code
    • @@ -21,18 +21,18 @@
    • Automatically inject Polyfill: Farm downgrades projects to ES5 by default, which means that the products built by Farm can run on almost all browsers
    • Automatic partial packaging: Based on dependencies and size, the project is partially packaged. For each resource request, about 25 resources are generated to ensure parallel loading performance and improve cache hits as much as possible. Rate
    -

    Add build script

    +

    Add build script

    Add build script in package.json:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build"
    },
    // ...ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build"
    },
    // ...ignore other fields
    }

    Then execute npm run build.

    -

    Configure Tree Shake and compression

    +

    Configure Tree Shake and compression

    -

    Configure Partial Bundling

    +

    Configure Partial Bundling

    +
    \ No newline at end of file diff --git a/docs/0.x/tutorials/create/index.html b/docs/0.x/tutorials/create/index.html index e4cf7a71f..eed44f0a0 100644 --- a/docs/0.x/tutorials/create/index.html +++ b/docs/0.x/tutorials/create/index.html @@ -8,35 +8,35 @@ - - - + + + -
    Version: 0.15

    Create A Project

    +
    Version: 0.15

    Create A Project

    In this chapter, we will create a new Farm React project from scratch, and launch it in development mode.

    -
    note

    In this tutorial, we use pnpm as default package manager. This chapter is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm.

    -

    Create A Package

    +
    note

    In this tutorial, we use pnpm as default package manager. This chapter is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm.

    +

    Create A Package

    First we execute pnpm init to create a new package.

    -
    mkdir farm-react && cd farm-react && pnpm init
    +
    mkdir farm-react && cd farm-react && pnpm init

    A package.json file will be autogenerated.

    -

    Install Dependencies

    +

    Install Dependencies

    Install necessary dependencies:

    react and react-dom:

    -
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D
    +
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D

    farm related dependencies:

    -
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react
    +
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react

    There are 3 packages that are necessary for a react project:

    • @farmfe/cli: This package provides commands like farm start, farm build, farm preview, it must be used with @farmfe/core and can not be used separately.
    • @farmfe/core: This package provides Compilation and Dev Server abilities, provides all necessary component for local development and product build. It exports Compiler, DevServer and Watcher, which is used for compile the project, serve the project in development mode and watch the project for Hot Module Replacement.
    • @farmfe/plugin-react: This package provides abilities for React Jsx compilation, and react-refresh support.
    -

    Create Farm Config File

    +

    Create Farm Config File

    Create a farm.config.ts file under project root:

    -
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml
    +
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml

    and add following configuration:

    -
    import { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig): UserConfig {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });
    +
    import { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig): UserConfig {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });

    For configuration file above, we use input, output and plugins, which is the most basic configuration in Farm.

    • input: Configure the entry point. Farm will compile and build a module graph from the entries.
    • @@ -44,20 +44,20 @@

      Crea
    • plugins: Configure farm plugins, all extended abilities like React, Vue SFC are supported by plugins. Here we use a Rust Plugin(@farmfe/plugin-react) to support compiling React jsx.

    Check config reference for more options.

    -
    note

    In above example, we config input as index: './src/index.html', if we do not configure input, it's default to index: './index.html'. And we can configure multiple entries in input, see Multi Page App for details

    -

    Create A Entry Html and Js

    +
    note

    In above example, we config input as index: './src/index.html', if we do not configure input, it's default to index: './index.html'. And we can configure multiple entries in input, see Multi Page App for details

    +

    Create A Entry Html and Js

    Create 2 files src/index.html and src/index.tsx under project root:

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx

    Content of src/index.html is:

    -
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    -
    note

    Note that we must add at least one <script> to refer to a script module.

    +
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    +
    note

    Note that we must add at least one <script> to refer to a script module.

    Content of src/index.tsx is:

    -
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    -

    Start Your Farm Project!

    +
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    +

    Start Your Farm Project!

    Now every thing is ready, add a start script to your package.json:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }

    then run npm start, if farm output following messages, means your project are launched successfully:

    -
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    -

    Open http://localhost:9000 in browser.

    +
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    +

    Open http://localhost:9000 in browser.

    \ No newline at end of file diff --git a/docs/0.x/tutorials/overview/index.html b/docs/0.x/tutorials/overview/index.html index b28eeb04d..e247fa4cd 100644 --- a/docs/0.x/tutorials/overview/index.html +++ b/docs/0.x/tutorials/overview/index.html @@ -8,14 +8,14 @@ - - - + + + -
    Version: 0.15

    Overview

    +
    Version: 0.15

    Overview

    In this tutorial, we will create a Farm react project from scratch, and introducing how to add useful component libraries and Farm plugins.

    -
    note

    Vue project is also fully supported by Farm. You can directly use Vite's @vitejs/plugin-vue in Farm. Farm is compatible with most vite plugins and can use them out of box.

    +
    note

    Vue project is also fully supported by Farm. You can directly use Vite's @vitejs/plugin-vue in Farm. Farm is compatible with most vite plugins and can use them out of box.

    you will learn:

    • How to build a production ready Farm React project from scratch. We will introduce how to add popular component
    • @@ -23,13 +23,13 @@
    • Farm's daily configurations and commonly used plugins.

    We aim to simplify your development experience with the Farm ecosystem through this tutorial. And it can also be helpful if you want to migrate from other tools to Farm.

    -
    note

    This tutorial is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm.

    +
    note

    This tutorial is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm.

    Following our tutorial, and open your super-fast Farm develop journey!

    -
    note

    The source code of this tutorial is in farm tutorials

    +
    note

    The source code of this tutorial is in farm tutorials

    \ No newline at end of file diff --git a/docs/0.x/tutorials/start/index.html b/docs/0.x/tutorials/start/index.html index 8341ce6fd..f433dd1ce 100644 --- a/docs/0.x/tutorials/start/index.html +++ b/docs/0.x/tutorials/start/index.html @@ -8,79 +8,79 @@ - - - + + + -
    Version: 0.15

    Develop With Farm

    +
    Version: 0.15

    Develop With Farm

    In this chapter, we will introduce commonly used configuration and plugins to help you build complex production-ready web project with Farm.

    -
    note

    This chapter reuse the project we created in chapter 1

    +
    note

    This chapter reuse the project we created in chapter 1

    We'll setup our project step by step:

    1. Introduce popular component library antd, and configure necessary plugins for it
    2. Introduce commonly used plugins like postcss, svgr, less and so on.
    3. Configure proxies and other useful dev server options
    -

    Introduce Component Library

    +

    Introduce Component Library

    A component library is often necessary when develop a web project, in this section, we will use ant-design as a demo to show How to add component libraries in Farm.

    We use ant design here only for illustration, you can introduce any component library. Farm does not have objection.

    First we need to install ant-design into our project:

    -
    pnpm add antd # execute under project root
    +
    pnpm add antd # execute under project root

    Ant Design needs Sass, so we also need to install plugins for compiling scss. We can use @farmfe/plugin-sass which is a Rust Plugin officially provided by Farm:

    -
    pnpm add @farmfe/plugin-sass -D
    +
    pnpm add @farmfe/plugin-sass -D

    Then add this plugin to plugins:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ]
    });
    +
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ]
    });

    Now Antd is ready, add it to our project:

    -
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    antd DatePicker: <DatePicker />
    </div>
    );
    +
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    antd DatePicker: <DatePicker />
    </div>
    );

    Then execute npm start and open http://localhost:9000 in browser:

    -

    Styling the Project

    +

    Styling the Project

    Now we have successfully introduced a component library into our project. Next we'll learn how to styling.

    -

    Create a Basic Admin Site Layout

    +

    Create a Basic Admin Site Layout

    First we create a new app.tsx next to index.tsx:

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx

    Content of app.tsx(It's demo code from official site of Antd):

    -
    app.tsx
    import React from 'react';
    import { Breadcrumb, Layout, Menu, theme } from 'antd';

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: 'flex', alignItems: 'center' }}>
    <div className="demo-logo" />
    <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: '0 50px' }}>
    <Breadcrumb style={{ margin: '16px 0' }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div className="site-layout-content" style={{ background: colorBgContainer }}>
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
    </Layout>
    );
    };

    export default App;
    +
    app.tsx
    import React from 'react';
    import { Breadcrumb, Layout, Menu, theme } from 'antd';

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: 'flex', alignItems: 'center' }}>
    <div className="demo-logo" />
    <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: '0 50px' }}>
    <Breadcrumb style={{ margin: '16px 0' }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div className="site-layout-content" style={{ background: colorBgContainer }}>
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
    </Layout>
    );
    };

    export default App;

    Then modify index.tsx as:

    -
    index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import App from './app';
    // import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );

    +
    index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import App from './app';
    // import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );

    Then we get a Basic admin layout:

    -

    Styling With Css Modules

    +

    Styling With Css Modules

    Farm supports css modules out of box, by default, Farm will treat any .module.(css|scss|less) as css modules. Firstly we create a app.module.scss:

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx

    Content of app.module.scss:

    -
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }
    +
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }

    Then import app.module.scss in app.tsx and save it:

    -

    import styles from './app.module.scss';
    // ...
    +

    import styles from './app.module.scss';
    // ...

    Then your page should be updated like below:

    -

    Using Css Preprocessor

    +

    Using Css Preprocessor

    Farm provided official js plugins for postcss(@farmfe/js-plugin-postcss) and less(@farmfe/js-plugin-less) (We have already installed rust plugin sass(@farmfe/plugin-sass) above).

    To use postcss, First we need to install the plugin:

    -
    pnpm add -D @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/js-plugin-postcss

    then configure it in plugins of farm.config.ts:

    -
    farm.config.ts
    // ...
    import farmPluginPostcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass',
    farmPluginPostcss()
    ]
    });
    +
    farm.config.ts
    // ...
    import farmPluginPostcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass',
    farmPluginPostcss()
    ]
    });

    Now postcss is fully supported in Farm, we won't cover postcss details here, refer to postcss docs for more details.

    -
    tip

    Refer to Farm Plugins to learn more about Farm plugins.

    -

    Configuring Alias And Externals

    +
    tip

    Refer to Farm Plugins to learn more about Farm plugins.

    +

    Configuring Alias And Externals

    Alias and externals are also most useful configurations, we can use compilation.resolve.alias and compilation.externals in Farm:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '@/': path.join(process.cwd(), 'src')
    },
    externals: [
    'node:fs'
    ]
    }
    }
    // ...
    });
    -

    Configuring DevServer

    +
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '@/': path.join(process.cwd(), 'src')
    },
    externals: [
    'node:fs'
    ]
    }
    }
    // ...
    });
    +

    Configuring DevServer

    You can find server configuration in Farm Dev Server Config.

    -

    Useful Configuration

    +

    Useful Configuration

    Example configuration:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    open: true,
    port: 9001,
    hmr: {
    // Configure the port for web socket listening
    port: 9801
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // All dev server options are under server
    server: {
    open: true,
    port: 9001,
    hmr: {
    // Configure the port for web socket listening
    port: 9801
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });

    For above examples, we used following options:

    • open: open the browser with specified port automatically
    • port: set the dev sever port to 9001
    • hmr: set the hmr port and watched files, we ignores file changes under auto_generated directory.
    -

    Setup Proxy

    +

    Setup Proxy

    Configure server proxy. farm uses http-proxy as a proxy for the development server. Based on http-proxy implementation, specific options refer to its documentation, example:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    \ No newline at end of file diff --git a/docs/0.x/using-plugins/index.html b/docs/0.x/using-plugins/index.html index fb2248a22..2a4ae72b9 100644 --- a/docs/0.x/using-plugins/index.html +++ b/docs/0.x/using-plugins/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 0.15

    Using Plugins

    +
    Version: 0.15

    Using Plugins

    There are 4 kinds of plugins supported in Farm:

    • Farm Compilation Plugins: Both Rust plugins and Js Plugins, which adopt a rollup-style hooks.
    • @@ -22,66 +22,66 @@
    • Swc Plugins: Swc plugins are supported in Farm out of Box.

    Farm adopt Vite/Rollup ecosystem, Vite/Rollup Plugins can be used directly in Farm.

    -
    tip

    For how to write your own plugins, refer to Plugins

    -

    Farm Compilation Plugins

    +
    tip

    For how to write your own plugins, refer to Plugins

    +

    Farm Compilation Plugins

    First, install the plugins your need, for example:

    -
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss

    Using plugins to configure Farm compilation plugins:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    // Js plugin, configure the plugin object
    farmPostcssPlugin()
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    // Js plugin, configure the plugin object
    farmPostcssPlugin()
    ],
    });

    There are 2 kinds of Farm compilation plugins:

    • Rust Plugins: which is written in Rust and has best performance.
    • Js Plugins: which is written in JS/TS, and it's used for compatibility with current JS ecosystem
    -

    Using Rust Plugins

    +

    Using Rust Plugins

    Using package name to configure a Rust Plugin, for example:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    ],
    });

    For above example, Farm will resolve package @farmfe/plugin-sass and treat it as a Farm Rust Plugin.

    If you want to configure options for rust plugins, you can use array syntax like [packageName, optionsObject], for example:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // using array syntax to configure a rust plugin
    [
    // rust plugin's name
    "@farmfe/plugin-sass",
    // rust plugin's options
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // using array syntax to configure a rust plugin
    [
    // rust plugin's name
    "@farmfe/plugin-sass",
    // rust plugin's options
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });

    Currently Farm supports 2 rust plugins officially:

    • @farmfe/plugin-react: Farm rust plugin for react jsx compilation and react-refresh injection.
    • @farmfe/plugin-sass: Farm rust plugin for scss files compilation, uses sass-embedded internally.
    -
    tip

    To learn more about rust plugins, see Rust Plugins

    -

    Using Js Plugins

    +
    tip

    To learn more about rust plugins, see Rust Plugins

    +

    Using Js Plugins

    Farm JS plugin is a JS object with methods as hooks, for example:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    farmPostcssPlugin({
    // ... configure postcss options
    })
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    farmPostcssPlugin({
    // ... configure postcss options
    })
    ],
    });

    farmPostcssPlugin() returns a plugin object, and you can pass any postcss options by its arguments.

    You can use priority to control the order of your plugins, for example:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });

    priority of internal plugin are 100, if you want the plugin execute first, set it larger than 100, otherwise set it smaller than 100.

    If you want to add a Farm JS plugin quickly, you can just configure a plugin object:

    -
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // configure a custom plugin
    {
    // plugin name, required
    name: 'my-first-farm-plugin',
    // this priority of this plugin, bigger value will be executed first, default to 100.
    priority: 1000,
    // define a load hook to determine how to load a more
    load: {
    // to improve performance, modules will be skipped if they don't match the filters.
    filters: {
    // only be executed for .png files.
    resolvedPaths: ['\\.txt$']
    },
    // executor callback for this hook
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    -
    warning

    filters is required in Farm for js plugins. Because Js Plugin is really slow and we should avoid executing it as much as possible. For those modules that don't match the filters, Farm won't trigger js plugin hook for them at all! Which means Farm can handle them only on Rust side safely and concurrently.

    -
    tip

    To learn more about Farm Js Plugins, refer to JS Plugin

    -

    Using Vite/Rollup/Unplugin Plugins In Farm

    +
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // configure a custom plugin
    {
    // plugin name, required
    name: 'my-first-farm-plugin',
    // this priority of this plugin, bigger value will be executed first, default to 100.
    priority: 1000,
    // define a load hook to determine how to load a more
    load: {
    // to improve performance, modules will be skipped if they don't match the filters.
    filters: {
    // only be executed for .png files.
    resolvedPaths: ['\\.txt$']
    },
    // executor callback for this hook
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    +
    warning

    filters is required in Farm for js plugins. Because Js Plugin is really slow and we should avoid executing it as much as possible. For those modules that don't match the filters, Farm won't trigger js plugin hook for them at all! Which means Farm can handle them only on Rust side safely and concurrently.

    +
    tip

    To learn more about Farm Js Plugins, refer to JS Plugin

    +

    Using Vite/Rollup/Unplugin Plugins In Farm

    Farm supports Vite plugins out of Box. First you need to install vite plugins,for example:

    -
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D
    +
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D

    Then you can use vite plugins directly by vitePlugins in farm.config.ts.

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });

    To improve performance of vite plugins, you can use function syntax that returns a filters, for example:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // Using function syntax of Vite plugin
    function configureVitePluginVue() {
    // return plugin and its filters
    return {
    // using plugin vue
    vitePlugin: vue(),
    // configuring filters for it. Unmatched module paths will be skipped.
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    configureVitePluginVue()
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // Using function syntax of Vite plugin
    function configureVitePluginVue() {
    // return plugin and its filters
    return {
    // using plugin vue
    vitePlugin: vue(),
    // configuring filters for it. Unmatched module paths will be skipped.
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    configureVitePluginVue()
    ]
    });

    Using unplugin:

    -
    pnpm add unplugin-auto-import unplugin-vue-components -D
    +
    pnpm add unplugin-auto-import unplugin-vue-components -D

    configuring unplugin in vitePlugins via unplugin/vite or unplugin/rollup:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    -
    note

    Currently you can use unplugin/vite or unplugin/rollup. unplugin/farm will be available as soon as this unplugin PR merged.

    -

    Farm Runtime Plugin

    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    +
    note

    Currently you can use unplugin/vite or unplugin/rollup. unplugin/farm will be available as soon as this unplugin PR merged.

    +

    Farm Runtime Plugin

    Farm has a runtime module system to control how to load and execute modules. Configuring compilation.runtime.plugins to add more runtime plugin, for example:

    -
    export default defineConfig({
    compilation: {
    // configure Farm runtime module system
    runtime: {
    plugins: [
    // a runtime plugin package
    require.resolve('farm-plugin-runtime-mock'),
    // a local runtime plugin
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });
    +
    export default defineConfig({
    compilation: {
    // configure Farm runtime module system
    runtime: {
    plugins: [
    // a runtime plugin package
    require.resolve('farm-plugin-runtime-mock'),
    // a local runtime plugin
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });

    you have to configure a path that point to your runtime plugin's entry. Recommend to a absolute path to avoid path issue.

    -
    tip

    To learn more about runtime plugin refer to Runtime Plugin

    -

    Using SWC Plugins

    +
    tip

    To learn more about runtime plugin refer to Runtime Plugin

    +

    Using SWC Plugins

    Swc Plugin can also be used directly in Farm, Configuring compilation.script.plugins to add SWC plugins, for example:

    -
    import jsPluginVue from '@farmfe/js-plugin-vue';

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [{
    // the package name of the swc plugin
    name: 'swc-plugin-vue-jsx',
    // options of this swc plugin
    options: {
    "transformOn": true,
    "optimize": true
    },
    // plugin execute when the filters are matched.
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    };
    +
    import jsPluginVue from '@farmfe/js-plugin-vue';

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [{
    // the package name of the swc plugin
    name: 'swc-plugin-vue-jsx',
    // options of this swc plugin
    options: {
    "transformOn": true,
    "optimize": true
    },
    // plugin execute when the filters are matched.
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    };

    Each plugin item of the array contains three fields:

    • name: the package name of the swc plugin
    • options: Configuration items passed to swc plugin
    • filters: Which modules to execute the plug-in, must be configured, support resolvedPaths and moduleTypes these two filter items, if both are specified at the same time, take the union.
    -
    note

    SWC plugin may not be compatible with the SWC version that Farm uses. If a error occurred, try upgrade the plugin.

    +
    note

    SWC plugin may not be compatible with the SWC version that Farm uses. If a error occurred, try upgrade the plugin.

    \ No newline at end of file diff --git a/docs/0.x/why-farm/index.html b/docs/0.x/why-farm/index.html index ea25e023d..6d10a8473 100644 --- a/docs/0.x/why-farm/index.html +++ b/docs/0.x/why-farm/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 0.15

    Why Farm?

    +
    Version: 0.15

    Why Farm?

    As the web project scales, building performance has been the major bottleneck, for a huge project, compiling with webpack may cost 10min or more, a hmr update may cost 10s or more, heavily reduced the efficiency.

    Then some tools like vite comes out, it uses native ESM and is unbundled for source files in dev mode, pre-bundle dependencies using esbuild, which makes the dev server launch and the HMR very fast.

    But Unbundled is not perfect, there are still big problem when comes for a large project:

    @@ -25,7 +25,7 @@

    So I think we just need a fast, powerful, consistent web bundler, which can solve the problems above and fast, then I designed and implemented Farm.

    And Farm is not just a normal bundler re-written in Rust, it has a lot of powerful and progressive designs:

    -

    Farm Design Philosophy

    +

    Farm Design Philosophy

    • Performance first: Everything will be written in Rust as long as we can, only several parts which is not the performance bottleneck will be written in JS
    • Consistence first: Make sure that the development and production exactly the same by default, what you see in development will be the same as what you got in production.
    • @@ -34,6 +34,6 @@

      Farm
    • Compatibility: Farm will work with both legacy(ES5) and modern browser.
    • Rollup style plugin system and vite/rollup compatible js-plugins: Easy to create your own plugins and easy to migrate your plugins/projects from rollup/vite. Support both Rust and JS plugins.
    -

    Farm's goal is to be the real next generation build tool, inherit all advantages from existing tools, and to be fast, powerful, consistent, and providing best development experience for web developers.

    +

    Farm's goal is to be the real next generation build tool, inherit all advantages from existing tools, and to be fast, powerful, consistent, and providing best development experience for web developers.

    \ No newline at end of file diff --git a/docs/advanced/minification/index.html b/docs/advanced/minification/index.html index e9cef3326..1b14236aa 100644 --- a/docs/advanced/minification/index.html +++ b/docs/advanced/minification/index.html @@ -8,19 +8,19 @@ - - - + + + -
    Version: 1.0.0

    Minification

    +
    Version: 1.0.0

    Minification

    Farm supports production minify out of box, which is automatically enabled in production by default. It can be enable or disable via the compilation.minify option.

    -
    farm.config.ts
    export default {
    compilation: {
    // enable minification for both development and production
    minify: true
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    // enable minification for both development and production
    minify: true
    },
    };

    If minify is enabled:

    • For js/ts modules, the code will be compressed and mangled, and all the blank characters will be removed.
    • For css and html modules, all spaces will be removed.
    -
    note

    Farm use swc minifier under the hood, refer to compilation.minify for detailed options.

    +
    note

    Farm use swc minifier under the hood, refer to compilation.minify for detailed options.

    \ No newline at end of file diff --git a/docs/advanced/partial-bundling/index.html b/docs/advanced/partial-bundling/index.html index 1f1964cd4..bc45321d4 100644 --- a/docs/advanced/partial-bundling/index.html +++ b/docs/advanced/partial-bundling/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 1.0.0

    Partial Bundling

    +
    Version: 1.0.0

    Partial Bundling

    Partial Bundling is a strategy that Farm uses to bundle modules, similar to what other bundlers do but the goal of Farm's Partial Bundling is different.

    Unlike other bundlers, Farm will not trying to bundle everything together and then split them out using optimizations like splitChunks, on the opposite, Farm will bundle projects into several output files directly. For example, if there are hundreds of modules needed to launch a html page, Farm will try to bundle them into 20-30 output files directly. Farm calls this behavior Partial Bundling.

    Farm's goal of Partial Bundling is to:

    @@ -23,8 +23,8 @@

    For traditional bundlers, we may have a hard time to configure complex splitChunks or manualChunks to achieve the goal above, but in Farm, it is supported natively through Partial Bundling.

    Note that the default bundling strategy is designed for browser, but it also works well for Node.js. Try Configuring Partial Bundling if want to change bundling strategy for Node.js.

    -
    tip

    Refer to RFC-003 Partial Bundling to get more technical details.

    -

    Motivation

    +
    tip

    Refer to RFC-003 Partial Bundling to get more technical details.

    +

    Motivation

    There are two main methods of handling modules in web build tools now: Bundling or native ESM. But they both have drawbacks:

    • For bundling, bundlers aim to bundle everything together and then split them out for optimization, but splitting is often hard to configure and is hard to balance resources loading performance and cache hit rate manually.
    • @@ -34,14 +34,14 @@

      Motivation

      I renamed Module Merging to Partial Bundling later because I think Partial Bundling can expresses more accurately what I was thinking.

      -

      Partial Bundling Rules

      +

      Partial Bundling Rules

      In this section, we will introduce the basic rules that Partial Bundling uses by examples.

      First we look into a basic react project example. For a basic react project like below, we only import react and react-dom in the entry script:

      -
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );
      +
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );

      The bundling result will looks like:

      -
      ./dist/
      ├── index_9c07.49b83356.js # contains react-dom
      ├── index_a35f.0ac21082.js # contains ./index.tsx
      ├── index_b7e0.7ab9ca2d.js # contains react and its dependencies
      ├── index_ce26.7f833381.css $ contains ./index.scss
      └── index.html # contains ./index.html
      +
      ./dist/
      ├── index_9c07.49b83356.js # contains react-dom
      ├── index_a35f.0ac21082.js # contains ./index.tsx
      ├── index_b7e0.7ab9ca2d.js # contains react and its dependencies
      ├── index_ce26.7f833381.css $ contains ./index.scss
      └── index.html # contains ./index.html

      Farm will bundle your project into 5 files by default:

      • 2 js files are from node_modules and contains react, react-dom and their dependencies.
      • @@ -58,14 +58,14 @@

        Parti
      • Output files should be of similar size and min resource size should be greater than 20KB by default: Because react-dom is the largest and more than 100KB, it is in a separate file, and react and its dependencies are smaller than 20KB, there are merged into the same output file.
      • Now we have familiar with Partial Bundling's basic rules, if met problems with partial bundling, using above rules to debug your project. Next we'll cover how to configure partial bundling.

        -

        Configuring Partial Bundling

        -

        Two Configuring Methods

        +

        Configuring Partial Bundling

        +

        Two Configuring Methods

        There 2 different ways to control bundling:

        • groups: Tell Farm that you want these modules bundled together as possible, but it's not enforced because of the optimization strategy of Farm. See Grouping Modules for this method.
        • enforceResources: Tell Farm that you want these module always bundled together, ignore all other optimization strategy constraints. See Using enforceResources for this method.
        -

        Partial Bundling Options

        +

        Partial Bundling Options

        Partial Bundling supports a lot of options to let users customize its behavior. All the options are as below:

        1. targetConcurrentRequests: Farm tries to generate resource numbers as closer as possible to this config value for initial resource loading or a dynamic resource loading.
        2. @@ -90,41 +90,41 @@

          Par
        3. immutableModules: Regex array to match the immutable modules
        4. immutableModulesWeight: Default to 0.8, immutable module will have 80% request numbers. For example, if targetConcurrentRequest is 25, then immutable resources will take 25 * 80% = 20 by default. This option is to make sure that mutable and immutable modules are isolate, if change your business code, code under node_modules won't be affected.
        -
        note

        In general, you can use targetConcurrentRequests, targetMinSize and targetMaxSize to control the default behavior of Partial Bundling. The default value set by Farm is based on best practice, so make sure it's necessary when you want to change the default value.

        -

        Grouping Modules

        +
        note

        In general, you can use targetConcurrentRequests, targetMinSize and targetMaxSize to control the default behavior of Partial Bundling. The default value set by Farm is based on best practice, so make sure it's necessary when you want to change the default value.

        +

        Grouping Modules

        you can use groups to group modules together, for above basic react project example, using following configuration to make modules under node_modules are bundled together:

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });

        we add a group item with name and test to group react and react-dom together. The bundle result is:

        -
        ./dist/
        ├── index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules
        ├── index_a35f.0ac21082.js # contains `./index.tsx`
        ├── index_ce26.7f833381.css # contains `./index.scss`
        └── index.html # contains `./index.html`
        +
        ./dist/
        ├── index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules
        ├── index_a35f.0ac21082.js # contains `./index.tsx`
        ├── index_ce26.7f833381.css # contains `./index.scss`
        └── index.html # contains `./index.html`

        Now all modules under node_modules are bundled into index_499e.72cf733c.js. Note that groups is not not enforce that all modules matches this group are bundled, a group make produce multiple output file, because:

        1. mutable and immutable module are always in different output files. When both mutable and immutable modules hit this group, they will be in different output.
        2. when comes to a multi page app or dynamic imported entries, there may be shared modules, and these should modules are always in different output files.

        If you need to enforce modules in the same output files, you can use enforceResources

        -

        Using enforceResources

        +

        Using enforceResources

        To group all modules together and ignore all other conditions, you can use enforceResources, for example:

        -
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });

        will produce:

        -
        ./dist/
        ├── index.7f833381.css # all css modules are bundled together
        ├── index.ba5550d9.js # all script modules are bundled together
        └── index.html
        -
        warning

        enforceResources will ignore all Farm's internal optimization, be careful when you use it.

        -

        Configuring immutable modules

        +
        ./dist/
        ├── index.7f833381.css # all css modules are bundled together
        ├── index.ba5550d9.js # all script modules are bundled together
        └── index.html
        +
        warning

        enforceResources will ignore all Farm's internal optimization, be careful when you use it.

        +

        Configuring immutable modules

        Using immutableModules to configure immutable modules, by default, Farm set it to node_modules/.

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        immutableModules: ['node_modules/', '/global-constants']
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        immutableModules: ['node_modules/', '/global-constants']
        },
        },
        });

        Immutable module can affect bundling and incoming persistent cache, be careful if you want to change it.

        -

        Examples

        -
        note

        Normally you don't need to configure bundling manually, if you want to configure the bundles, make sure you really need it. And these examples are only illustrations to help you learn how to configure bundling strategy easily.

        -

        Grouping Files under Same Directory

        +

        Examples

        +
        note

        Normally you don't need to configure bundling manually, if you want to configure the bundles, make sure you really need it. And these examples are only illustrations to help you learn how to configure bundling strategy easily.

        +

        Grouping Files under Same Directory

        Grouping modules under src/components and output them in the same bundle as possible.

        -
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'components',
        test: ['./src/components'],
        }
        ]
        },
        },
        });
        -

        Configuring Bundle Numbers and Size

        -
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        targetConcurrentRequests: 15,
        targetMinSize: 200 * 1024 // 200 KB
        },
        },
        });
        +
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'components',
        test: ['./src/components'],
        }
        ]
        },
        },
        });
        +

        Configuring Bundle Numbers and Size

        +
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        targetConcurrentRequests: 15,
        targetMinSize: 200 * 1024 // 200 KB
        },
        },
        });

        In above example, Farm will try to bundle your project into 15 files as possible, with min size of each file larger than 200KB as possible.

        -

        Bundle All Modules Together

        -
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });
        +

        Bundle All Modules Together

        +
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });

        In above example, we enforce to bundle all modules together and ignore all other constraints(for example, request numbers, file size). You can also enforce to bundle some modules together using enforceResources:

        -
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['\\./src/components/.+'],
        }
        ]
        },
        },
        });
        +
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['\\./src/components/.+'],
        }
        ]
        },
        },
        });

        We enforce to bundle all modules under src/components directory.

        -
        note

        enforceResources would break internal optimization for bundles, be careful when you use it.

    +
    note

    enforceResources would break internal optimization for bundles, be careful when you use it.

    \ No newline at end of file diff --git a/docs/advanced/persistent-cache/index.html b/docs/advanced/persistent-cache/index.html index b53ce8fb9..12e82d510 100644 --- a/docs/advanced/persistent-cache/index.html +++ b/docs/advanced/persistent-cache/index.html @@ -8,22 +8,22 @@ - - - + + + -
    Version: 1.0.0

    Incremental Building

    -
    tip

    Farm supports incremental build by persistent cache since v0.14.0

    +
    Version: 1.0.0

    Incremental Building

    +
    tip

    Farm supports incremental build by persistent cache since v0.14.0

    Since v0.14.0, Farm supports cache the compiled result to disk, which can greatly speed up the compilation for hot start/hot build. When persistentCache is enabled, the compilation time can reduce up to 80%.

    Performance compare between cold start(without cache) and hot start(with cache) using examples/argo-pro:

    Cold(without cache)Hot(with cache)diff
    start1519ms371msreduced 75%
    build3582ms562msreduced 84%
    -

    Using Cache

    +

    Using Cache

    Using compilation.persistentCache to enable/disable Cache:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    persistentCache: true,
    },
    });
    -
    note

    persistentCache: true is equal to:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: "node_modules/.farm/cache",
    // namespace of the cache
    namespace: "farm-cache",
    buildDependencies: [
    "farm.config.ts",
    "@farmfe/core",
    "@farmfe/plugin-react",
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    },
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    persistentCache: true,
    },
    });
    +
    note

    persistentCache: true is equal to:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: "node_modules/.farm/cache",
    // namespace of the cache
    namespace: "farm-cache",
    buildDependencies: [
    "farm.config.ts",
    "@farmfe/core",
    "@farmfe/plugin-react",
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    },
    },
    });

    Configuring persistentCache to false to disable cache.

    -

    Cache Validation

    +

    Cache Validation

    Cache will be validated when trying to reuse it by following conditions, if any of following conditions changed, all cache will be invalidated:

    • Env Object: configured by persistentCache.envs, default to Farm Env Mode(process.env.NODE_ENV, process.env.DEV, process.env.PROD), see Environment Variables and Modes.
    • @@ -35,20 +35,20 @@

      Cache Valid
    • Internal Cache Version: Farm maintains a cache version internally, if Farm itself changed, for example, render optimization that affects the output between versions of Farm, Farm will bump the cache version and all cache will be invalidated.

    If your cache does not work, check out above conditions to figure out the reason. If the cache is broken, you can also delete node_modules/.farm/cache to remove cache manually.

    -

    Build Dependencies

    +

    Build Dependencies

    Build dependencies is dependencies that can affect the compilation process or compiled output, for examples, plugins or config files. If any of these dependencies changed, all cache will be invalidated.

    Build dependencies can be a file path for a package name, for example:

    -
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    -
    note

    By default, all config files and its dependencies are included. But if you want to add some additional files or dependencies to invalidate the cache, you can using buildDependencies once these files changed, all cache will be invalidated.

    -

    Module Cache Key Strategy

    +
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    +
    note

    By default, all config files and its dependencies are included. But if you want to add some additional files or dependencies to invalidate the cache, you can using buildDependencies once these files changed, all cache will be invalidated.

    +

    Module Cache Key Strategy

    Farm provides 2 strategies to control how to generate module cache key:

    • timestamp: whether check timestamp of the module, if the update timestamp does not change, the build of this module will be skipped, which has the best performance.
    • hash: whether check content hash after load and transform, if the content does not change, the left build of this module will be skipped.

    By default timestamp and hash are both enabled.

    -

    Caveats For Plugins

    +

    Caveats For Plugins

    when timestamp is enabled, all build stages hooks like load and transform won't be called. So if the plugin relies load and transform and it does not implement plugin_cache_loaded and write_plugin_cache hook, it may not work as expected. For example, if a plugin collect information in load and transform, all emit them at finish hook, it should implement plugin_cache_loaded and write_plugin_cache hook to load and write cache, otherwise it will not work as expected.

    -

    Farm will set timestamp to false when output.targetEnv is node.

    +

    Farm will set timestamp to false when output.targetEnv is node.

    \ No newline at end of file diff --git a/docs/advanced/polyfill/index.html b/docs/advanced/polyfill/index.html index 59c5e8e1a..8c5d591b7 100644 --- a/docs/advanced/polyfill/index.html +++ b/docs/advanced/polyfill/index.html @@ -8,33 +8,33 @@ - - - + + + -
    Version: 1.0.0

    Syntax Downgrade and Polyfill

    +
    Version: 1.0.0

    Syntax Downgrade and Polyfill

    By default, Farm will downgrade to ES2017(native support async/await) and inject necessary polyfills automatically in production mode.

    -
    note

    By default, Farm won't do transformation and inject polyfills for modules under node_modules/, if you need to downgrade syntax and inject polyfills for node_modules/ you can use compilation.presetEnv.include.

    -

    Configuring targetEnv

    +
    note

    By default, Farm won't do transformation and inject polyfills for modules under node_modules/, if you need to downgrade syntax and inject polyfills for node_modules/ you can use compilation.presetEnv.include.

    +

    Configuring targetEnv

    Farm provide a normalized output.targetEnv option to configure the target execution environment of your application. Farm will perform properly syntax downgrade and polyfill injection for your target environment automatically. For example:

    -
    farm.config.ts
    export default {
    compilation: {
    output: {
    targetEnv: 'browser-legacy'
    }
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    output: {
    targetEnv: 'browser-legacy'
    }
    },
    };

    Farm will compile your application to legacy browsers(ES5):

    • Compile all Js/Jsx/Ts/Tsx modules to ES5, and inject all polyfills(Promise, regenerator-runtime and so on).
    • Add prefix for all css/scss/less modules, for example, --webkit-.

    Farm supports many normalized targetEnv options like browser-modern, browser-es2017, browser-es2015, node16, node-legacy, etc. By default, targetEnv is browser-es2017. Refer to output.targetEnv.

    -
    note

    You may need to install core-js@3 or regeneration-runtime manually if polyfill is needed. Try run pnpm add core-js if you met something error like can not resolve 'core-js/modules/xxx'

    -

    Configuring Syntax and Polyfill Separately

    +
    note

    You may need to install core-js@3 or regeneration-runtime manually if polyfill is needed. Try run pnpm add core-js if you met something error like can not resolve 'core-js/modules/xxx'

    +

    Configuring Syntax and Polyfill Separately

    Internally, targetEnv just presets of presetEnv, script.target and css.prefixer. You can configure them more precisely if you need.

    -

    Configuring presetEnv

    +

    Configuring presetEnv

    You can use compilation.presetEnv to custom syntax downgrade and polyfill injection. By default all modules under node_modules will be ignored. Using include to add extra modules that need to be polyfilled.

    -
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "Chrome >= 48"
    }
    }
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "Chrome >= 48"
    }
    }
    },
    };

    Note that if your project does not require browser compatibility, you can use set a looser value for targets, then less polyfills will be injected and output sizes will be smaller.

    Refer to compilation.presetEnv for more options.

    -

    Configuring script.target

    +

    Configuring script.target

    script.target is used to control the target env when generate code. If you want to downgrade your project to ES5, you should set both:

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5'
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "> 0.25%, not dead"
    }
    }
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5'
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "> 0.25%, not dead"
    }
    }
    },
    };
    \ No newline at end of file diff --git a/docs/advanced/ssr/index.html b/docs/advanced/ssr/index.html index 83d7bf3e2..21578138f 100644 --- a/docs/advanced/ssr/index.html +++ b/docs/advanced/ssr/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 1.0.0

    Server-Side Rendering (SSR)

    +
    Version: 1.0.0

    Server-Side Rendering (SSR)

    Server-Side Rendering (SSR) means rendering front-end frameworks(for example React, Vue, Solid, etc) to html in Node.js(Server Side), and hydrating the rendered html on the client.

    -
    note

    This document describes how to built a SSR application on top of Farm from scratch.

    -

    Example Projects

    +
    note

    This document describes how to built a SSR application on top of Farm from scratch.

    +

    Example Projects

    Farm provides a list of SSR examples for popular frameworks:

    -

    Project Structure

    +

    Project Structure

    A SSR typical application often have the following source file structure:

    -
    .
    ├── index.html
    ├── farm.config.ts
    ├── farm.config.server.ts
    ├── server.js
    └── src
    ├── index-client.tsx
    ├── index-server.tsx
    └── main.tsx
    +
    .
    ├── index.html
    ├── farm.config.ts
    ├── farm.config.server.ts
    ├── server.js
    └── src
    ├── index-client.tsx
    ├── index-server.tsx
    └── main.tsx
    • index.html: Entry html of the application that running on the client(browser)
    • farm.config.ts: farm config that builds the project to client
    • @@ -36,34 +36,34 @@

      Project St
    • src/main.tsx: Application code shared for both client and server

    index.html need to reference index-client.tsx and include a placeholder where the server-rendered markup should injected:

    -
    <div id="root"><div>app-html-to-replace</div></div>
    <script src="./src/index-client.tsx"></script>
    +
    <div id="root"><div>app-html-to-replace</div></div>
    <script src="./src/index-client.tsx"></script>

    You should replace <div>app-html-to-replace</div> to the server-rendered markup.

    -
    tip

    We have to build the SSR application twice, one for client(browser) and one for server(Node.js). So farm.config.ts and farm.config.server.ts are needed, we'll discuss the details in later sections.

    -

    Setting up Dev Server

    +
    tip

    We have to build the SSR application twice, one for client(browser) and one for server(Node.js). So farm.config.ts and farm.config.server.ts are needed, we'll discuss the details in later sections.

    +

    Setting up Dev Server

    For above example, farm.config.ts is used to build the project for browser and setting up DevServer for server rendering. The content of farm.config.ts normally would be:

    -
    farm.config.ts
    import path from 'path';
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index_client: './index.html'
    },
    output: {
    path: './build'
    },
    },
    server: {
    hmr: true,
    cors: true,
    middlewares: [
    // register a middleware that render the application on the server,
    // inject server rendered markup and return final index.html
    (server) => {
    server.app().use(async (ctx, next) => {
    await next();

    // handle index.html or SPA fallback
    if (ctx.path === '/' || ctx.status === 404) {
    // loading the server entry, and render it by ctx.path
    const render = await import(path.join(process.cwd(), 'dist', 'index.js')).then(
    (m) => m.default
    );
    const renderedHtml = render(ctx.path);

    // get compiled index.html content from server.getCompiler()
    // The html is compiled for client with all client bundles injected
    const template = server
    .getCompiler()
    .resource('index_client.html')
    .toString();

    // replace the placeholder to rendered markup and return it as html
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    renderedHtml
    );
    ctx.body = html;
    ctx.type = 'text/html';
    ctx.status = 200;
    }

    console.log('ctx.path outer', ctx.path);
    });
    }
    ]
    },
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass']
    });
    +
    farm.config.ts
    import path from 'path';
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index_client: './index.html'
    },
    output: {
    path: './build'
    },
    },
    server: {
    hmr: true,
    cors: true,
    middlewares: [
    // register a middleware that render the application on the server,
    // inject server rendered markup and return final index.html
    (server) => {
    server.app().use(async (ctx, next) => {
    await next();

    // handle index.html or SPA fallback
    if (ctx.path === '/' || ctx.status === 404) {
    // loading the server entry, and render it by ctx.path
    const render = await import(path.join(process.cwd(), 'dist', 'index.js')).then(
    (m) => m.default
    );
    const renderedHtml = render(ctx.path);

    // get compiled index.html content from server.getCompiler()
    // The html is compiled for client with all client bundles injected
    const template = server
    .getCompiler()
    .resource('index_client.html')
    .toString();

    // replace the placeholder to rendered markup and return it as html
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    renderedHtml
    );
    ctx.body = html;
    ctx.type = 'text/html';
    ctx.status = 200;
    }

    console.log('ctx.path outer', ctx.path);
    });
    }
    ]
    },
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass']
    });

    In above example, a middleware is required for rendering the application to markup and serve it as html. Normal workflow for SSR in the middleware:

    • Load compiled server entry: A index-server entry which exports a render function is required, we need to import(server_entry_path) to get the render function.
    • Get compiled client index.html: All client bundles and Farm runtime are injected to index.html, so the client can hydrate successfully.
    • Replace the placeholder to rendered markup: Replace the placeholder and return the final html.
    -
    note

    In this example, we are building a SPA SSR application with if (ctx.path === '/' || ctx.status === 404) {, if you are building a MPA SSR application, guard ctx.path to your pages.

    -

    Building for Node.js

    +
    note

    In this example, we are building a SPA SSR application with if (ctx.path === '/' || ctx.status === 404) {, if you are building a MPA SSR application, guard ctx.path to your pages.

    +

    Building for Node.js

    farm.config.server.ts is used to build the project for Node.js, producing the compiled server entry which can be used to rendering the application to markup on the server side.

    -
    farm.config.server.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index-server.tsx'
    },
    output: {
    path: './dist',
    targetEnv: 'node'
    }
    },
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: false,
    development: false
    }
    ],
    '@farmfe/plugin-sass'
    ]
    });
    +
    farm.config.server.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index-server.tsx'
    },
    output: {
    path: './dist',
    targetEnv: 'node'
    }
    },
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: false,
    development: false
    }
    ],
    '@farmfe/plugin-sass'
    ]
    });

    For farm.config.server.ts, we set input to server entry and output.targetEnv to node.

    -
    note

    By default, Farm compiles server entry script to esm, if you want to compile it to cjs, try set output.format.

    -

    Develop SSR Project

    +
    note

    By default, Farm compiles server entry script to esm, if you want to compile it to cjs, try set output.format.

    +

    Develop SSR Project

    You have start compilation for both client and server, for example, you may have following scripts in package.json:

    -
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    }
    }
    +
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    }
    }

    When starting your SSR project, you should run both npm run start and npm run start:server in different terminal.

    -

    Building for Production

    +

    Building for Production

    You have build both client and server, for example, you may add following command to scripts:

    -
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    "build": "farm build",
    "build:server": "farm build --config farm.config.server.mjs"
    }
    }
    +
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    "build": "farm build",
    "build:server": "farm build --config farm.config.server.mjs"
    }
    }

    When building for production, you should run both npm run build and npm run build:server, the client bundles will be emitted to build dir, and the server bundles will be emitted to dist dir.

    For production, you need a node server for rendering and serving rendered html, in this example, we provide a server.js as production server:

    -
    server.js
    import path from 'node:path';
    import { fileURLToPath } from 'node:url'
    import fsp from 'fs/promises';
    import express from 'express';

    function resolve(p) {
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    return path.resolve(__dirname, p);
    }

    // create a node production server
    async function createServer() {
    let app = express();
    // serve the client builds as static assets, you can also deploy client builds to CDN or separate dev server as you wish.
    app.use(express.static(resolve('build')));
    // listen '/' route, you can replace it to the routes you use.
    app.use('/', async (req, res) => {
    let url = req.originalUrl;

    try {
    let template;
    let render;

    // load client html
    template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // load server render function
    render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );
    // render the application to markup
    const markup = render(url);

    let html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // return the rendered html with client bundles, the client bundles hydrate the server rendered markup and make it interactive
    res.setHeader('Content-Type', 'text/html');
    return res.status(200).end(html);
    } catch (error) {
    console.log(error.stack);
    res.status(500).end(error.stack);
    }
    });

    return app;
    }
    // create and listen the server
    createServer().then((app) => {
    app.listen(3000, () => {
    console.log('HTTP server is running at http://localhost:3000');
    });
    });
    +
    server.js
    import path from 'node:path';
    import { fileURLToPath } from 'node:url'
    import fsp from 'fs/promises';
    import express from 'express';

    function resolve(p) {
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    return path.resolve(__dirname, p);
    }

    // create a node production server
    async function createServer() {
    let app = express();
    // serve the client builds as static assets, you can also deploy client builds to CDN or separate dev server as you wish.
    app.use(express.static(resolve('build')));
    // listen '/' route, you can replace it to the routes you use.
    app.use('/', async (req, res) => {
    let url = req.originalUrl;

    try {
    let template;
    let render;

    // load client html
    template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // load server render function
    render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );
    // render the application to markup
    const markup = render(url);

    let html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // return the rendered html with client bundles, the client bundles hydrate the server rendered markup and make it interactive
    res.setHeader('Content-Type', 'text/html');
    return res.status(200).end(html);
    } catch (error) {
    console.log(error.stack);
    res.status(500).end(error.stack);
    }
    });

    return app;
    }
    // create and listen the server
    createServer().then((app) => {
    app.listen(3000, () => {
    console.log('HTTP server is running at http://localhost:3000');
    });
    });

    We use express as server here, but you can use whatever server frameworks you want. The rendering process are the same:

    • Loading client compiled html
    • @@ -71,8 +71,8 @@

      Buil
    • Call const markup = render(url) function to get the server-side rendered markup of your application
    • Replace the placeholder in client index.html to the rendered markup and return the replaced html as final result
    -

    Static-Site Generation(SSG)

    +

    Static-Site Generation(SSG)

    The same flow of SSG is the same as SSR, the difference is SSG that emits to replaced html to the final resources. Example scripts for SSG:

    -
    // load client html
    const template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // load server render function
    const render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );

    const pages = renderDirEntry('src/pages');

    for (const page of pages) {
    // render the application to markup
    const markup = render(url);
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // emit the static generated page, for example writing it to disk
    emitPage(page, html);
    }
    +
    // load client html
    const template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // load server render function
    const render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );

    const pages = renderDirEntry('src/pages');

    for (const page of pages) {
    // render the application to markup
    const markup = render(url);
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // emit the static generated page, for example writing it to disk
    emitPage(page, html);
    }
    \ No newline at end of file diff --git a/docs/advanced/tree-shake/index.html b/docs/advanced/tree-shake/index.html index e9b7cb0a6..6d75caffd 100644 --- a/docs/advanced/tree-shake/index.html +++ b/docs/advanced/tree-shake/index.html @@ -8,26 +8,26 @@ - - - + + + -
    Version: 1.0.0

    Tree Shake

    +
    Version: 1.0.0

    Tree Shake

    Farm supports Tree Shake, which is automatically enabled in the default Production environment. It can be turned on or off by the compilation.treeShaking option.

    During Tree Shake, the sideEffects field in package.json will be automatically read, and modules with sideEffects will not perform Tree Shake.

    -
    note

    Farm will treat all circularly dependent modules as sideEffects and will not perform Tree Shake. Please try to avoid circular dependencies in your project.

    +
    note

    Farm will treat all circularly dependent modules as sideEffects and will not perform Tree Shake. Please try to avoid circular dependencies in your project.

    Tree shake example:

    -
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    export b2 = "B2";
    +
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";
    export b2 = "B2";

    a.js is entry and it imports b.js, after tree shaking, the result is:

    -
    a.js
    import { b1 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    +
    a.js
    import { b1 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";

    b2 is not used and will be removed in both a.js and b.js

    -

    Configuring Tree Shake

    +

    Configuring Tree Shake

    Tree Shake is enabled in production mode by default, to disable tree shake, use compilation.treeShake:

    -
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    -

    Deal With Side Effects

    +
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    +

    Deal With Side Effects

    When a module contains side effects, Farm won't apply tree shake for it, and all of its imported and exports are treated as used. Farm will think following modules have side effects:

    1. CommonJs modules always have side effects.
    2. @@ -37,16 +37,16 @@

      Deal
    3. Entry modules are always has side effects.

    Example 1:

    -
    const a = require('./')
    module.exports = a;
    +
    const a = require('./')
    module.exports = a;

    CommonJs module are always has side effects.

    Example 2:

    -
    import a from './';

    a();
    +
    import a from './';

    a();

    a() is executed at global scope and we treat it as side effect.

    Example 3:

    -
    // a.js
    import b from './b.js'

    // b.js
    import a from './a.js'
    +
    // a.js
    import b from './b.js'

    // b.js
    import a from './a.js'

    a, b are cyclic dependencies, so they will be treated as side effects too.

    Example 4:

    -
    package.json
    {
    "name": "my-package",
    "sideEffects": [
    "./global/**.ts"
    ]
    }
    -

    all ts modules under global/ are treat as side effects.

    +
    package.json
    {
    "name": "my-package",
    "sideEffects": [
    "./global/**.ts"
    ]
    }
    +

    all ts modules under global/ are treat as side effects.

    \ No newline at end of file diff --git a/docs/api/hmr-api/index.html b/docs/api/hmr-api/index.html index 9d619a93a..b66b5b8f6 100644 --- a/docs/api/hmr-api/index.html +++ b/docs/api/hmr-api/index.html @@ -8,55 +8,55 @@ - - - + + + -
    Version: 1.0.0

    Hmr Api

    -
    note

    The Farm HMR API is compatible with Vite's HMR API.

    +
    Version: 1.0.0

    Hmr Api

    +
    note

    The Farm HMR API is compatible with Vite's HMR API.

    Farm exports its HMR API via the special import.meta.hot object(compatible with Vite):

    -
    export interface ViteHotContext {
    readonly data: any;

    accept(): void;
    accept(cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(
    deps: readonly string[],
    cb: (mods: Array<ModuleNamespace | undefined>) => void
    ): void;

    dispose(cb: (data: any) => void): void;
    prune(cb: (data: any) => void): void;
    invalidate(message?: string): void;

    on<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    off<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    send<T extends string>(event: T, data?: InferCustomEventPayload<T>): void;
    }
    -

    Required Conditional Guard

    +
    export interface ViteHotContext {
    readonly data: any;

    accept(): void;
    accept(cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(
    deps: readonly string[],
    cb: (mods: Array<ModuleNamespace | undefined>) => void
    ): void;

    dispose(cb: (data: any) => void): void;
    prune(cb: (data: any) => void): void;
    invalidate(message?: string): void;

    on<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    off<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    send<T extends string>(event: T, data?: InferCustomEventPayload<T>): void;
    }
    +

    Required Conditional Guard

    HMR only works for development mode, make sure to guard HMR API usage with a conditional block:

    -
    if (import.meta.hot) {
    // HMR Code
    }
    -

    IntelliSense for TypeScript

    +
    if (import.meta.hot) {
    // HMR Code
    }
    +

    IntelliSense for TypeScript

    The same as Vite, Farm provides type definitions for import.meta.hot in @farmfe/core/client.d.ts. You can create an env.d.ts in the src directory so TypeScript picks up the type definitions:

    -
    /// <reference types="@farmfe/core/client" />
    -

    hot.accept()

    +
    /// <reference types="@farmfe/core/client" />
    +

    hot.accept()

    For a self-accepted module, use import.meta.hot.accept():

    -
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept();

    const div = document.getElementById(id);
    // update the page
    if (div) {
    const comp = SelfAcceptedEmpty().render();
    div.replaceWith(comp);
    }
    }
    -

    hot.accept(cb)

    +
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept();

    const div = document.getElementById(id);
    // update the page
    if (div) {
    const comp = SelfAcceptedEmpty().render();
    div.replaceWith(comp);
    }
    }
    +

    hot.accept(cb)

    If you want to update the module status based on exports of updated module, you can use import.meta.hot.accept(cb):

    -
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    const comp = mod[id]().render();
    div?.replaceWith(comp);
    });
    }
    +
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    const comp = mod[id]().render();
    div?.replaceWith(comp);
    });
    }

    Arguments of cb is the exports of updated module, you can do updates based on it.

    -

    hot.accept(deps, cb)

    +

    hot.accept(deps, cb)

    A module can also accept updates from direct dependencies without reloading itself.

    Accept single dependency:

    -
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept('./accept-deps-data', (data) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }
    +
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept('./accept-deps-data', (data) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }

    Accept multiple dependencies:

    -
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept(['./accept-deps-data'], ([data]) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }
    -

    hot.dispose(cb)

    +
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept(['./accept-deps-data'], ([data]) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }
    +

    hot.dispose(cb)

    A self-accepting module or a module that expects to be accepted by others can use hot.dispose to clean-up any persistent side effects created by its updated copy:

    -
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    div?.appendChild(mod.createChild());
    });

    // clean side effects
    import.meta.hot.dispose(() => {
    // remove all children of the div
    const div = document.getElementById(id);

    if (div) {
    while (div.firstChild) {
    console.log('dispose', div.firstChild);
    div.removeChild(div.firstChild);
    }
    }
    });
    }
    -

    hot.prune(cb)

    +
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    div?.appendChild(mod.createChild());
    });

    // clean side effects
    import.meta.hot.dispose(() => {
    // remove all children of the div
    const div = document.getElementById(id);

    if (div) {
    while (div.firstChild) {
    console.log('dispose', div.firstChild);
    div.removeChild(div.firstChild);
    }
    }
    });
    }
    +

    hot.prune(cb)

    Register a callback that will call when the module is no longer imported on the page. Compared to hot.dispose, this can be used if the source code cleans up side-effects by itself on updates and you only need to clean-up when it's removed from the page. Farm currently uses this for .css imports(the same as Vite).

    -
    if (import.meta.hot) {{
    import.meta.hot.accept();
    import.meta.hot.prune(() => {{
    style.remove();
    }});
    }}
    -

    hot.data

    +
    if (import.meta.hot) {{
    import.meta.hot.accept();
    import.meta.hot.prune(() => {{
    style.remove();
    }});
    }}
    +

    hot.data

    The import.meta.hot.data object is persisted across different instances of the same updated module. It can be used to pass on information from a previous version of the module to the next one.

    -
    import.meta.hot.data.value = 'value';
    -

    hot.invalidate(message?: string)

    +
    import.meta.hot.data.value = 'value';
    +

    hot.invalidate(message?: string)

    A self-accepting module may realize during runtime that it can't handle a HMR update, and so the update needs to be forcefully propagated to importers. By calling import.meta.hot.invalidate(), the HMR server will invalidate the importers of the caller, as if the caller wasn't self-accepting. This will log a message both in the browser console and in the terminal. You can pass a message to give some context on why the invalidation happened.

    Note that you should always call import.meta.hot.accept even if you plan to call invalidate immediately afterwards, or else the HMR client won't listen for future changes to the self-accepting module. To communicate your intent clearly, we recommend calling invalidate within the accept callback like so:

    -
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept((mod) => {
    if (cannotHandleUpdate(mod)) {
    import.meta.hot.invalidate('parent module should accept this');
    }
    });
    }
    -

    hot.on(event, cb)

    +
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept((mod) => {
    if (cannotHandleUpdate(mod)) {
    import.meta.hot.invalidate('parent module should accept this');
    }
    });
    }
    +

    hot.on(event, cb)

    The same as Vite, see Vite hot.on

    -

    hot.off(event, cb)

    +

    hot.off(event, cb)

    Remove callback from the event listeners

    -

    hot.send(event, data)

    +

    hot.send(event, data)

    Send message from HMR client to dev server:

    -
    import.meta.hot.send('event-name', { data: '123' });
    +
    import.meta.hot.send('event-name', { data: '123' });

    Receive message on dev server:

    -
    server.ws.on('event-name', (data) => {});
    +
    server.ws.on('event-name', (data) => {});
    \ No newline at end of file diff --git a/docs/api/javascript-api/index.html b/docs/api/javascript-api/index.html index ffd475205..326c6796c 100644 --- a/docs/api/javascript-api/index.html +++ b/docs/api/javascript-api/index.html @@ -8,181 +8,181 @@ - - - + + + -
    Version: 1.0.0

    Javascript Api

    +
    Version: 1.0.0

    Javascript Api

    Farm provides a comprehensive set of APIs for development servers, compilers, watchers, etc. Developers can use these APIs by importing the @farmfe/core package.

    Install the @farmfe/core package:

    -
    npm
    yarn
    pnpm
    bun
    npm add @farmfe/core@latest
    -

    Start

    +
    npm
    yarn
    pnpm
    bun
    npm add @farmfe/core@latest
    +

    Start

    The start method is used to quickly launch the development server.

    After calling the start method, you can see the log information of the available ip address in the current console. By default, it compiles the index.html file in the current directory.

    Type:

    -
    start(options: InlineConfig): Promise<void>
    +
    start(options: InlineConfig): Promise<void>

    Basic example:

    -
    import { start, logger } from "@farmfe/core";
    try {
    await start({
    compilation: {
    output: {
    publicPath: "/dist"
    },
    input: {
    index: "./base.html"
    }
    },
    server: {
    port: 6532,
    hmr: {
    path: "/__farm_hmr",
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ],
    });
    } catch (error) {
    logger.error(`Failed to start server:\n ${error.stack}`);
    process.exit(1);
    }

    +
    import { start, logger } from "@farmfe/core";
    try {
    await start({
    compilation: {
    output: {
    publicPath: "/dist"
    },
    input: {
    index: "./base.html"
    }
    },
    server: {
    port: 6532,
    hmr: {
    path: "/__farm_hmr",
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ],
    });
    } catch (error) {
    logger.error(`Failed to start server:\n ${error.stack}`);
    process.exit(1);
    }

    another way is use more deep api to start server:

    -
    import {
    createCompiler,
    createDevServer,
    resolveConfig
    } from '@farmfe/core';

    const resolveUserConfig = await resolveConfig({
    compilation: {
    output: {
    publicPath: "/dist"
    },
    input: {
    index: "./base.html"
    }
    },
    server: {
    port: 6532,
    hmr: {
    path: "/__farm_hmr",
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ],
    })

    // create compiler
    const compiler = await createCompiler(resolveUserConfig);
    const server = await createDevServer(compiler, resolveUserConfig);
    server.listen();
    -

    Build

    +
    import {
    createCompiler,
    createDevServer,
    resolveConfig
    } from '@farmfe/core';

    const resolveUserConfig = await resolveConfig({
    compilation: {
    output: {
    publicPath: "/dist"
    },
    input: {
    index: "./base.html"
    }
    },
    server: {
    port: 6532,
    hmr: {
    path: "/__farm_hmr",
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ],
    })

    // create compiler
    const compiler = await createCompiler(resolveUserConfig);
    const server = await createDevServer(compiler, resolveUserConfig);
    server.listen();
    +

    Build

    The build method is used to build for the production environment.

    After calling the build method, it defaults to building browser artifacts and generates a dist folder in the current directory. If you need to build artifacts for different environments and versions, such as node, node-next, browser, browser-es2017, etc., you can configure it by checking output targetEnv.

    Type:

    -
    build(options: InlineConfig): Promise<void>
    +
    build(options: InlineConfig): Promise<void>

    Basic example:

    -
    import { build, logger } from "@farmfe/core";
    try {
    await build(options);
    } catch (error) {
    logger.error(`error during build:\n ${error.stack}`);
    process.exit(1);
    }
    -

    Watch

    +
    import { build, logger } from "@farmfe/core";
    try {
    await build(options);
    } catch (error) {
    logger.error(`error during build:\n ${error.stack}`);
    process.exit(1);
    }
    +

    Watch

    The watch method provides real-time updates for the compilation of the current project, equivalent to npx farm build --watch. Generally used in the node environment.

    Type:

    -
    watch(options: InlineConfig): Promise<void>
    +
    watch(options: InlineConfig): Promise<void>

    Basic example:

    -
    import { watch, logger } from "@farmfe/core";
    try {
    await watch(defaultOptions);
    } catch (error) {
    logger.error(`error during watch project:\n ${error.stack}`);
    process.exit(1);
    }
    -

    Preview

    +
    import { watch, logger } from "@farmfe/core";
    try {
    await watch(defaultOptions);
    } catch (error) {
    logger.error(`error during watch project:\n ${error.stack}`);
    process.exit(1);
    }
    +

    Preview

    The preview method starts a preview server for previewing production artifacts. Make sure to have built the artifacts using the build method and have the correct production artifacts.

    Type:

    -
    preview(options: InlineConfig): Promise<void>
    +
    preview(options: InlineConfig): Promise<void>

    Basic example:

    -
    import { preview, logger } from "@farmfe/core";
    try {
    await preview(defaultOptions);
    } catch (error) {
    logger.error(`Failed to start preview server:\n ${error.stack}`);
    process.exit(1);
    }
    -

    Clean

    +
    import { preview, logger } from "@farmfe/core";
    try {
    await preview(defaultOptions);
    } catch (error) {
    logger.error(`Failed to start preview server:\n ${error.stack}`);
    process.exit(1);
    }
    +

    Clean

    The clean method clears the cache generated by the farm incremental build. If you have issues with the incremental build causing crashes due to unforeseen or undiscovered problems, clearing the cache might help.

    -
    warning

    If there are problems with the incremental build causing crashes that are not resolved by clearing the cache, please submit an issue on GitHub.

    +
    warning

    If there are problems with the incremental build causing crashes that are not resolved by clearing the cache, please submit an issue on GitHub.

    Type:

    -
    clean(options: InlineConfig): Promise<void>
    +
    clean(options: InlineConfig): Promise<void>

    Basic example:

    -
    import { clean, logger } from "@farmfe/core";
    try {
    await clean(defaultOptions);
    } catch (error) {
    logger.error(`Failed to clean cache:\n ${error.stack}`);
    process.exit(1);
    }
    -

    loadEnv

    +
    import { clean, logger } from "@farmfe/core";
    try {
    await clean(defaultOptions);
    } catch (error) {
    logger.error(`Failed to clean cache:\n ${error.stack}`);
    process.exit(1);
    }
    +

    loadEnv

    Load environment variables from the .env file.

    -
    type LoadEnvFunc = (
    mode: string,
    envDir: string,
    prefixes: string | string[] = ['FARM_', 'VITE_']
    ) => [env: Record<string, string>, existsEnvFiles: string[]];
    +
    type LoadEnvFunc = (
    mode: string,
    envDir: string,
    prefixes: string | string[] = ['FARM_', 'VITE_']
    ) => [env: Record<string, string>, existsEnvFiles: string[]];
    • mode is development, production or any string. loadEnv will try load [``.env``, ``.env.local``, ``.env.${mode}``, ``.env.${mode}.local``] for envDir.
    • envDir is the directory where the .env file is located.
    • prefixes is the prefix of the environment variable. The default value is ['FARM_', 'VITE_']. Env variables with these prefixes will be injected into define automatically.
    -
    const [env, files] = loadEnv('development', '/path/to/project/env');
    // use env
    -

    createDevServer

    +
    const [env, files] = loadEnv('development', '/path/to/project/env');
    // use env
    +

    createDevServer

    The createDevServer method is used to start a local development server. You need to instantiate the Server object first and pass the compiler as a parameter.

    Type:

    -
    createDevServer(options: DevServerOptions): Promise<void>
    +
    createDevServer(options: DevServerOptions): Promise<void>

    Basic example:

    -
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    -

    createPreviewServer

    +
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    +

    createPreviewServer

    Create a preview server for previewing production artifacts.

    Type:

    -
    createPreviewServer(options: DevServerOptions): Promise<void>
    +
    createPreviewServer(options: DevServerOptions): Promise<void>

    Basic example:

    -

    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createPreviewServer(options);
    -

    getCompiler

    +

    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createPreviewServer(options);
    +

    getCompiler

    Get the current development server's compiler instance. Pass the compiler as a parameter when instantiating the Server.

    Type:

    -

    getCompiler(): Compiler
    +

    getCompiler(): Compiler

    Basic example:

    -

    import { Server, Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const server = new Server({
    compiler
    });
    const compilerInstance = server.getCompiler();
    -

    close

    +

    import { Server, Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const server = new Server({
    compiler
    });
    const compilerInstance = server.getCompiler();
    +

    close

    Close all servers and WebSocket services opened by createDevServer.

    Basic example:

    -

    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    await server.close();
    -

    Compiler

    +

    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    await server.close();
    +

    Compiler

    The Compiler provides a set of compiler APIs. You can create a compiler instance by instantiating Compiler.

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    -

    compile

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    +

    compile

    Asynchronously start the compilation process. Returns a Promise.

    -
    note

    If specific environment variables are set (process.env.FARM_PROFILE), it performs a synchronous compilation.

    +
    note

    If specific environment variables are set (process.env.FARM_PROFILE), it performs a synchronous compilation.

    Type:

    -

    compile(): Promise<void>
    +

    compile(): Promise<void>

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    -

    compileSync

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    +

    compileSync

    Synchronously start the compilation process.

    Type:

    -

    compileSync(): void
    +

    compileSync(): void

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.compileSync();
    -

    traceDependencies

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.compileSync();
    +

    traceDependencies

    Trace dependencies between files. Returns an array of all dependencies for the provided input in the compiler configuration. Useful for restarting compilation based on file dependencies.

    Type:

    -

    traceDependencies(): Array<string>
    +

    traceDependencies(): Array<string>

    Basic example:

    -

    import { Compiler } from "@farmfe/core";

    const config = {
    input: "./farm.config.js"
    }
    const compiler = new Compiler(config);
    const dependencies = compiler.traceDependencies();
    +

    import { Compiler } from "@farmfe/core";

    const config = {
    input: "./farm.config.js"
    }
    const compiler = new Compiler(config);
    const dependencies = compiler.traceDependencies();

    Returns an array of paths representing all dependencies.

    -

    update

    +

    update

    Update compilation based on the provided paths. Returns a Promise resolving to a JsUpdateResult. If compilation is already in progress, it waits for completion and updates. If ignoreCompilingCheck is set to true, it won't check the compilation status.

    -

    type JsUpdateResult = {
    success: boolean
    errors: Array<Error>
    warnings: Array<Error>
    }

    update(paths: Array<string>, sync: boolean, ignoreCompilingCheck: boolean): JsUpdateResult
    +

    type JsUpdateResult = {
    success: boolean
    errors: Array<Error>
    warnings: Array<Error>
    }

    update(paths: Array<string>, sync: boolean, ignoreCompilingCheck: boolean): JsUpdateResult

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = await compiler.update(paths, true, true);
    -

    hasModule

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = await compiler.update(paths, true, true);
    +

    hasModule

    Pass a path to determine if the current path is within the modules compiled by the compiler.

    Type:

    -

    hasModule(path: string): boolean
    +

    hasModule(path: string): boolean

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.hasModule(path);
    -

    getParentFiles

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.hasModule(path);
    +

    getParentFiles

    Retrieve the current file that a module import with the module import name (id) or resolved path identifier (resolvedPath) imports.

    Type:

    -

    getParentFiles(resolvedPath: string): Array<string>
    +

    getParentFiles(resolvedPath: string): Array<string>

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.getParentFiles(resolvedPath);
    -

    resources

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.getParentFiles(resolvedPath);
    +

    resources

    Return all resources compiled by the compiler.

    Type:

    -

    type Resource = {
    path: string
    buffer: Buffer
    }
    resources(): Array<Resource>
    +

    type Resource = {
    path: string
    buffer: Buffer
    }
    resources(): Array<Resource>

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resources();
    -

    Resource

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resources();
    +

    Resource

    Return the buffer of the current artifact based on the given file.

    Type:

    -

    resource(path: string): Buffer | null
    +

    resource(path: string): Buffer | null

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resource(path);
    -

    writeResourcesToDisk

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resource(path);
    +

    writeResourcesToDisk

    Write resources to disk based on the configured output path.

    Type:

    -

    writeResourcesToDisk(): void
    +

    writeResourcesToDisk(): void

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.writeResourcesToDisk();
    -

    removeOutputPathDir

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.writeResourcesToDisk();
    +

    removeOutputPathDir

    Remove the output path directory.

    Type:

    -

    removeOutputPathDir(): void
    +

    removeOutputPathDir(): void

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.removeOutputPathDir();
    -

    resolvedWatchPaths

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.removeOutputPathDir();
    +

    resolvedWatchPaths

    Return resolved watch paths.

    Type:

    -

    resolvedWatchPaths(): Array<string>
    +

    resolvedWatchPaths(): Array<string>

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedWatchPaths();
    -

    resolvedModulePaths

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedWatchPaths();
    +

    resolvedModulePaths

    Return resolved module paths relative to the provided root path.

    Type:

    -

    resolvedModulePaths(rootPath: string): Array<string>
    +

    resolvedModulePaths(rootPath: string): Array<string>

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedModulePaths(rootPath);
    -

    onUpdateFinish

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedModulePaths(rootPath);
    +

    onUpdateFinish

    Add a callback to be executed after the update process is complete.

    Type:

    -

    onUpdateFinish(callback: (...args: any[]) => any): void
    +

    onUpdateFinish(callback: (...args: any[]) => any): void

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.onUpdateFinish(callback);
    -

    outputPath

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.onUpdateFinish(callback);
    +

    outputPath

    Return the resolved output path.

    Type:

    -

    outputPath(): string
    +

    outputPath(): string

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.outputPath();
    -

    addExtraWatchFile

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.outputPath();
    +

    addExtraWatchFile

    Add extra watch files for the compiler.

    Type:

    -

    addExtraWatchFile(rootPath: string, filePath: string[]): void
    +

    addExtraWatchFile(rootPath: string, filePath: string[]): void

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.addExtraWatchFile(rootPath, filePath);
    -

    modules

    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.addExtraWatchFile(rootPath, filePath);
    +

    modules

    Return an array of objects representing file module resolutions.

    Type:

    -

    export interface Module {
    id: string
    moduleType: string
    moduleGroups: Array<string>
    resourcePot?: string
    sideEffects: boolean
    sourceMapChain: Array<string>
    external: boolean
    immutable: boolean
    }
    modules(): Array<Module>
    +

    export interface Module {
    id: string
    moduleType: string
    moduleGroups: Array<string>
    resourcePot?: string
    sideEffects: boolean
    sourceMapChain: Array<string>
    external: boolean
    immutable: boolean
    }
    modules(): Array<Module>

    Basic example:

    -

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.modules();
    +

    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.modules();
    \ No newline at end of file diff --git a/docs/api/js-plugin-api/index.html b/docs/api/js-plugin-api/index.html index c1ff486b2..2b7b28f9b 100644 --- a/docs/api/js-plugin-api/index.html +++ b/docs/api/js-plugin-api/index.html @@ -8,43 +8,43 @@ - - - + + + -
    Version: 1.0.0

    Js Plugin Api

    +
    Version: 1.0.0

    Js Plugin Api

    Farm Js Plugin has designed a similar rollup style design plugin system and easy to migrate your plugins/projects from Rollup/Vite/Webpack.

    -

    Configuring Js Plugins

    +

    Configuring Js Plugins

    Adding JS plugins by plugins option:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";
    // import a js plugin
    import farmPluginFoo from "farm-plugin-foo";

    export default defineConfig({
    // configuring it in plugins
    plugins: [farmPluginFoo()],
    });
    -

    Writing Js Plugins

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";
    // import a js plugin
    import farmPluginFoo from "farm-plugin-foo";

    export default defineConfig({
    // configuring it in plugins
    plugins: [farmPluginFoo()],
    });
    +

    Writing Js Plugins

    A Farm Js Plugin is a plain javascript object which exposes a set of hooks. for example:

    -
    my-farm-plugin.ts
    // Create a plugin file that exports a plugin function which returns a `JsPlugin` Object:
    import type { JsPlugin } from '@farmfe/core';

    // Plugin Options
    export interface PluginOptions {
    test: boolean;
    }
    // export a Plugin Function
    export default function MyPlugin(options: PluginOptions): JsPlugin {
    // reading options
    const { test } = options;

    // return a object that exposes hook
    return {
    name: 'my-farm-plugin',
    // using load hook to load custom modules
    load: {
    filters: {
    resolvedPaths: ['\\.test$'] // filter files to improve performance
    },
    async executor({ resolvedPath }) {
    if (test && resolvedPath.endsWith('.test')) {
    return {
    content: 'test file',
    sourceMap: null
    }
    }
    }
    }
    }
    }
    -
    note
      +
      my-farm-plugin.ts
      // Create a plugin file that exports a plugin function which returns a `JsPlugin` Object:
      import type { JsPlugin } from '@farmfe/core';

      // Plugin Options
      export interface PluginOptions {
      test: boolean;
      }
      // export a Plugin Function
      export default function MyPlugin(options: PluginOptions): JsPlugin {
      // reading options
      const { test } = options;

      // return a object that exposes hook
      return {
      name: 'my-farm-plugin',
      // using load hook to load custom modules
      load: {
      filters: {
      resolvedPaths: ['\\.test$'] // filter files to improve performance
      },
      async executor({ resolvedPath }) {
      if (test && resolvedPath.endsWith('.test')) {
      return {
      content: 'test file',
      sourceMap: null
      }
      }
      }
      }
      }
      }
      +
      note
      • Farm provided create-farm-plugin tool to help you create and develop you js plugin quickly. For more details about writing JS plugins, refer to Writing JS Plugins
      -

      Plugin Hook Overview

      +

      Plugin Hook Overview

      The Js plugin hook is the same as the Rust plugin, See Rust Plugin Hook Overview.

      -
      note

      Not all hooks are exposed to Js Plugins, only hooks listed in this document are available.

      -

      hooks

      -

      name

      +
      note

      Not all hooks are exposed to Js Plugins, only hooks listed in this document are available.

      +

      hooks

      +

      name

      • type: string
      • required: true

      The name of this plugins, MUST not be empty.

      -
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      // ...
      }
      }
      -

      priority

      +
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      // ...
      }
      }
      +

      priority

      • type: number
      • required: false
      • default: 100

      The priority of this plugins, default to 100. priority controls the execution order of plugins, the larger the value, the earlier the plugin is executed.

      -
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      priority: 1000, // make this plugins execute before all other plugins
      // ...
      }
      }
      -
      note

      Note that the priority of most farm internal plugins like plugin-script, plugin-resolve is 99, which means your plugins is always executed before the internal plugins. If your want to make your plugin executed after farm internal plugins, set priority to a value that smaller than 99, for example: 98. Also the priority value can be negative, you can set it to -9999 to make sure it is always executed at last.

      -

      config

      +
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      priority: 1000, // make this plugins execute before all other plugins
      // ...
      }
      }
      +
      note

      Note that the priority of most farm internal plugins like plugin-script, plugin-resolve is 99, which means your plugins is always executed before the internal plugins. If your want to make your plugin executed after farm internal plugins, set priority to a value that smaller than 99, for example: 98. Also the priority value can be negative, you can set it to -9999 to make sure it is always executed at last.

      +

      config

      • type: config?: (config: UserConfig) => UserConfig | Promise<UserConfig>;
      • hook type: serial
      • @@ -52,9 +52,9 @@

        configFarm config in config hook, return the (partial) modified config, the returned config will be deeply merged into the config resolved from cli and config file. You can also directly mutate the config.

        Example:

        -
        const resolveConfigPlugin = () => ({
        name: 'return-resolve-config-plugin',
        config: (_config) => ({
        compilation: {
        resolve: {
        alias: {
        foo: 'bar'
        }
        }
        }
        })
        });
        -
        note

        config hook is called after all user plugins are resolved, so add new plugins into the config has no effect.

        -

        configResolved

        +
        const resolveConfigPlugin = () => ({
        name: 'return-resolve-config-plugin',
        config: (_config) => ({
        compilation: {
        resolve: {
        alias: {
        foo: 'bar'
        }
        }
        }
        })
        });
        +
        note

        config hook is called after all user plugins are resolved, so add new plugins into the config has no effect.

        +

        configResolved

        • type: configResolved?: (config: ResolvedUserConfig) => void | Promise<void>;
        • hook type: serial
        • @@ -62,19 +62,19 @@

          configResolve

        Called when the config resolved(after all plugin's config hook being called). Useful when you want to get the final resolved config for your plugin.

        Example:

        -
        const myPlugin = () => {
        let farmConfig;

        return {
        name: 'my-plugin',
        configResolved(resolvedConfig) {
        // get resolved config
        resolvedConfig = farmConfig;
        },
        transform: {
        filters: {
        moduleTypes: ['js']
        },
        async executor(param) {
        if (farmConfig.xxx) {
        // ...
        }
        }
        }
        }
        }
        -

        configureDevServer

        +
        const myPlugin = () => {
        let farmConfig;

        return {
        name: 'my-plugin',
        configResolved(resolvedConfig) {
        // get resolved config
        resolvedConfig = farmConfig;
        },
        transform: {
        filters: {
        moduleTypes: ['js']
        },
        async executor(param) {
        if (farmConfig.xxx) {
        // ...
        }
        }
        }
        }
        }
        +

        configureDevServer

        • type: configureDevServer?: (server: Server) => void | Promise<void>;
        • hook type: serial
        • required: false
        -
        note

        Note that this hook runs in development mode only.

        +
        note

        Note that this hook runs in development mode only.

        Called when Dev Server is ready, you can get the dev server instance.

        Example:

        -
        const myPlugin = () => {
        let devServer;

        return {
        name: 'my-plugin',
        configureDevServer(server) {
        devServer = server;
        }
        }
        }
        -
        note

        Both config and configResolved hook of js plugin are called before config hook of rust plugin.

        -

        configureCompiler

        +
        const myPlugin = () => {
        let devServer;

        return {
        name: 'my-plugin',
        configureDevServer(server) {
        devServer = server;
        }
        }
        }
        +
        note

        Both config and configResolved hook of js plugin are called before config hook of rust plugin.

        +

        configureCompiler

        • type: configureCompiler?: (compiler: Compiler) => void | Promise<void>;
        • hook type: serial
        • @@ -82,8 +82,8 @@

          configureC

        Called when Rust Compiler is ready, this hook runs in both development and production. You can get Compiler instance here

        Example:

        -
        const myPlugin = () => {
        let farmCompiler;

        return {
        name: 'my-plugin',
        configureCompiler(compiler) {
        farmCompiler = compiler;
        }
        }
        }
        -

        buildStart

        +
        const myPlugin = () => {
        let farmCompiler;

        return {
        name: 'my-plugin',
        configureCompiler(compiler) {
        farmCompiler = compiler;
        }
        }
        }
        +

        buildStart

        • type: buildStart?: { executor: Callback<Record<string, never>, void> };
        • hook type: parallel
        • @@ -91,24 +91,24 @@

          buildStart

          Called before the compilation starts. You can do some initialization work here.

          Example:

          -
          const myPlugin = () => {
          // your plugin operations
          let myPluginContext = createMyPluginContext();

          return {
          name: 'my-plugin',
          buildStart: {
          async executor() {
          // set up my plugin before compilation.
          myPluginContext.setup();
          }
          }
          }
          }
          -
          note

          buildStart is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger buildStart.

          -

          resolve

          +
          const myPlugin = () => {
          // your plugin operations
          let myPluginContext = createMyPluginContext();

          return {
          name: 'my-plugin',
          buildStart: {
          async executor() {
          // set up my plugin before compilation.
          myPluginContext.setup();
          }
          }
          }
          }
          +
          note

          buildStart is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger buildStart.

          +

          resolve

          • required: false
          • hook type: first
          • type:
          -
          type ResolveHook = { 
          filters: {
          importers: string[];
          sources: string[];
          };
          executor: Callback<PluginResolveHookParam, PluginResolveHookResult>
          };

          type Callback<P, R> = (
          param: P,
          context?: CompilationContext,
          hookContext?: { caller?: string; meta: Record<string, unknown> }
          ) => Promise<R | null | undefined>;

          /// Parameter of the resolve hook
          export interface PluginResolveHookParam {
          /// the start location to resolve `source`, being [None] if resolving a entry or resolving a hmr update.
          /// it's id of the parent module, for example: `src/index.ts` or `src/index.vue?vue&type=xxx`
          importer: string | null;
          /// for example, [ResolveKind::Import] for static import (`import a from './a'`)
          kind: ResolveKind;
          /// source of the import. for example in index.ts (import App from "./App.vue")
          /// source should be './App.vue'
          source: string;
          }
          /// Resolve result of the resolve hook
          export interface PluginResolveHookResult {
          /// resolved path, normally a absolute path. you can also return a virtual path, and use [PluginLoadHookResult] to provide the content of the virtual path
          resolvedPath: string;
          /// whether this module should be external, if true, the module won't present in the final result
          external: boolean;
          /// whether this module has side effects, affects tree shaking
          sideEffects: boolean;
          /// the query parsed from specifier, for example, query should be `{ inline: true }` if specifier is `./a.png?inline`
          /// if you custom plugins, your plugin should be responsible for parsing query
          /// if you just want a normal query parsing like the example above, [crate::utils::parse_query] is for you
          query: [string, string][] | null;
          /// meta data of the module, will be passed to [PluginLoadHookParam] and [PluginTransformHookParam]
          meta: Record<string, string> | null;
          }
          -
          note

          All filters sources and importers of resolve hook are regex string.

          +
          type ResolveHook = { 
          filters: {
          importers: string[];
          sources: string[];
          };
          executor: Callback<PluginResolveHookParam, PluginResolveHookResult>
          };

          type Callback<P, R> = (
          param: P,
          context?: CompilationContext,
          hookContext?: { caller?: string; meta: Record<string, unknown> }
          ) => Promise<R | null | undefined>;

          /// Parameter of the resolve hook
          export interface PluginResolveHookParam {
          /// the start location to resolve `source`, being [None] if resolving a entry or resolving a hmr update.
          /// it's id of the parent module, for example: `src/index.ts` or `src/index.vue?vue&type=xxx`
          importer: string | null;
          /// for example, [ResolveKind::Import] for static import (`import a from './a'`)
          kind: ResolveKind;
          /// source of the import. for example in index.ts (import App from "./App.vue")
          /// source should be './App.vue'
          source: string;
          }
          /// Resolve result of the resolve hook
          export interface PluginResolveHookResult {
          /// resolved path, normally a absolute path. you can also return a virtual path, and use [PluginLoadHookResult] to provide the content of the virtual path
          resolvedPath: string;
          /// whether this module should be external, if true, the module won't present in the final result
          external: boolean;
          /// whether this module has side effects, affects tree shaking
          sideEffects: boolean;
          /// the query parsed from specifier, for example, query should be `{ inline: true }` if specifier is `./a.png?inline`
          /// if you custom plugins, your plugin should be responsible for parsing query
          /// if you just want a normal query parsing like the example above, [crate::utils::parse_query] is for you
          query: [string, string][] | null;
          /// meta data of the module, will be passed to [PluginLoadHookParam] and [PluginTransformHookParam]
          meta: Record<string, string> | null;
          }
          +
          note

          All filters sources and importers of resolve hook are regex string.

          Custom source resolving from importer, for example, resolving ./b from a.ts:

          -
          a.ts
          import b from './b?raw';
          // ...
          +
          a.ts
          import b from './b?raw';
          // ...

          Then the resolve params would be:

          -
          const param = {
          source: "./b",
          importer: { relative_path: "a.ts", query_string: "" },
          kind: 'import'
          }
          +
          const param = {
          source: "./b",
          importer: { relative_path: "a.ts", query_string: "" },
          kind: 'import'
          }

          The resolve result of default resolver would be:

          -
          const resolve_result = {
          resolved_path: "/root/b.ts", // resolved absolute path of the module
          external: false, // this module should be included in the final compiled resources and should not be external
          side_effects: false, // this module may be tree shaken as it does not contains side effects
          query: [["raw", ""]], // query from the source.
          meta: {}
          }
          +
          const resolve_result = {
          resolved_path: "/root/b.ts", // resolved absolute path of the module
          external: false, // this module should be included in the final compiled resources and should not be external
          side_effects: false, // this module may be tree shaken as it does not contains side effects
          query: [["raw", ""]], // query from the source.
          meta: {}
          }

          The HookContext is used to pass status when you can the hooks recursively, for example, your plugin call context.resolve in resolve hook:

          -
          const myPlugin = () => ({
          name: 'my-plugin',
          resolve: {
          filters: {
          sources: ['^.+foo.+$'],
          importers: ['^src/index.ts$']
          },
          executor: async (param, context, hookContext) => {
          console.log(param);
          if (hookContext.caller === 'my-plugin') {
          return null;
          }
          // replace the original source and resolve new source
          const newSource = param.source.replace('foo', 'bar');
          return context.resolve({
          ...param,
          source: newSource
          }, {
          caller: 'my-plugin',
          meta: {}
          });
          }
          }
          });
          +
          const myPlugin = () => ({
          name: 'my-plugin',
          resolve: {
          filters: {
          sources: ['^.+foo.+$'],
          importers: ['^src/index.ts$']
          },
          executor: async (param, context, hookContext) => {
          console.log(param);
          if (hookContext.caller === 'my-plugin') {
          return null;
          }
          // replace the original source and resolve new source
          const newSource = param.source.replace('foo', 'bar');
          return context.resolve({
          ...param,
          source: newSource
          }, {
          caller: 'my-plugin',
          meta: {}
          });
          }
          }
          });

          In above example, we call context.resolve and pass caller as parameter, then we should add a guard like if (hookContext.caller === 'my-plugin') { to avoid infinite loop.

          Note:

            @@ -117,26 +117,26 @@

            resolveload

            +

            load

            • required: false
            • hook type: first
            • type:
            -
            type LoadHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginLoadHookParam, PluginLoadHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginLoadHookParam {
            moduleId: string;
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            }

            export interface PluginLoadHookResult {
            /// the content of the module
            content: string;
            /// the type of the module, for example [ModuleType::Js] stands for a normal javascript file,
            /// usually end with `.js` extension
            moduleType: ModuleType;
            /// source map of the module
            sourceMap?: string | null;
            }
            +
            type LoadHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginLoadHookParam, PluginLoadHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginLoadHookParam {
            moduleId: string;
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            }

            export interface PluginLoadHookResult {
            /// the content of the module
            content: string;
            /// the type of the module, for example [ModuleType::Js] stands for a normal javascript file,
            /// usually end with `.js` extension
            moduleType: ModuleType;
            /// source map of the module
            sourceMap?: string | null;
            }

            Custom how to load your module from a resolved module path or module id. For example, load a virtual module:

            -
            const myPlugin = () => ({
            name: 'my-plugin',
            load: {
            filters: {
            resolvedPaths: ['^virtual:my-plugin$'],
            },
            executor: async (param, context, hookContext) => {
            if (param.resolvedPath === 'virutal:my-plugin') {
            return {
            content: 'export default "foo"',
            moduleType: 'js'
            };
            }
            }
            }
            });
            +
            const myPlugin = () => ({
            name: 'my-plugin',
            load: {
            filters: {
            resolvedPaths: ['^virtual:my-plugin$'],
            },
            executor: async (param, context, hookContext) => {
            if (param.resolvedPath === 'virutal:my-plugin') {
            return {
            content: 'export default "foo"',
            moduleType: 'js'
            };
            }
            }
            }
            });

            module_type and content is required when loading modules in your load hook. source_map is optional, you can return source map if you do transform in the load hook(which is not recommended, we recommend to use transform hook for this situation) or you load original source map from other locations.

            filters.resolvedPath of load hook is resolvedPath + query, for example: /root/src/index.vue?vue&type=style&lang=css. If you want to ignore query when filtering modules, you can use $: src/index\\.vue$; If you want to filter modules by query, for example, filtering lang=css, you can use src/index.vue\\.+\\?vue&.+lang=css.

            -

            transform

            +

            transform

            • required: false
            • hook type: serial
            • type:
            -
            type TransformHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginTransformHookParam, PluginTransformHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginTransformHookParam {
            moduleId: string;
            /// source content after load or transformed result of previous plugin
            content: string;
            /// module type after load
            moduleType: ModuleType; // Module Type is 'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'html'...
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            sourceMapChain: string[];
            }

            export interface PluginTransformHookResult {
            /// transformed source content, will be passed to next plugin.
            content: string;
            /// you can change the module type after transform.
            moduleType?: ModuleType;
            /// transformed source map, all plugins' transformed source map will be stored as a source map chain.
            sourceMap?: string | null;
            // ignore previous source map. if true, the source map chain will be cleared. and this result should return a new source map that combines all previous source map.
            ignorePreviousSourceMap?: boolean;
            }
            +
            type TransformHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginTransformHookParam, PluginTransformHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginTransformHookParam {
            moduleId: string;
            /// source content after load or transformed result of previous plugin
            content: string;
            /// module type after load
            moduleType: ModuleType; // Module Type is 'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'html'...
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            sourceMapChain: string[];
            }

            export interface PluginTransformHookResult {
            /// transformed source content, will be passed to next plugin.
            content: string;
            /// you can change the module type after transform.
            moduleType?: ModuleType;
            /// transformed source map, all plugins' transformed source map will be stored as a source map chain.
            sourceMap?: string | null;
            // ignore previous source map. if true, the source map chain will be cleared. and this result should return a new source map that combines all previous source map.
            ignorePreviousSourceMap?: boolean;
            }

            Do transformation based on module content and module type. Example for transforming sass to css:

            -
            export default function farmSassPlugin(
            options: SassPluginOptions = {}
            ): JsPlugin {
            return {
            name: pluginName,
            load: {
            filters: { resolvedPaths: ['\\.(scss|sass)$'] },
            async executor(param) {
            if (param.query.length === 0 && existsSync(param.resolvedPath)) {
            const data = await readFile(param.resolvedPath);
            return {
            content: data,
            moduleType: 'sass'
            };
            }

            return null;
            }
            },
            transform: {
            filters: {
            moduleTypes: ['sass']
            },
            async executor(param, ctx) {
            const { css: compiledCss, map } = compileSass(param.content);
            return {
            content: compiledCss,
            moduleType: 'css' // transformed sass to css,
            sourceMap: JSON.stringify(map)
            ignorePreviousSourceMap: false,
            }
            }
            }
            }
            }
            +
            export default function farmSassPlugin(
            options: SassPluginOptions = {}
            ): JsPlugin {
            return {
            name: pluginName,
            load: {
            filters: { resolvedPaths: ['\\.(scss|sass)$'] },
            async executor(param) {
            if (param.query.length === 0 && existsSync(param.resolvedPath)) {
            const data = await readFile(param.resolvedPath);
            return {
            content: data,
            moduleType: 'sass'
            };
            }

            return null;
            }
            },
            transform: {
            filters: {
            moduleTypes: ['sass']
            },
            async executor(param, ctx) {
            const { css: compiledCss, map } = compileSass(param.content);
            return {
            content: compiledCss,
            moduleType: 'css' // transformed sass to css,
            sourceMap: JSON.stringify(map)
            ignorePreviousSourceMap: false,
            }
            }
            }
            }
            }

            Normal steps for writing transform hook:

            1. add a if guard based moduleType or resolvedPath or moduleId
            2. @@ -150,8 +150,8 @@

              transformfilters.resolvedPaths is resolvedPath + query, for example: /root/src/index.vue?vue&type=style&lang=css. If you want to ignore query when filtering modules, you can use $: src/index\\.vue$; If you want to filter modules by query, for example, filtering lang=css, you can use src/index.vue\\.+\\?vue&.+lang=css.
            3. filters.moduleTypes is NOT regex, it must exactly match the ModuleType like css, js, tsx, etc.
          - -

          buildEnd

          +
          note

          transform hook is content to content. There is a similar hook called process_module, process_module is ast to ast. Js plugin does not support process_module hook due to performance issues, if you want ast to ast transformations, try Rust Plugin instead.

          +

          buildEnd

    -
    note

    buildEnd is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger buildEnd.

    -

    renderStart

    +
    const myPlugin = () => {
    // your plugin operations
    let myPluginContext = createMyPluginContext();

    return {
    name: 'my-plugin',
    buildEnd: {
    async executor() {
    // update my plugin status
    myPluginContext.updateStatus('module-graph-built');
    }
    }
    }
    }
    +
    note

    buildEnd is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger buildEnd.

    +

    renderStart

    • type: renderStart?: { executor: Callback<Config['config'], void>; };
    • hook type: parallel
    • @@ -169,36 +169,36 @@

      renderStart

      Called before the resources render starts.

      Example:

      -
      const myPlugin = () => {
      // your plugin operations
      let myPluginContext = createMyPluginContext();

      return {
      name: 'my-plugin',
      renderStart: {
      async executor() {
      // update my plugin status
      myPluginContext.updateStatus('render-start');
      }
      }
      }
      }
      -
      note

      renderStart is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger renderStart.

      -

      renderResourcePot

      +
      const myPlugin = () => {
      // your plugin operations
      let myPluginContext = createMyPluginContext();

      return {
      name: 'my-plugin',
      renderStart: {
      async executor() {
      // update my plugin status
      myPluginContext.updateStatus('render-start');
      }
      }
      }
      }
      +
      note

      renderStart is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger renderStart.

      +

      renderResourcePot

      • required: false
      • hook type: serial
      • type:
      -
      type RenderResourcePotHook = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      RenderResourcePotParams,
      RenderResourcePotResult
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };

      export interface RenderResourcePotParams {
      content: string;
      sourceMapChain: string[];
      resourcePotInfo: {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      };
      }
      export interface RenderResourcePotResult {
      content: string;
      sourceMap?: string;
      }
      +
      type RenderResourcePotHook = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      RenderResourcePotParams,
      RenderResourcePotResult
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };

      export interface RenderResourcePotParams {
      content: string;
      sourceMapChain: string[];
      resourcePotInfo: {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      };
      }
      export interface RenderResourcePotResult {
      content: string;
      sourceMap?: string;
      }

      Resource Pot is the abstract representation of the final output bundle file, you can return transformed resourcePot content to mutate the final bundle. For example, rendering css:

      -
      const myPlugin = () => ({
      name: 'test-render-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return {
      content: param.content.replace(
      '<--layer-->',
      cssCode
      ),
      sourceMap
      };
      }
      }
      })
      +
      const myPlugin = () => ({
      name: 'test-render-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return {
      content: param.content.replace(
      '<--layer-->',
      cssCode
      ),
      sourceMap
      };
      }
      }
      })

      We transform all <--layer--> in css resource pot and replace them to real css code.

      -
      note

      When both filters.moduleIds and filters.resourcePotTypes are specified, take the union.

      -

      augmentResourceHash

      +
      note

      When both filters.moduleIds and filters.resourcePotTypes are specified, take the union.

      +

      augmentResourceHash

      • required: false
      • hook type: serial
      • type:
      -
      type AugmentResourceHash = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      },
      string
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };
      +
      type AugmentResourceHash = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      },
      string
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };

      Append resource hash for give Resource Pot. Useful if you want to add additional conditions when generating resource hash.

      -
      const myPlugin = () => ({
      name: 'test-augment-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return 'my-hash-args';
      }
      }
      })
      -
      note

      When both filters.moduleIds and filters.resourcePotTypes are specified, take the union.

      -

      finalizeResources

      +
      const myPlugin = () => ({
      name: 'test-augment-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return 'my-hash-args';
      }
      }
      })
      +
      note

      When both filters.moduleIds and filters.resourcePotTypes are specified, take the union.

      +

      finalizeResources

      • required: false
      • hook type: serial
      • type:
      -
      type FinalizeResourcesHook = {
      executor: Callback<
      FinalizeResourcesHookParams,
      FinalizeResourcesHookParams['resourcesMap']
      >;
      };

      export type FinalizeResourcesHookParams = {
      resourcesMap: Record<string, Resource>;
      config: Config['config'];
      };

      export interface Resource {
      name: string;
      bytes: number[];
      emitted: boolean;
      resourceType: string;
      origin: { type: 'ResourcePot' | 'Module'; value: string };
      info?: ResourcePotInfo;
      }
      +
      type FinalizeResourcesHook = {
      executor: Callback<
      FinalizeResourcesHookParams,
      FinalizeResourcesHookParams['resourcesMap']
      >;
      };

      export type FinalizeResourcesHookParams = {
      resourcesMap: Record<string, Resource>;
      config: Config['config'];
      };

      export interface Resource {
      name: string;
      bytes: number[];
      emitted: boolean;
      resourceType: string;
      origin: { type: 'ResourcePot' | 'Module'; value: string };
      info?: ResourcePotInfo;
      }

      Do some transformations for all generated resources, return transformed resourcesMap. You can add, remove, modify final generated resources in this hook.

      Note:

        @@ -206,53 +206,53 @@

        finalizeRe
      • name is the final file name.
      • origin represent where this Resource is from, ResourcePot means it's generated from ResourcePot which is a modules bundle; Module means it's from Module, for example, static files like .png/.jpg are from Module.
      -

      transformHtml

      +

      transformHtml

      • required: false
      • hook type: serial
      • type:
      -
      type TransformHtmlHook = {
      order?: 0 | 1 | 2;
      executor: Callback<{ htmlResource: Resource }, Resource>;
      };
      +
      type TransformHtmlHook = {
      order?: 0 | 1 | 2;
      executor: Callback<{ htmlResource: Resource }, Resource>;
      };

      The order is used to configure when to execute transformHtml hook:

      • 0: means pre, executed before parse and generate resources. You can transform original html in this stage.
      • 1 and 2: means normal and post, executed after parse and generate resources. In this stage, all <script>, <link> tag are injected.

      Transform the final generated html(after all <script>, <link> tag are injected).

      -
      const myPlugin = () => ({
      name: 'my-plugin',
      transformHtml: {
      order: 2,
      async executor({ htmlResource }) {
      const htmlCode = Buffer.from(htmlResource).toString();

      const newHtmlCode = htmlCode.replace('my-app-data', data);
      htmlResource.bytes = [...Buffer.from(newHtmlCode)];

      return htmlResource;
      }
      }
      });
      -
      note

      You should modify bytes field of htmlResource and return the mutated htmlResource, mutate any other fields take no effects

      -

      writeResources

      +
      const myPlugin = () => ({
      name: 'my-plugin',
      transformHtml: {
      order: 2,
      async executor({ htmlResource }) {
      const htmlCode = Buffer.from(htmlResource).toString();

      const newHtmlCode = htmlCode.replace('my-app-data', data);
      htmlResource.bytes = [...Buffer.from(newHtmlCode)];

      return htmlResource;
      }
      }
      });
      +
      note

      You should modify bytes field of htmlResource and return the mutated htmlResource, mutate any other fields take no effects

      +

      writeResources

      • required: false
      • hook type: serial
      • type:
      -
      type WriteResourcesHook = {
      executor: (param: FinalizeResourcesHookParams) => void | Promise<void>;
      };
      +
      type WriteResourcesHook = {
      executor: (param: FinalizeResourcesHookParams) => void | Promise<void>;
      };

      Called AFTER all resources are written to disk.

      -

      pluginCacheLoaded

      +

      pluginCacheLoaded

      • required: false
      • hook type: serial
      • type:
      -
      type PluginCacheLoadedHook = {
      executor: Callback<number[], undefined | null | void>;
      };
      +
      type PluginCacheLoadedHook = {
      executor: Callback<number[], undefined | null | void>;
      };

      Extend persistent cache loading for your plugin.

      When Persistent Cache enabled, load and transform hook may be skipped when hitting cache. If your plugin relies on previous compilation result(for example, load a virtual module based on existing modules), you may need to implement this hook to load cached infos of your plugin to ensure cache work as expected.

      Example:

      -
      const myPlugin = () => {
      let cachedData;

      return {
      name: 'my-plugin',
      pluginCacheLoaded: {
      async executor(bytes) {
      const str = Buffer.from(bytes).toString();
      cachedData = JSON.parse(str);
      }
      }
      }
      }
      -
      note

      You must decide how to serialize/deserialize cache to bytes in your plugins. For a basic example, you can deserialize data by [...Buffer.from(JSON.stringify(data))]

      -

      writePluginCache

      +
      const myPlugin = () => {
      let cachedData;

      return {
      name: 'my-plugin',
      pluginCacheLoaded: {
      async executor(bytes) {
      const str = Buffer.from(bytes).toString();
      cachedData = JSON.parse(str);
      }
      }
      }
      }
      +
      note

      You must decide how to serialize/deserialize cache to bytes in your plugins. For a basic example, you can deserialize data by [...Buffer.from(JSON.stringify(data))]

      +

      writePluginCache

      • required: false
      • hook type: serial
      • type:
      -
      type WritePluginCacheHook = {
      executor: Callback<undefined, number[]>;
      };
      +
      type WritePluginCacheHook = {
      executor: Callback<undefined, number[]>;
      };

      Extend persistent cache writing for your plugin. writePluginCache is often used together with pluginCaceLoaded to read and write persistent cache for plugin. Return the serialized bytes of your data.

      Example:

      -
      const myPlugin = () => {
      let cachedData = { foo: 'bar' };

      return {
      name: 'my-plugin',
      writePluginCache: {
      async executor() {
      const bytes = [...Buffer.from(JSON.stringify(data))];
      return bytes;
      }
      }
      }
      }
      -
      note

      You must decide how to serialize/deserialize cache to bytes in your plugins. For a basic example, you can deserialize data by [...Buffer.from(JSON.stringify(data))]

      -

      finish

      +
      const myPlugin = () => {
      let cachedData = { foo: 'bar' };

      return {
      name: 'my-plugin',
      writePluginCache: {
      async executor() {
      const bytes = [...Buffer.from(JSON.stringify(data))];
      return bytes;
      }
      }
      }
      }
      +
      note

      You must decide how to serialize/deserialize cache to bytes in your plugins. For a basic example, you can deserialize data by [...Buffer.from(JSON.stringify(data))]

      +

      finish

    -
    note

    finish is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger finish.

    -

    updateModules

    +
    const myPlugin = () => {
    // your plugin operations
    let myPluginContext = createMyPluginContext();

    return {
    name: 'my-plugin',
    finish: {
    async executor() {
    // update my plugin status
    myPluginContext.updateStatus('finish');
    }
    }
    }
    }
    +
    note

    finish is only called once for the first compile. Later compiling like Lazy Compilation and HMR Update won't trigger finish.

    +

    updateModules

    • required: false
    • hook type: serial
    • type:
    -
    type UpdateModulesHook = {
    executor: Callback<
    { paths: [string, string][] },
    string[] | undefined | null | void
    >;
    };
    +
    type UpdateModulesHook = {
    executor: Callback<
    { paths: [string, string][] },
    string[] | undefined | null | void
    >;
    };

    Called when calling compiler.update(module_paths). Useful to do some operations like clearing previous state or ignore some files when performing HMR.

    • paths is paths that will be recompiled for this update
    • return the new paths, later compilation will update the new returned paths.
    • -
    +
    \ No newline at end of file diff --git a/docs/api/runtime-plugin-api/index.html b/docs/api/runtime-plugin-api/index.html index d62fbd0e8..c254eaeee 100644 --- a/docs/api/runtime-plugin-api/index.html +++ b/docs/api/runtime-plugin-api/index.html @@ -8,64 +8,64 @@ - - - + + + -
    Version: 1.0.0

    Runtime Plugin API

    +
    Version: 1.0.0

    Runtime Plugin API

    Plugin hook definition:

    -
    export interface FarmRuntimePlugin {
    // plugin name
    name: string;
    // invoked when the module system is bootstrapped
    bootstrap?: (moduleSystem: ModuleSystem) => void | Promise<void>;
    // invoked after new module instances are created
    moduleCreated?: (module: Module) => void | Promise<void>;
    // invoked after module initialization functions are called
    moduleInitialized?: (module: Module) => void | Promise<void>;
    // invoked after module caches are read, return true to skip cache reading
    readModuleCache?: (module: Module) => boolean | Promise<boolean>;
    // called when module is not found
    moduleNotFound?: (moduleId: string) => void | Promise<void>;
    // called when loading resources, custom your resource loading in this hook.
    // return { success: true } to indicate that this resources have been loaded successfully.
    // return { success: false, retryWithDefaultResourceLoader: true } to indicate that this resources have not been loaded successfully and should be retried with the default resource loader.
    loadResource?: (
    resource: Resource,
    targetEnv: 'browser' | 'node'
    ) => Promise<ResourceLoadResult>;
    }
    -

    Writing Runtime Plugin

    +
    export interface FarmRuntimePlugin {
    // plugin name
    name: string;
    // invoked when the module system is bootstrapped
    bootstrap?: (moduleSystem: ModuleSystem) => void | Promise<void>;
    // invoked after new module instances are created
    moduleCreated?: (module: Module) => void | Promise<void>;
    // invoked after module initialization functions are called
    moduleInitialized?: (module: Module) => void | Promise<void>;
    // invoked after module caches are read, return true to skip cache reading
    readModuleCache?: (module: Module) => boolean | Promise<boolean>;
    // called when module is not found
    moduleNotFound?: (moduleId: string) => void | Promise<void>;
    // called when loading resources, custom your resource loading in this hook.
    // return { success: true } to indicate that this resources have been loaded successfully.
    // return { success: false, retryWithDefaultResourceLoader: true } to indicate that this resources have not been loaded successfully and should be retried with the default resource loader.
    loadResource?: (
    resource: Resource,
    targetEnv: 'browser' | 'node'
    ) => Promise<ResourceLoadResult>;
    }
    +

    Writing Runtime Plugin

    See Writing Runtime Plugin

    -

    Hooks

    +

    Hooks

    Then are 2 kind of execution orders when calling Farm runtime plugin hooks:

    • serial: The hook is called ono by one by the order of plugins. All plugins would be called serially.
    • first: Skip all left plugins once truthy value is returned.

    Hook execution order:

    -
              for each module                     true                         true                     return false
    bootstrap -----------> module registered? ------> module initialized? ----> readModuleCache -------------------------> done
    | | false |false | return true |
    | | |--------------> moduleCreated ------> moduleInitialized --|
    | |-------------------> moduleNotFound
    |
    | dynamic import
    | ---------------> loadResource
    -

    name

    +
              for each module                     true                         true                     return false
    bootstrap -----------> module registered? ------> module initialized? ----> readModuleCache -------------------------> done
    | | false |false | return true |
    | | |--------------> moduleCreated ------> moduleInitialized --|
    | |-------------------> moduleNotFound
    |
    | dynamic import
    | ---------------> loadResource
    +

    name

    • type: string

    The name of your runtime plugin.

    -

    bootstrap

    +

    bootstrap

    • hook type: serial
    • type: (moduleSystem: ModuleSystem) => void | Promise<void>

    Invoked once when the module system is bootstrapped. Setup your plugin in this hook. Example:

    -
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // define hooks
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    };
    -

    moduleCreated

    +
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // define hooks
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    };
    +

    moduleCreated

    • hook type: serial
    • type: (module: Module) => void | Promise<void>

    Invoked after new module instances are created. You can read or update property of the new created module.

    -
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    moduleCreated(module) {
    // create a hot context for each module
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };
    -
    note

    moduleCreated is called BEFORE the module is executed, so module.exports is always empty, use moduleInitialized instead if you want to access module.exports.

    -

    moduleInitialized

    +
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    moduleCreated(module) {
    // create a hot context for each module
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };
    +
    note

    moduleCreated is called BEFORE the module is executed, so module.exports is always empty, use moduleInitialized instead if you want to access module.exports.

    +

    moduleInitialized

    • hook type: serial
    • type: (module: Module) => void | Promise<void>

    Invoked after module initialization functions are called.

    -
    note

    moduleCreated is called AFTER the module is executed, so module.exports is available is this hook.

    -

    readModuleCache

    +
    note

    moduleCreated is called AFTER the module is executed, so module.exports is available is this hook.

    +

    readModuleCache

    • hook type: serial
    • type: (module: Module) => boolean | Promise<boolean>

    Invoked after module caches are read, return true to skip cache reading and re-executed the module.

    -

    moduleNotFound

    +

    moduleNotFound

    • hook type: serial
    • type: (module: Module) => void | Promise<void>

    Called when module is not registered.

    -

    loadResource

    +

    loadResource

    -
    import { Plugin } from '@farmfe/runtime';

    export default <Plugin>{
    name: 'runtime-plugin-example',
    loadResource: (resource, targetEnv) => {
    // override default resource loading
    // load the resource from different location
    return import('./replaced.js').then(() => {
    return {
    success: true
    };
    });
    }
    };

    +
    import { Plugin } from '@farmfe/runtime';

    export default <Plugin>{
    name: 'runtime-plugin-example',
    loadResource: (resource, targetEnv) => {
    // override default resource loading
    // load the resource from different location
    return import('./replaced.js').then(() => {
    return {
    success: true
    };
    });
    }
    };

    \ No newline at end of file diff --git a/docs/api/rust-api/index.html b/docs/api/rust-api/index.html index a3a36af46..44b4c0849 100644 --- a/docs/api/rust-api/index.html +++ b/docs/api/rust-api/index.html @@ -8,14 +8,14 @@ - - - + + + -
    Version: 1.0.0

    Rust Api

    +
    Version: 1.0.0

    Rust Api

    You can create a Farm Rust compiler in your rust code. Example:

    -
    use farmfe_compiler::Compiler;
    use farmfe_core::config::Config;

    // create farm compiler
    pub fn create_farm_compiler() {
    let config = Config::default();
    let extra_plugins = vec![];

    let compiler = Compiler::new(config, extra_plugins);

    compiler
    }

    // compile the project
    pub fn compile() {
    let compiler = create_farm_compiler();
    compiler.compile()
    }

    // perform hot update
    pub fn update(compiler: Compiler) {
    let update_result = compiler.update(vec![(String::from("/root/index.ts"), UpdateType:Update)], || {
    // called when all update(including resource regeneration) finished
    }, true);

    // handle update_result...
    }
    -

    Farm Rust compiler is exported by farmfe_compiler crate. Refer to farmfe_compiler documentation.

    +
    use farmfe_compiler::Compiler;
    use farmfe_core::config::Config;

    // create farm compiler
    pub fn create_farm_compiler() {
    let config = Config::default();
    let extra_plugins = vec![];

    let compiler = Compiler::new(config, extra_plugins);

    compiler
    }

    // compile the project
    pub fn compile() {
    let compiler = create_farm_compiler();
    compiler.compile()
    }

    // perform hot update
    pub fn update(compiler: Compiler) {
    let update_result = compiler.update(vec![(String::from("/root/index.ts"), UpdateType:Update)], || {
    // called when all update(including resource regeneration) finished
    }, true);

    // handle update_result...
    }
    +

    Farm Rust compiler is exported by farmfe_compiler crate. Refer to farmfe_compiler documentation.

    \ No newline at end of file diff --git a/docs/api/rust-plugin-api/index.html b/docs/api/rust-plugin-api/index.html index 224d5bebd..222303eb5 100644 --- a/docs/api/rust-plugin-api/index.html +++ b/docs/api/rust-plugin-api/index.html @@ -8,22 +8,22 @@ - - - + + + -
    Version: 1.0.0

    Rust Plugin Api

    -
    note

    This document only covers the details of the plugin hooks. For how to create, build and publish a rust plugin see: Writing Rust Plugins

    -

    Configuring Rust Plugins

    +
    Version: 1.0.0

    Rust Plugin Api

    +
    note

    This document only covers the details of the plugin hooks. For how to create, build and publish a rust plugin see: Writing Rust Plugins

    +

    Configuring Rust Plugins

    Adding Rust plugins by plugins option:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // configuring it in plugins
    plugins: [
    ['@farmfe/plugin-sass', { /** plugin options here */ }]
    ],
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // configuring it in plugins
    plugins: [
    ['@farmfe/plugin-sass', { /** plugin options here */ }]
    ],
    });

    Configuring the Rust plugin package name(or path) in string and its options in object.

    -

    Writing Rust Plugin

    +

    Writing Rust Plugin

    See Writing Rust Plugins for details.

    -

    Plugin Hooks Overview

    +

    Plugin Hooks Overview

    Farm provides a lot of rollup-style hooks, these hooks are divided into build stage and generate stage: -Farm Plugin Hooks

    +Farm Plugin Hooks

    All plugin hooks accept a parameter called CompilationContext. All of the shared compilation info are stored in the context.

    There are three kinds of hooks (the same as Rollup):

      @@ -31,73 +31,73 @@

      Plugin
    • serial: The hooks execute in serial, and every hook's result will pass to the next hook, using the last hook's result as the final result.
    • parallel: The hooks execute in parallel in a thread pool and should be isolated.
    -
    note

    For full Plugin Hooks signature, see Plugin Trait

    -

    name

    +
    note

    For full Plugin Hooks signature, see Plugin Trait

    +

    name

    • required: true
    • default:
    -
    fn name(&self) -> &str;
    +
    fn name(&self) -> &str;

    Returns the name of this plugin. Example:

    -
    impl Plugin for MyPlugin {
    fn name(&self) -> &str {
    "MyPlugin"
    }
    }
    -

    priority

    +
    impl Plugin for MyPlugin {
    fn name(&self) -> &str {
    "MyPlugin"
    }
    }
    +

    priority

    • required: false
    • default:
    -
    fn priority(&self) -> i32 {
    100
    }
    +
    fn priority(&self) -> i32 {
    100
    }

    Define the priority of this plugin, the larger the value, the earlier this plugin execute. When plugins has same priority, they will be executed as the same order as the registered order in plugins.

    -
    note

    By default, all custom plugin's priority is 100. And some internal plugins' order is 99, like plugin-script, plugin-css, you can override the internal plugin's behavior when default priority. But some internal plugins' priority is 101, like plugin-resolve, plugin-html, you should setup a larger priority if you want override the default behavior.

    -

    config

    +
    note

    By default, all custom plugin's priority is 100. And some internal plugins' order is 99, like plugin-script, plugin-css, you can override the internal plugin's behavior when default priority. But some internal plugins' priority is 101, like plugin-resolve, plugin-html, you should setup a larger priority if you want override the default behavior.

    +

    config

    • required: false
    • hook type: serial
    • default:
    -
    fn config(&self, _config: &mut Config) -> Result<Option<()>> {
    Ok(None)
    }
    +
    fn config(&self, _config: &mut Config) -> Result<Option<()>> {
    Ok(None)
    }

    Modify the config before compilation start in config hook. Refer to Config for definition of Config struct. Example:

    -
    impl Plugin for MyPlugin {
    // implement config hook
    fn config(&self, config: &mut Config) -> Result<Option<()>> {
    // set minify to false
    config.input.insert("custom-entry", "./custom.html");
    Ok(Some(()))
    }
    }
    +
    impl Plugin for MyPlugin {
    // implement config hook
    fn config(&self, config: &mut Config) -> Result<Option<()>> {
    // set minify to false
    config.input.insert("custom-entry", "./custom.html");
    Ok(Some(()))
    }
    }

    Note that the Rust Plugin's config hook are called after JS Plugin's config and configResolved hook.

    -

    plugin_cache_loaded

    +

    plugin_cache_loaded

    • required: false
    • hook type: serial
    • default:
    -
    fn plugin_cache_loaded(
    &self,
    _cache: &Vec<u8>,
    _context: &Arc<CompilationContext>,
    ) -> Result<Option<()>> {
    Ok(None)
    }
    +
    fn plugin_cache_loaded(
    &self,
    _cache: &Vec<u8>,
    _context: &Arc<CompilationContext>,
    ) -> Result<Option<()>> {
    Ok(None)
    }

    Extend persistent cache loading for your plugin.

    When Persistent Cache enabled, load and transform hook may be skipped when hitting cache. If your plugin relies on previous compilation result(for example, load a virtual module based on existing modules), you may need to implement this hook to load cached infos of your plugin to ensure cache work as expected.

    Example:

    -
    #[cache_item]
    struct CachedStaticAssets {
    list: Vec<Resource>,
    }

    impl Plugin for StaticAssetsPlugin {
    fn plugin_cache_loaded(
    &self,
    cache: &Vec<u8>,
    context: &Arc<CompilationContext>,
    ) -> farmfe_core::error::Result<Option<()>> {
    let cached_static_assets: CachedAssets = deserialize!(cache, CachedStaticAssets);

    for asset in cached_static_assets.list {
    if let ResourceOrigin::Module(m) = asset.origin {
    context.emit_file(EmitFileParams {
    resolved_path: m.to_string(),
    name: asset.name,
    content: asset.bytes,
    resource_type: asset.resource_type,
    });
    }
    }

    Ok(Some(()))
    }
    }
    +
    #[cache_item]
    struct CachedStaticAssets {
    list: Vec<Resource>,
    }

    impl Plugin for StaticAssetsPlugin {
    fn plugin_cache_loaded(
    &self,
    cache: &Vec<u8>,
    context: &Arc<CompilationContext>,
    ) -> farmfe_core::error::Result<Option<()>> {
    let cached_static_assets: CachedAssets = deserialize!(cache, CachedStaticAssets);

    for asset in cached_static_assets.list {
    if let ResourceOrigin::Module(m) = asset.origin {
    context.emit_file(EmitFileParams {
    resolved_path: m.to_string(),
    name: asset.name,
    content: asset.bytes,
    resource_type: asset.resource_type,
    });
    }
    }

    Ok(Some(()))
    }
    }

    Note:

    • deserialize is exposed by farmfe_core, it can help you deserialize your structs or enums from Vec<u8>.
    • The cached structs or enums must be rkyv serializable, you can use #[cache_item] exposed by farmfe_core create a cacheable struct quickly.
    -

    build_start

    +

    build_start

    • required: false
    • hook type: parallel
    • default:
    -
    fn build_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
    Ok(None)
    }
    +
    fn build_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
    Ok(None)
    }

    Called before the first compilation starts. You can use this hook to initialize any initial status of your plugins.

    -
    note

    build_start is only called once for the first compilation. If you want to do something when ModuleGraph is updated in HMR or Lazy Compilation, you should use update_modules hook.

    -

    resolve

    +
    note

    build_start is only called once for the first compilation. If you want to do something when ModuleGraph is updated in HMR or Lazy Compilation, you should use update_modules hook.

    +

    resolve

    • required: false
    • hook type: first
    • default:
    -
    fn resolve(
    &self,
    _param: &PluginResolveHookParam,
    _context: &Arc<CompilationContext>,
    _hook_context: &PluginHookContext,
    ) -> Result<Option<PluginResolveHookResult>> {
    Ok(None)
    }

    /// Parameter of the resolve hook
    #[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
    #[serde(rename_all = "camelCase")]
    pub struct PluginResolveHookParam {
    /// the source would like to resolve, for example, './index'
    pub source: String,
    /// the start location to resolve `specifier`, being [None] if resolving a entry or resolving a hmr update.
    pub importer: Option<ModuleId>,
    /// for example, [ResolveKind::Import] for static import (`import a from './a'`)
    pub kind: ResolveKind,
    }

    #[derive(Debug, Default, Serialize, Deserialize, Clone)]
    #[serde(rename_all = "camelCase", default)]
    pub struct PluginResolveHookResult {
    /// resolved path, normally a absolute file path.
    pub resolved_path: String,
    /// whether this module should be external, if true, the module won't present in the final result
    pub external: bool,
    /// whether this module has side effects, affects tree shaking
    pub side_effects: bool,
    /// the query parsed from specifier, for example, query should be `{ inline: "" }` if specifier is `./a.png?inline`
    /// if you custom plugins, your plugin should be responsible for parsing query
    /// if you just want a normal query parsing like the example above, [farmfe_toolkit::resolve::parse_query] should be helpful
    pub query: Vec<(String, String)>,
    /// the meta data passed between plugins and hooks
    pub meta: HashMap<String, String>,
    }
    +
    fn resolve(
    &self,
    _param: &PluginResolveHookParam,
    _context: &Arc<CompilationContext>,
    _hook_context: &PluginHookContext,
    ) -> Result<Option<PluginResolveHookResult>> {
    Ok(None)
    }

    /// Parameter of the resolve hook
    #[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
    #[serde(rename_all = "camelCase")]
    pub struct PluginResolveHookParam {
    /// the source would like to resolve, for example, './index'
    pub source: String,
    /// the start location to resolve `specifier`, being [None] if resolving a entry or resolving a hmr update.
    pub importer: Option<ModuleId>,
    /// for example, [ResolveKind::Import] for static import (`import a from './a'`)
    pub kind: ResolveKind,
    }

    #[derive(Debug, Default, Serialize, Deserialize, Clone)]
    #[serde(rename_all = "camelCase", default)]
    pub struct PluginResolveHookResult {
    /// resolved path, normally a absolute file path.
    pub resolved_path: String,
    /// whether this module should be external, if true, the module won't present in the final result
    pub external: bool,
    /// whether this module has side effects, affects tree shaking
    pub side_effects: bool,
    /// the query parsed from specifier, for example, query should be `{ inline: "" }` if specifier is `./a.png?inline`
    /// if you custom plugins, your plugin should be responsible for parsing query
    /// if you just want a normal query parsing like the example above, [farmfe_toolkit::resolve::parse_query] should be helpful
    pub query: Vec<(String, String)>,
    /// the meta data passed between plugins and hooks
    pub meta: HashMap<String, String>,
    }

    Custom source resolving from importer, for example, resolving ./b from a.ts:

    -
    a.ts
    import b from './b?raw';
    // ...
    +
    a.ts
    import b from './b?raw';
    // ...

    Then the resolve params would be:

    -
    let param = PluginResolveHookParam {
    source: "./b",
    importer: Some(ModuleId { relative_path: "a.ts", query_string: "" }),
    kind: ResolveKind::Import
    }
    +
    let param = PluginResolveHookParam {
    source: "./b",
    importer: Some(ModuleId { relative_path: "a.ts", query_string: "" }),
    kind: ResolveKind::Import
    }

    The resolve result of default resolver would be:

    -
    let resolve_result = PluginResolveHookResult {
    resolved_path: "/root/b.ts", // resolved absolute path of the module
    external: false, // this module should be included in the final compiled resources and should not be external
    side_effects: false, // this module may be tree shaken as it does not contains side effects
    query: vec![("raw", "")], // query from the source.
    meta: HashMap::new()
    }
    +
    let resolve_result = PluginResolveHookResult {
    resolved_path: "/root/b.ts", // resolved absolute path of the module
    external: false, // this module should be included in the final compiled resources and should not be external
    side_effects: false, // this module may be tree shaken as it does not contains side effects
    query: vec![("raw", "")], // query from the source.
    meta: HashMap::new()
    }

    The HookContext is used to pass status when you can the hooks recursively, for example, your plugin call context.plugin_driver.resolve in resolve hook:

    -
    impl Plugin for MyPlugin {
    fn resolve(
    &self,
    param: &farmfe_core::plugin::PluginResolveHookParam,
    context: &Arc<CompilationContext>,
    hook_context: &PluginHookContext,
    ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginResolveHookResult>> {
    // add a guard to avoid infinite loop
    if let Some(caller) = &hook_context.caller {
    if caller.as_str() == "FarmPluginCss" {
    return Ok(None);
    }
    }

    if matches!(param.kind, ResolveKind::CssAtImport | ResolveKind::CssUrl) {
    // if dep starts with '~', means it's from node_modules.
    // otherwise it's always relative
    let source = if let Some(striped_source) = param.source.strip_suffix('~') {
    striped_source.to_string()
    } else if !param.source.starts_with('.') {
    format!("./{}", param.source)
    } else {
    param.source.clone()
    };

    // call resolve recursively
    return context.plugin_driver.resolve(
    &PluginResolveHookParam {
    source,
    ..param.clone()
    },
    context,
    &PluginHookContext {
    // pass caller we call resolve recursively
    caller: Some("FarmPluginCss".to_string()),
    meta: Default::default(),
    },
    );
    }

    Ok(None)
    }
    }
    +
    impl Plugin for MyPlugin {
    fn resolve(
    &self,
    param: &farmfe_core::plugin::PluginResolveHookParam,
    context: &Arc<CompilationContext>,
    hook_context: &PluginHookContext,
    ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginResolveHookResult>> {
    // add a guard to avoid infinite loop
    if let Some(caller) = &hook_context.caller {
    if caller.as_str() == "FarmPluginCss" {
    return Ok(None);
    }
    }

    if matches!(param.kind, ResolveKind::CssAtImport | ResolveKind::CssUrl) {
    // if dep starts with '~', means it's from node_modules.
    // otherwise it's always relative
    let source = if let Some(striped_source) = param.source.strip_suffix('~') {
    striped_source.to_string()
    } else if !param.source.starts_with('.') {
    format!("./{}", param.source)
    } else {
    param.source.clone()
    };

    // call resolve recursively
    return context.plugin_driver.resolve(
    &PluginResolveHookParam {
    source,
    ..param.clone()
    },
    context,
    &PluginHookContext {
    // pass caller we call resolve recursively
    caller: Some("FarmPluginCss".to_string()),
    meta: Default::default(),
    },
    );
    }

    Ok(None)
    }
    }

    In above example, we call context.plugin_driver.resolve and pass caller as parameter, then we should add a guard like if caller.as_str() == "FarmPluginCss" to avoid infinite loop.

    Note:

      @@ -106,25 +106,25 @@

      resolveload

      +

      load

      • required: false
      • hook type: first
      • default:
      -
      fn load(
      &self,
      _param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookParam<'a> {
      /// the module id string
      pub module_id: String,
      /// the resolved path from resolve hook
      pub resolved_path: &'a str,
      /// the query map
      pub query: Vec<(String, String)>,
      /// the meta data passed between plugins and hooks
      pub meta: HashMap<String, String>,
      }


      #[derive(Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookResult {
      /// the source content of the module
      pub content: String,
      /// the type of the module, for example [ModuleType::Js] stands for a normal javascript file,
      /// usually end with `.js` extension
      pub module_type: ModuleType,
      /// source map of the module
      pub source_map: Option<String>,
      }
      +
      fn load(
      &self,
      _param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookParam<'a> {
      /// the module id string
      pub module_id: String,
      /// the resolved path from resolve hook
      pub resolved_path: &'a str,
      /// the query map
      pub query: Vec<(String, String)>,
      /// the meta data passed between plugins and hooks
      pub meta: HashMap<String, String>,
      }


      #[derive(Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookResult {
      /// the source content of the module
      pub content: String,
      /// the type of the module, for example [ModuleType::Js] stands for a normal javascript file,
      /// usually end with `.js` extension
      pub module_type: ModuleType,
      /// source map of the module
      pub source_map: Option<String>,
      }

      Custom how to load your module from a resolved module path or module id. For example, load a virtual module:

      -
      impl Plugin for MyPlugin {
      fn load(
      &self,
      param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      // only handle the specified path
      if param.resolved_path == "virtual:my-plugin" {
      return Ok(Some(
      PluginLoadHookResult {
      content: "import real from './real-path';",
      module_type: ModuleType::Js
      source_map: None,
      }
      ))
      }

      Ok(None)
      }
      }
      +
      impl Plugin for MyPlugin {
      fn load(
      &self,
      param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      // only handle the specified path
      if param.resolved_path == "virtual:my-plugin" {
      return Ok(Some(
      PluginLoadHookResult {
      content: "import real from './real-path';",
      module_type: ModuleType::Js
      source_map: None,
      }
      ))
      }

      Ok(None)
      }
      }

      module_type and content is required when loading modules in your load hook. source_map is optional, you can return source map if you do transform in the load hook(which is not recommended, we recommend to use transform hook for this situation) or you load original source map from other locations.

      -

      transform

      +

      transform

      • required: false
      • hook type: serial
      • default:
      -
      fn transform(
      &self,
      _param: &PluginTransformHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginTransformHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginTransformHookParam<'a> {
      /// the module id string
      pub module_id: String,
      /// source content after load or transformed result of previous plugin
      pub content: String,
      /// module type after load
      pub module_type: ModuleType,
      /// resolved path from resolve hook
      pub resolved_path: &'a str,
      /// query from resolve hook
      pub query: Vec<(String, String)>,
      /// the meta data passed between plugins and hooks
      pub meta: HashMap<String, String>,
      /// source map chain of previous plugins
      pub source_map_chain: Vec<Arc<String>>,
      }


      #[derive(Debug, Default, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginTransformHookResult {
      /// transformed source content, will be passed to next plugin.
      pub content: String,
      /// you can change the module type after transform.
      pub module_type: Option<ModuleType>,
      /// transformed source map, all plugins' transformed source map will be stored as a source map chain.
      pub source_map: Option<String>,
      /// if true, the previous source map chain will be ignored, and the source map chain will be reset to [source_map] returned by this plugin.
      pub ignore_previous_source_map: bool,
      }
      +
      fn transform(
      &self,
      _param: &PluginTransformHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginTransformHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginTransformHookParam<'a> {
      /// the module id string
      pub module_id: String,
      /// source content after load or transformed result of previous plugin
      pub content: String,
      /// module type after load
      pub module_type: ModuleType,
      /// resolved path from resolve hook
      pub resolved_path: &'a str,
      /// query from resolve hook
      pub query: Vec<(String, String)>,
      /// the meta data passed between plugins and hooks
      pub meta: HashMap<String, String>,
      /// source map chain of previous plugins
      pub source_map_chain: Vec<Arc<String>>,
      }


      #[derive(Debug, Default, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginTransformHookResult {
      /// transformed source content, will be passed to next plugin.
      pub content: String,
      /// you can change the module type after transform.
      pub module_type: Option<ModuleType>,
      /// transformed source map, all plugins' transformed source map will be stored as a source map chain.
      pub source_map: Option<String>,
      /// if true, the previous source map chain will be ignored, and the source map chain will be reset to [source_map] returned by this plugin.
      pub ignore_previous_source_map: bool,
      }

      Do transformation based on module content and module type. Example for transforming sass to css:

      -
      impl Plugin for MyPlugin {
      // ignore other code ...
      fn transform(
      &self,
      param: &farmfe_core::plugin::PluginTransformHookParam,
      context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
      // module type guard is neccessary
      if param.module_type == ModuleType::Custom(String::from("sass")) {
      // parse options
      const options = parse_options(&self.options, param.module_id);
      // compile sass to css
      let compile_result = compileSass(&param.content, options);

      return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
      content: compile_result.css,
      source_map: compile_result.source_map,
      // tell farm compiler that we have transformed this module to css
      module_type: Some(farmfe_core::module::ModuleType::Css),
      ignore_previous_source_map: false,
      }));
      }

      Ok(None)
      }
      }
      +
      impl Plugin for MyPlugin {
      // ignore other code ...
      fn transform(
      &self,
      param: &farmfe_core::plugin::PluginTransformHookParam,
      context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
      // module type guard is neccessary
      if param.module_type == ModuleType::Custom(String::from("sass")) {
      // parse options
      const options = parse_options(&self.options, param.module_id);
      // compile sass to css
      let compile_result = compileSass(&param.content, options);

      return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
      content: compile_result.css,
      source_map: compile_result.source_map,
      // tell farm compiler that we have transformed this module to css
      module_type: Some(farmfe_core::module::ModuleType::Css),
      ignore_previous_source_map: false,
      }));
      }

      Ok(None)
      }
      }

      Normal steps for writing transform hook:

      1. add a if guard based module_type or resolved_path or module_id
      2. @@ -132,86 +132,86 @@

        transformreturn the transformed content, source_map and module_type

      For ignore_previous_source_map, if you handled param.source_map_chain and collapsed the source maps of previous plugins in the transform hook. You should set ignore_previous_source_map to true to ensure source map is correct. Otherwise, you should always set this option to false and leave source map chain handled by Farm.

      -
      note

      transform hook is content to content. There is a similar hook called process_module, process_module is ast to ast. So if you want to transform the loaded content string, you need to use transform hook, and if you want to transform the ast, you should use process_module hook.

      -

      parse

      +
      note

      transform hook is content to content. There is a similar hook called process_module, process_module is ast to ast. So if you want to transform the loaded content string, you need to use transform hook, and if you want to transform the ast, you should use process_module hook.

      +

      parse

      • required: false
      • hook type: first
      • default:
      -
      fn parse(
      &self,
      _param: &PluginParseHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleMetaData>> {
      Ok(None)
      }

      #[derive(Debug)]
      pub struct PluginParseHookParam {
      /// module id
      pub module_id: ModuleId,
      /// resolved path
      pub resolved_path: String,
      /// resolved query
      pub query: Vec<(String, String)>,
      pub module_type: ModuleType,
      /// source content(after transform)
      pub content: Arc<String>,
      }


      /// Module meta data shared by core plugins through the compilation
      /// Meta data which is not shared by core plugins should be stored in [ModuleMetaData::Custom]
      #[cache_item]
      pub enum ModuleMetaData {
      Script(ScriptModuleMetaData),
      Css(CssModuleMetaData),
      Html(HtmlModuleMetaData),
      Custom(Box<dyn SerializeCustomModuleMetaData>),
      }
      +
      fn parse(
      &self,
      _param: &PluginParseHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleMetaData>> {
      Ok(None)
      }

      #[derive(Debug)]
      pub struct PluginParseHookParam {
      /// module id
      pub module_id: ModuleId,
      /// resolved path
      pub resolved_path: String,
      /// resolved query
      pub query: Vec<(String, String)>,
      pub module_type: ModuleType,
      /// source content(after transform)
      pub content: Arc<String>,
      }


      /// Module meta data shared by core plugins through the compilation
      /// Meta data which is not shared by core plugins should be stored in [ModuleMetaData::Custom]
      #[cache_item]
      pub enum ModuleMetaData {
      Script(ScriptModuleMetaData),
      Css(CssModuleMetaData),
      Html(HtmlModuleMetaData),
      Custom(Box<dyn SerializeCustomModuleMetaData>),
      }

      Parse the transformed module content to ast. Js/Jsx/Ts/Tsx, css and html are supported natively by Farm. Normally you do not need to implement this hook unless you want to support a new module_type other than Js/Jsx/Ts/Tsx, css and html, use ModuleMetaData::Custom for this scenario.

      -

      process_module

      +

      process_module

      • required: false
      • hook type: serial
      • default:
      -
      fn process_module(
      &self,
      _param: &mut PluginProcessModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginProcessModuleHookParam<'a> {
      pub module_id: &'a ModuleId,
      pub module_type: &'a ModuleType,
      pub content: Arc<String>,
      pub meta: &'a mut ModuleMetaData,
      }
      +
      fn process_module(
      &self,
      _param: &mut PluginProcessModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginProcessModuleHookParam<'a> {
      pub module_id: &'a ModuleId,
      pub module_type: &'a ModuleType,
      pub content: Arc<String>,
      pub meta: &'a mut ModuleMetaData,
      }

      Do transformation of the parsed result, usually do ast transformation. For example, Farm strip typescript in process_module hook:

      -
      impl Plugin for MyPlugin {
      fn process_module(
      &self,
      param: &mut PluginProcessModuleHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      if !param.module_type.is_script() {
      return Ok(None);
      }
      // strip typescript
      if param.module_type.is_typescript() {
      swc_script_transforms::strip_typescript(param, &cm, context)?;
      }
      // ...ignore other code

      Ok(Some(()))
      }

      }
      +
      impl Plugin for MyPlugin {
      fn process_module(
      &self,
      param: &mut PluginProcessModuleHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      if !param.module_type.is_script() {
      return Ok(None);
      }
      // strip typescript
      if param.module_type.is_typescript() {
      swc_script_transforms::strip_typescript(param, &cm, context)?;
      }
      // ...ignore other code

      Ok(Some(()))
      }

      }

      In above example, we ignore non-script modules and strip type annotation of the ast for ts/tsx modules.

      -

      analyze_deps

      +

      analyze_deps

      • required: false
      • hook type: serial
      • default:
      -
      fn analyze_deps(
      &self,
      _param: &mut PluginAnalyzeDepsHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginAnalyzeDepsHookParam<'a> {
      pub module: &'a Module,
      /// analyzed deps from previous plugins, you can push new entries to it for your plugin.
      pub deps: Vec<PluginAnalyzeDepsHookResultEntry>,
      }
      +
      fn analyze_deps(
      &self,
      _param: &mut PluginAnalyzeDepsHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginAnalyzeDepsHookParam<'a> {
      pub module: &'a Module,
      /// analyzed deps from previous plugins, you can push new entries to it for your plugin.
      pub deps: Vec<PluginAnalyzeDepsHookResultEntry>,
      }

      Analyze dependencies of the module. For example, we have a.ts:

      -
      a.ts
      import b from './b';
      const c = require('./c');
      +
      a.ts
      import b from './b';
      const c = require('./c');

      then normally this hook should push 2 entries to params.deps:

      -
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./b".to_string(),
      kind: ResolveKind::Import
      });
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./c".to_string(),
      kind: ResolveKind::Require
      });
      +
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./b".to_string(),
      kind: ResolveKind::Import
      });
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./c".to_string(),
      kind: ResolveKind::Require
      });

      param.deps will be passed to resolve hook later. You can also add new deps that is not related to the ast of your module as you wish, Farm will resolve, load these unrelated modules and add them to the module graph too.

      -

      finalize_modules

      +

      finalize_modules

      • required: false
      • hook type: serial
      • default:
      -
      fn finalize_module(
      &self,
      _param: &mut PluginFinalizeModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeModuleHookParam<'a> {
      pub module: &'a mut Module,
      pub deps: &'a Vec<PluginAnalyzeDepsHookResultEntry>,
      }
      +
      fn finalize_module(
      &self,
      _param: &mut PluginFinalizeModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeModuleHookParam<'a> {
      pub module: &'a mut Module,
      pub deps: &'a Vec<PluginAnalyzeDepsHookResultEntry>,
      }

      Do any thing you want before seal the module. Note that you can only modify param.module.

      -

      build_end

      +

      build_end

      • required: false
      • hook type: parallel
      • default:
      -
      /// The module graph should be constructed and finalized here
      fn build_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// The module graph should be constructed and finalized here
      fn build_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      Called when all dependencies starting from config.input are handled and ModuleGraph is successfully constructed, you can get the full resolved ModuleGraph here by context.module_graph.

      -
      note

      build_end is only called once for the first compilation. If you want to do something when ModuleGraph is updated in HMR or Lazy Compilation, you should use module_graph_updated hook.

      -

      generate_start

      +
      note

      build_end is only called once for the first compilation. If you want to do something when ModuleGraph is updated in HMR or Lazy Compilation, you should use module_graph_updated hook.

      +

      generate_start

      • required: false
      • hook type: parallel
      • default:
      -
      fn generate_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn generate_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      Called before generate stage start.

      -

      optimize_module_graph

      +

      optimize_module_graph

      • required: false
      • hook type: serial
      • default:
      -
      /// Some optimization of the module graph should be performed here, for example, tree shaking
      fn optimize_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// Some optimization of the module graph should be performed here, for example, tree shaking
      fn optimize_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      You can do optimization of the module_graph here. For internal plugins, Farm does tree shaking, minification in this hook.

      -

      analyze_module_graph

      +

      analyze_module_graph

      • required: false
      • hook type: first
      • default:
      -
      /// Analyze module group based on module graph
      fn analyze_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleGroupGraph>> {
      Ok(None)
      }
      +
      /// Analyze module group based on module graph
      fn analyze_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleGroupGraph>> {
      Ok(None)
      }

      Analyze dynamic import of the module_graph, and groups modules based on dynamic import, return the grouped modules.

      -
      warning

      Normally you should not implement this hook, unless you want to implement a full new bundling algorithm in Farm.

      -

      partial_bundling

      +
      warning

      Normally you should not implement this hook, unless you want to implement a full new bundling algorithm in Farm.

      +

      partial_bundling

      • required: false
      • hook type: first
      • default:
      -
      /// partial bundling modules to [Vec<ResourcePot>]
      fn partial_bundling(
      &self,
      _modules: &Vec<ModuleId>,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<Vec<ResourcePot>>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,
      /// [None] if this [ResourcePot] does not contain entry module.
      /// [Some(entry_id)] otherwise
      pub entry_module: Option<ModuleId>,
      /// the resources generated in this [ResourcePot]
      resources: HashSet<String>,

      /// This field should be filled in partial_bundling_hooks.
      /// the module groups that this [ResourcePot] belongs to.
      /// A [ResourcePot] can belong to multiple module groups.
      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      }
      +
      /// partial bundling modules to [Vec<ResourcePot>]
      fn partial_bundling(
      &self,
      _modules: &Vec<ModuleId>,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<Vec<ResourcePot>>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,
      /// [None] if this [ResourcePot] does not contain entry module.
      /// [Some(entry_id)] otherwise
      pub entry_module: Option<ModuleId>,
      /// the resources generated in this [ResourcePot]
      resources: HashSet<String>,

      /// This field should be filled in partial_bundling_hooks.
      /// the module groups that this [ResourcePot] belongs to.
      /// A [ResourcePot] can belong to multiple module groups.
      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      }

      Bundle the modules to Vec<ResourcePot> based on module_group_graph and module_graph. A ResourcePot is a structure that Farm uses to hold bundled modules, it will be emitted to final resources in generate_resources hook, you can treat a ResourcePot as Chunk of other tools.

      Note:

        @@ -219,141 +219,141 @@

        partial_bun
      • You should set module.resource_pot in this hook.

      Refer to the internal implementation of partial bundling in Farm for best practice. Refer to RFC-003 Partial Bundling for how Farm designs bundling.

      -
      warning

      Normally you should not implement this hook, unless you want to implement a full new bundling algorithm in Farm. And If you override this hook, config.partial_bundling may not work unless you follow the same bundling spec as Farm.

      -

      process_resource_pots

      +
      warning

      Normally you should not implement this hook, unless you want to implement a full new bundling algorithm in Farm. And If you override this hook, config.partial_bundling may not work unless you follow the same bundling spec as Farm.

      +

      process_resource_pots

      • required: false
      • hook type: serial
      • default:
      -
      /// process resource pots before render and generating each resource
      fn process_resource_pots(
      &self,
      _resource_pots: &mut Vec<&mut ResourcePot>,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// process resource pots before render and generating each resource
      fn process_resource_pots(
      &self,
      _resource_pots: &mut Vec<&mut ResourcePot>,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      Do some transformation of the ResourcePots. Note that ResourcePots are not rendered at this time, which means you can not get the rendered code of the Resource Pot, instead, you can only add, remove, transform the modules inside the ResourcePot

      -

      render_start

      +

      render_start

      • required: false
      • hook type: serial
      • default:
      -
      fn render_start(
      &self,
      _config: &Config,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn render_start(
      &self,
      _config: &Config,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      Called before resource pots render. After rendering resource pots, executable html, css, js, etc files will be emitted.

      -
      note

      render_start is only called once for the first compilation. HMR or Lazy Compilation won't trigger render_start hook.

      -

      render_resource_pot_modules

      +
      note

      render_start is only called once for the first compilation. HMR or Lazy Compilation won't trigger render_start hook.

      +

      render_resource_pot_modules

      • required: false
      • hook type: first
      • default:
      -
      fn render_resource_pot_modules(
      &self,
      _resource_pot: &ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ResourcePotMetaData>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
      pub struct RenderedModule {
      pub id: ModuleId,
      pub rendered_content: Arc<String>,
      pub rendered_map: Option<Arc<String>>,
      pub rendered_length: usize,
      pub original_length: usize,
      }

      #[cache_item]
      #[derive(Clone, Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotMetaData {
      pub rendered_modules: HashMap<ModuleId, RenderedModule>,
      pub rendered_content: Arc<String>,
      pub rendered_map_chain: Vec<Arc<String>>,
      pub custom_data: HashMap<String, String>,
      }
      +
      fn render_resource_pot_modules(
      &self,
      _resource_pot: &ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ResourcePotMetaData>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
      pub struct RenderedModule {
      pub id: ModuleId,
      pub rendered_content: Arc<String>,
      pub rendered_map: Option<Arc<String>>,
      pub rendered_length: usize,
      pub original_length: usize,
      }

      #[cache_item]
      #[derive(Clone, Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotMetaData {
      pub rendered_modules: HashMap<ModuleId, RenderedModule>,
      pub rendered_content: Arc<String>,
      pub rendered_map_chain: Vec<Arc<String>>,
      pub custom_data: HashMap<String, String>,
      }

      Render the given ResourcePot to rendered_content and rendered_source_map_chain. This hook is used to render module's ast to bundled code. If you just want to modify the bundled code, use render_resource_pot instead.

      If you really need to use this hook, refer to plugin_runtime for best practice.

      -
      note

      Normally you should not override this hook for natively supported module types like js/jsx/ts/tsx/css/html, you should only use this hook when you ensure you want to override the default behavior for internal module types in Farm, or you want to support custom module types.

      -

      render_resource_pot

      +
      note

      Normally you should not override this hook for natively supported module types like js/jsx/ts/tsx/css/html, you should only use this hook when you ensure you want to override the default behavior for internal module types in Farm, or you want to support custom module types.

      +

      render_resource_pot

      • required: false
      • hook type: serial
      • default:
      -
      fn render_resource_pot(
      &self,
      _param: &PluginRenderResourcePotHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginRenderResourcePotHookParam {
      pub content: Arc<String>,
      pub source_map_chain: Vec<Arc<String>>,
      pub resource_pot_info: ResourcePotInfo,
      }

      #[derive(Debug, Serialize, Deserialize)]
      pub struct PluginRenderResourcePotHookResult {
      pub content: String,
      pub source_map: Option<String>,
      }
      +
      fn render_resource_pot(
      &self,
      _param: &PluginRenderResourcePotHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginRenderResourcePotHookParam {
      pub content: Arc<String>,
      pub source_map_chain: Vec<Arc<String>>,
      pub resource_pot_info: ResourcePotInfo,
      }

      #[derive(Debug, Serialize, Deserialize)]
      pub struct PluginRenderResourcePotHookResult {
      pub content: String,
      pub source_map: Option<String>,
      }

      Transform the rendered bundled code for the given ResourcePot. Return rendered content and source map.

      -
      impl Plugin for MyPlugin {
      fn render_resource_pot(
      &self,
      param: &PluginRenderResourcePotHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      if (param.resource_pot_info.resource_pot_type == ResourcePotType::Css) {
      return Ok(Some(PluginRenderResourcePotHookResult {
      content: param.content.replaceAll("<--layer-->", replaced_code),
      source_map: replaced_map,
      }))
      }

      Ok(None)
      }
      }
      +
      impl Plugin for MyPlugin {
      fn render_resource_pot(
      &self,
      param: &PluginRenderResourcePotHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      if (param.resource_pot_info.resource_pot_type == ResourcePotType::Css) {
      return Ok(Some(PluginRenderResourcePotHookResult {
      content: param.content.replaceAll("<--layer-->", replaced_code),
      source_map: replaced_map,
      }))
      }

      Ok(None)
      }
      }

      In above example, we transformed the content of a css Resource Pot, replaced all <--layer--> to replaced_code.

      -

      augment_resource_hash

      +

      augment_resource_hash

      • required: false
      • hook type: serial
      • default:
      -
      fn augment_resource_hash(
      &self,
      _render_pot_info: &ResourcePotInfo,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<String>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotInfo {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      pub module_ids: Vec<ModuleId>,
      pub map: Option<Arc<String>>,
      pub modules: HashMap<ModuleId, RenderedModule>,
      pub data: ResourcePotInfoData,
      }
      +
      fn augment_resource_hash(
      &self,
      _render_pot_info: &ResourcePotInfo,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<String>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotInfo {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      pub module_ids: Vec<ModuleId>,
      pub map: Option<Arc<String>>,
      pub modules: HashMap<ModuleId, RenderedModule>,
      pub data: ResourcePotInfoData,
      }

      Append additional hash when generating resource from given resource pot.

      -

      optimize_resource_pot

      +

      optimize_resource_pot

      • required: false
      • hook type: serial
      • default:
      -
      /// Optimize the resource pot, for example, minimize
      fn optimize_resource_pot(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,
      /// [None] if this [ResourcePot] does not contain entry module.
      /// [Some(entry_id)] otherwise
      pub entry_module: Option<ModuleId>,
      /// the resources generated in this [ResourcePot]
      resources: HashSet<String>,

      /// This field should be filled in partial_bundling_hooks.
      /// the module groups that this [ResourcePot] belongs to.
      /// A [ResourcePot] can belong to multiple module groups.
      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      pub info: Box<ResourcePotInfo>,
      }
      +
      /// Optimize the resource pot, for example, minimize
      fn optimize_resource_pot(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,
      /// [None] if this [ResourcePot] does not contain entry module.
      /// [Some(entry_id)] otherwise
      pub entry_module: Option<ModuleId>,
      /// the resources generated in this [ResourcePot]
      resources: HashSet<String>,

      /// This field should be filled in partial_bundling_hooks.
      /// the module groups that this [ResourcePot] belongs to.
      /// A [ResourcePot] can belong to multiple module groups.
      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      pub info: Box<ResourcePotInfo>,
      }

      Do some optimizations for the rendered resource pot. For example, minification. If you want to modify the rendered content of this hook, just modify resource_pot.meta.rendered_content and append sourcemap of this transformation in resource_pot.meta.rendered_source_map_chain.

      -
      note

      Optimizations like minification is handled internally by Farm, make sure that you really need to use this hook.

      -

      generate_resources

      +
      note

      Optimizations like minification is handled internally by Farm, make sure that you really need to use this hook.

      +

      generate_resources

      • required: false
      • hook type: first
      • default:
      -
      /// Generate resources based on the [ResourcePot], return [Vec<Resource>] represents the final generated files.
      /// For example, a .js file and its corresponding source map file
      fn generate_resources(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginGenerateResourcesHookResult>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginGenerateResourcesHookResult {
      pub resource: Resource,
      pub source_map: Option<Resource>,
      }
      +
      /// Generate resources based on the [ResourcePot], return [Vec<Resource>] represents the final generated files.
      /// For example, a .js file and its corresponding source map file
      fn generate_resources(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginGenerateResourcesHookResult>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginGenerateResourcesHookResult {
      pub resource: Resource,
      pub source_map: Option<Resource>,
      }

      Generate final resource for the give rendered resource pot. return generated resource and optional source map resource.

      -
      note

      For natively supported ModuleTypes like js/ts/jsx/tsx/css/html/static assets, normally you do not need to implement this hook. Use this hook when you want to support a new type of resource that not natively supported by Farm.

      -

      finalize_resources

      +
      note

      For natively supported ModuleTypes like js/ts/jsx/tsx/css/html/static assets, normally you do not need to implement this hook. Use this hook when you want to support a new type of resource that not natively supported by Farm.

      +

      finalize_resources

      • required: false
      • hook type: serial
      • default:
      -
      /// Do some finalization work on the generated resources, for example, transform html based on the generated resources
      fn finalize_resources(
      &self,
      _param: &mut PluginFinalizeResourcesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeResourcesHookParams<'a> {
      pub resources_map: &'a mut HashMap<String, Resource>,
      pub config: &'a Config,
      }
      +
      /// Do some finalization work on the generated resources, for example, transform html based on the generated resources
      fn finalize_resources(
      &self,
      _param: &mut PluginFinalizeResourcesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeResourcesHookParams<'a> {
      pub resources_map: &'a mut HashMap<String, Resource>,
      pub config: &'a Config,
      }

      Do some finalization work on the generated resources, for example, transform html based on the generated resources(insert <script>, <link> tags).

      You can also add or remove resources here.

      -

      generate_end

      +

      generate_end

      • required: false
      • hook type: parallel
      • default:
      -
      fn generate_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn generate_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      Called when all generate stage done(including finalize_resources). You can do some cleanup work here.

      -

      finish

      +

      finish

      • required: false
      • hook type: parallel
      • default:
      -
      fn finish(&self, _stat: &Stats, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn finish(&self, _stat: &Stats, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      Called when all compilation work done(including build stage and generate stage). You can do some cleanup work here.

      -
      note

      finish is only called once for the first compilation. HMR or Lazy Compilation won't trigger finish hook. You should use update_finished hook instead.

      -

      write_plugin_cache

      +
      note

      finish is only called once for the first compilation. HMR or Lazy Compilation won't trigger finish hook. You should use update_finished hook instead.

      +

      write_plugin_cache

      • required: false
      • hook type: serial
      • default:
      -
      fn write_plugin_cache(&self, _context: &Arc<CompilationContext>) -> Result<Option<Vec<u8>>> {
      Ok(None)
      }
      +
      fn write_plugin_cache(&self, _context: &Arc<CompilationContext>) -> Result<Option<Vec<u8>>> {
      Ok(None)
      }

      Extend persistent cache writing for your plugin. write_plugin_cache is often used together with plugin_cache_loaded to read and write persistent cache for plugin. Return the serialized bytes of your data.

      Example, writing cache for static assets:

      -
      impl Plugin for MyPlugin {
      fn write_plugin_cache(
      &self,
      context: &Arc<CompilationContext>,
      ) -> farmfe_core::error::Result<Option<Vec<u8>>> {
      let mut list = vec![];
      let resources_map = context.resources_map.lock();

      for (_, resource) in resources_map.iter() {
      if let ResourceOrigin::Module(m) = &resource.origin {
      if context.module_graph.read().has_module(m) {
      list.push(resource.clone());
      }
      }
      }

      if !list.is_empty() {
      let cached_static_assets = CachedStaticAssets { list };

      Ok(Some(serialize!(&cached_static_assets)))
      } else {
      Ok(None)
      }
      }
      }

      #[cache_item]
      struct CachedStaticAssets {
      list: Vec<Resource>,
      }
      -

      update_modules

      +
      impl Plugin for MyPlugin {
      fn write_plugin_cache(
      &self,
      context: &Arc<CompilationContext>,
      ) -> farmfe_core::error::Result<Option<Vec<u8>>> {
      let mut list = vec![];
      let resources_map = context.resources_map.lock();

      for (_, resource) in resources_map.iter() {
      if let ResourceOrigin::Module(m) = &resource.origin {
      if context.module_graph.read().has_module(m) {
      list.push(resource.clone());
      }
      }
      }

      if !list.is_empty() {
      let cached_static_assets = CachedStaticAssets { list };

      Ok(Some(serialize!(&cached_static_assets)))
      } else {
      Ok(None)
      }
      }
      }

      #[cache_item]
      struct CachedStaticAssets {
      list: Vec<Resource>,
      }
      +

      update_modules

      • required: false
      • hook type: serial
      • default:
      -
      /// Called when calling compiler.update(module_paths).
      /// Useful to do some operations like clearing previous state or ignore some files when performing HMR
      fn update_modules(
      &self,
      _params: &mut PluginUpdateModulesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginUpdateModulesHookParams {
      pub paths: Vec<(String, UpdateType)>,
      }
      +
      /// Called when calling compiler.update(module_paths).
      /// Useful to do some operations like clearing previous state or ignore some files when performing HMR
      fn update_modules(
      &self,
      _params: &mut PluginUpdateModulesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginUpdateModulesHookParams {
      pub paths: Vec<(String, UpdateType)>,
      }

      Called when calling compiler.update(module_paths). Useful to do some operations like clearing previous state or ignore some files when performing HMR

      • paths is paths that will be recompiled for this update
      • return the new paths, later compilation will update the new returned paths.
      -

      module_graph_updated

      +

      module_graph_updated

      • required: false
      • hook type: serial
      • default:
      -
      /// Called when calling compiler.update(module_paths).
      /// Useful to do some operations like modifying the module graph
      fn module_graph_updated(
      &self,
      _param: &PluginModuleGraphUpdatedHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginModuleGraphUpdatedHookParams {
      pub added_modules_ids: Vec<ModuleId>,
      pub removed_modules_ids: Vec<ModuleId>,
      pub updated_modules_ids: Vec<ModuleId>,
      }
      +
      /// Called when calling compiler.update(module_paths).
      /// Useful to do some operations like modifying the module graph
      fn module_graph_updated(
      &self,
      _param: &PluginModuleGraphUpdatedHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginModuleGraphUpdatedHookParams {
      pub added_modules_ids: Vec<ModuleId>,
      pub removed_modules_ids: Vec<ModuleId>,
      pub updated_modules_ids: Vec<ModuleId>,
      }

      Called when calling compiler.update(module_paths). Useful to do some operations like modifying the module graph.

      -

      update_finished

      +

      update_finished

      • required: false
      • hook type: serial
      • default:
      -
      /// Called when calling compiler.update(module_paths).
      /// This hook is called after all compilation work is done, including the resources regeneration and finalization.
      fn update_finished(
      &self,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// Called when calling compiler.update(module_paths).
      /// This hook is called after all compilation work is done, including the resources regeneration and finalization.
      fn update_finished(
      &self,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      Called when calling compiler.update(module_paths). This hook is called after all compilation work is done, including the resources regeneration and finalization.

      -

      handle_persistent_cached_module

      +

      handle_persistent_cached_module

      • required: false
      • hook type: serial
      • default:
      -
      fn handle_persistent_cached_module(
      &self,
      _module: &farmfe_core::module::Module,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<bool>> {
      Ok(None)
      }
      -

      Called when persistent cache is enabled and the cache hit for the module. Return true to skip loading cache for this module.

    +
    fn handle_persistent_cached_module(
    &self,
    _module: &farmfe_core::module::Module,
    _context: &Arc<CompilationContext>,
    ) -> Result<Option<bool>> {
    Ok(None)
    }
    +

    Called when persistent cache is enabled and the cache hit for the module. Return true to skip loading cache for this module.

    \ No newline at end of file diff --git a/docs/benchmark/index.html b/docs/benchmark/index.html index ec4e3c86e..d075d9f9c 100644 --- a/docs/benchmark/index.html +++ b/docs/benchmark/index.html @@ -8,27 +8,27 @@ - - - + + + -
    Version: 1.0.0

    Benchmarks

    -

    Introduction

    +
    Version: 1.0.0

    Benchmarks

    +

    Introduction

    Using Turbopack's bench cases (1000 React components), see https://turbo.build/pack/docs/benchmarks.

    -

    Run this benchmark yourself

    +

    Run this benchmark yourself

    Test Repo:https://github.com/farm-fe/performance-compare

    Test Machine(Linux Mint 21.1 Cinnamon, 11th Gen Intel© Core™ i5-11400 @ 2.60GHz × 6, 15.5 GiB)

    -

    Install dependencies

    -
    npm
    yarn
    pnpm
    bun
    npm install
    -

    run benchmark

    -
    npm
    yarn
    pnpm
    bun
    npm benchmark
    -

    Data

    +

    Install dependencies

    +
    npm
    yarn
    pnpm
    bun
    npm install
    +

    run benchmark

    +
    npm
    yarn
    pnpm
    bun
    npm benchmark
    +

    Data

    StartupHMR (Root)HMR (Leaf)Production Build
    Webpack8035ms345ms265ms11321ms
    Vite3078ms35ms18ms2266ms
    Rspack831ms104ms96ms724ms
    Farm403ms11ms10ms288ms

    -

    metrics

    +

    metrics

    • Cold StartUp Time: The time it takes to develop a build without caching

      @@ -54,13 +54,13 @@

      metricsBenchmark for all metrics

      +

      Benchmark for all metrics

      -

      Benchmark of HMR

      +

      Benchmark of HMR

      -

      Benchmark of Startup

      +

      Benchmark of Startup

      -

      Benchmark of Production Build

      -
    +

    Benchmark of Production Build

    +
    \ No newline at end of file diff --git a/docs/cli/cli-api/index.html b/docs/cli/cli-api/index.html index e8a24966f..d8b624c5d 100644 --- a/docs/cli/cli-api/index.html +++ b/docs/cli/cli-api/index.html @@ -8,31 +8,31 @@ - - - + + + -
    Version: 1.0.0

    Farm CLI

    +
    Version: 1.0.0

    Farm CLI

    The Farm CLI allows you to start, build, preview, and watch your application.

    To get a list of cli available to Farm, run the following command inside your command

    -
    Terminal
    npx farm -h
    +
    Terminal
    npx farm -h

    The output look like this:

    -
    Terminal
    farm/0.5.11

    Usage:
    $ farm [root]

    Commands:
    [root] Compile the project in dev mode and serve it with farm dev server
    build compile the project in production mode
    watch watch file change
    preview compile the project in watch mode
    clean [path] Clean up the cache built incrementally
    plugin [command] Commands for manage plugins

    For more info, run any command with the `--help` flag:
    $ farm --help
    $ farm build --help
    $ farm watch --help
    $ farm preview --help
    $ farm clean --help
    $ farm plugin --help

    Options:
    -l, --lazy lazyCompilation
    --host <host> specify host
    --port <port> specify port
    --open open browser on server start
    --hmr enable hot module replacement
    --cors enable cors
    --strictPort specified port is already in use, exit with error
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    -v, --version Display version number
    -

    Start

    +
    Terminal
    farm/0.5.11

    Usage:
    $ farm [root]

    Commands:
    [root] Compile the project in dev mode and serve it with farm dev server
    build compile the project in production mode
    watch watch file change
    preview compile the project in watch mode
    clean [path] Clean up the cache built incrementally
    plugin [command] Commands for manage plugins

    For more info, run any command with the `--help` flag:
    $ farm --help
    $ farm build --help
    $ farm watch --help
    $ farm preview --help
    $ farm clean --help
    $ farm plugin --help

    Options:
    -l, --lazy lazyCompilation
    --host <host> specify host
    --port <port> specify port
    --open open browser on server start
    --hmr enable hot module replacement
    --cors enable cors
    --strictPort specified port is already in use, exit with error
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    -v, --version Display version number
    +

    Start

    farm start The command is used to start the development server and compile the code in the development environment

    -
    Terminal
    Usage:
    $ farm [root]

    Options:
    -l, --lazy lazyCompilation
    --host <host> specify host
    --port <port> specify port
    --open open browser on server start
    --hmr enable hot module replacement
    --cors enable cors
    --strictPort specified port is already in use, exit with error
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -

    Build

    +
    Terminal
    Usage:
    $ farm [root]

    Options:
    -l, --lazy lazyCompilation
    --host <host> specify host
    --port <port> specify port
    --open open browser on server start
    --hmr enable hot module replacement
    --cors enable cors
    --strictPort specified port is already in use, exit with error
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    +

    Build

    farm build The command builds the products that can be used in the production environment in the default dist directory.

    -
    Terminal
    Usage:
    $ farm build

    Options:
    -o, --outDir <dir> output directory
    -i, --input <file> input file path
    -w, --watch watch file change
    --targetEnv <target> transpile targetEnv node, browser
    --format <format> transpile format esm, commonjs
    --sourcemap output source maps for build
    --treeShaking Eliminate useless code without side effects
    --minify code compression at build time
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    -

    Preview

    +
    Terminal
    Usage:
    $ farm build

    Options:
    -o, --outDir <dir> output directory
    -i, --input <file> input file path
    -w, --watch watch file change
    --targetEnv <target> transpile targetEnv node, browser
    --format <format> transpile format esm, commonjs
    --sourcemap output source maps for build
    --treeShaking Eliminate useless code without side effects
    --minify code compression at build time
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    +

    Preview

    farm preview the command for locally previewing the products built in your production environment, you need to execute farm build in advance to build the products in the production environment.

    -
    Terminal
    Usage:
    $ farm preview

    Options:
    --open [url] Whether to open the page in the browser at startup
    --port <port> Set the port number for Server snooping
    --host <host> Specify the host to listen to when Server starts
    -c --config <config> Specify the profile path
    -h, --help Show command help
    -

    Watch

    +
    Terminal
    Usage:
    $ farm preview

    Options:
    --open [url] Whether to open the page in the browser at startup
    --port <port> Set the port number for Server snooping
    --host <host> Specify the host to listen to when Server starts
    -c --config <config> Specify the profile path
    -h, --help Show command help
    +

    Watch

    farm watch the command generally listen for file changes and rebuild in node environment

    -
    Terminal

    Usage:
    $ farm watch

    Options:
    --format <format> transpile format esm, commonjs
    -o, --outDir <dir> output directory
    -i, --input <file> input file path
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    -

    Clean

    +
    Terminal

    Usage:
    $ farm watch

    Options:
    --format <format> transpile format esm, commonjs
    -o, --outDir <dir> output directory
    -i, --input <file> input file path
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    +

    Clean

    farm clean Because the incremental build provided by farm generates the cache file locally, you may need to clean up the cache file under certain circumstances (unpredictable compilation errors)

    -
    Terminal
    Usage:
    $ farm clean [path]

    Options:
    --recursive Recursively search for node_modules directories and clean them
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    +
    Terminal
    Usage:
    $ farm clean [path]

    Options:
    --recursive Recursively search for node_modules directories and clean them
    -c, --config <file> use specified config file
    -m, --mode <mode> set env mode
    --base <path> public base path
    --clearScreen allow/disable clear screen when logging
    -h, --help Display this message
    \ No newline at end of file diff --git a/docs/community/index.html b/docs/community/index.html index 60f294ec5..f3e3245e0 100644 --- a/docs/community/index.html +++ b/docs/community/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/docs/comparisons/index.html b/docs/comparisons/index.html index b2f286937..14f25e429 100644 --- a/docs/comparisons/index.html +++ b/docs/comparisons/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/docs/config/cli/index.html b/docs/config/cli/index.html index 2ce889dbd..fad554e37 100644 --- a/docs/config/cli/index.html +++ b/docs/config/cli/index.html @@ -8,27 +8,27 @@ - - - + + + -
    Version: 1.0.0

    CLI Options

    -

    create

    +
    Version: 1.0.0

    CLI Options

    +

    create

    Create a new Farm project.

    -
    pnpm create farm
    # or npm create farm
    # or yarn create farm
    # choose your favorite package manager
    +
    pnpm create farm
    # or npm create farm
    # or yarn create farm
    # choose your favorite package manager

    Other commands are provided by package @farmfe/cli:

    -

    start

    +

    start

    Start a dev server, compile the Farm project in development mode and watch file changes.

    -
    farm start
    -

    build

    +
    farm start
    +

    build

    Build a Farm project in production mode

    -
    farm build
    -

    preview

    +
    farm build
    +

    preview

    Preview the result of build command.

    -
    farm build && farm preview
    -

    watch

    +
    farm build && farm preview
    +

    watch

    Watch is usually used to compile a library project, it works Like start command but it does not launch a dev server.

    -
    farm build
    +
    farm build
    \ No newline at end of file diff --git a/docs/config/compilation-options/index.html b/docs/config/compilation-options/index.html index 9822c3234..c14893009 100644 --- a/docs/config/compilation-options/index.html +++ b/docs/config/compilation-options/index.html @@ -8,30 +8,30 @@ - - - + + + -
    Version: 1.0.0

    Compiler Options

    +
    Version: 1.0.0

    Compiler Options

    By default, Farm reads the configuration from the farm.config.ts|js|mjs file in the project root directory, an example configuration file:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";
    export default defineConfig({
    root: process.cwd(), // compiled root directory
    // compile options
    compilation: {
    //...
    },
    // Dev Server options
    server: {
    hmr: true,
    //...
    },
    // plugin configuration
    plugins: [],
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";
    export default defineConfig({
    root: process.cwd(), // compiled root directory
    // compile options
    compilation: {
    //...
    },
    // Dev Server options
    server: {
    hmr: true,
    //...
    },
    // plugin configuration
    plugins: [],
    });

    This document only covers details compilation options. For server or shared options, refer to server or shared

    -

    Compilation options - compilation

    +

    Compilation options - compilation

    All compilation-related configuration is under the compilation field.

    -

    input

    +

    input

    • type: Record<string, string>

    The entry point for the project. Input files can be html, ts/js/tsx/jsx, css or other files supported by plugins.

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    -

    output

    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    +

    output

    • type: OutputOptions
    -
    interface OutputOptions {
    // After partial bundling, the file name configuration of the resource where the entry file is located
    entryFilename?: string;
    // After partial bundling, other resources except the entry resource input file name configuration
    filename?: string;
    // output directory
    path?: string;
    // public path: resource loading prefix
    publicPath?: string;
    // Static resource file name configuration
    assetsFilename?: string;
    // Target execution environment, polyfill and syntax downgrade will be enabled if the target env is not `node-next` or `browser-esnext`
    targetEnv?: 'browser' | 'node' | 'node16' | 'node-legacy' | 'node-next' | 'browser-legacy' | 'browser-es2015' | 'browser-es2017' | 'browser-esnext';
    // output module format
    format?: "cjs" | "esm";
    }
    -
    note

    We call the compiled result a resource

    -

    output.entryFilename

    +
    interface OutputOptions {
    // After partial bundling, the file name configuration of the resource where the entry file is located
    entryFilename?: string;
    // After partial bundling, other resources except the entry resource input file name configuration
    filename?: string;
    // output directory
    path?: string;
    // public path: resource loading prefix
    publicPath?: string;
    // Static resource file name configuration
    assetsFilename?: string;
    // Target execution environment, polyfill and syntax downgrade will be enabled if the target env is not `node-next` or `browser-esnext`
    targetEnv?: 'browser' | 'node' | 'node16' | 'node-legacy' | 'node-next' | 'browser-legacy' | 'browser-es2015' | 'browser-es2017' | 'browser-esnext';
    // output module format
    format?: "cjs" | "esm";
    }
    +
    note

    We call the compiled result a resource

    +

    output.entryFilename

    • default: "[entryName].[ext]"
    @@ -42,7 +42,7 @@

    ou
  • [contentHash]: The content hash of the resource.
  • [ext]: The extension of the resource, js for js/jsx/ts/tsx, css for css/scss/less.
  • -

    output.filename

    +

    output.filename

    • Default value: "[resourceName].[ext]"
    @@ -52,26 +52,26 @@

    output.
  • [contentHash]: The content hash of the resource.
  • [ext]: The extension of the resource, js for js/jsx/ts/tsx, css for css/scss/less.
  • -

    output.path

    +

    output.path

    • default: "dist"

    directory of output resources

    -

    output.publicPath

    +

    output.publicPath

    • Default value: "/"

    The resource url load prefix. For example URL https://xxxx, or a absolute path /xxx/. For example config:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    output: {
    publicPath: process.env.NODE_ENV === 'production' ? 'https://cdn.com' : '/'
    }
    }
    // ...
    });
    +
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    output: {
    publicPath: process.env.NODE_ENV === 'production' ? 'https://cdn.com' : '/'
    }
    }
    // ...
    });

    When building for production, the injected resources url would be https://cdn.com/index-s2f3.s14dqwa.js. For example, in your output html, all <script> and <link> would be:

    -
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>
    +
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>

    and when loading dynamic scripts and css, the dynamic fetched resources url would also be: https://cdn.com/<asset-path>

    -

    output.assetsFileName

    +

    output.assetsFileName

    • Default value: "[resourceName].[ext]"

    The filename configuration for static resource output, the placeholder is the same as output.filename.

    -

    output.targetEnv

    +

    output.targetEnv

    • default: "browser-es2017"
    @@ -91,119 +91,119 @@

    output
  • node-next: Compile the project to latest Node Version, no polyfill will be injected.
  • node: Alias of node16
  • -

    output.format

    +

    output.format

    • default: "esm"

    The format of the configuration product, which can be "esm" or "cjs".

    -
    note

    This option is only valid for Js products

    -

    resolve

    +
    note

    This option is only valid for Js products

    +

    resolve

    • type: ResolveOptions
    -
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    -

    resolve.extensions

    +
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    +

    resolve.extensions

    • default: ["tsx", "ts", "jsx", "js", "mjs", "json", "html", "css"]

    Configure the suffix when parsing dependencies. For example, when parsing ./index, if it is not resolved, the suffix parsing will be automatically added, such as trying ./index.tsx, ./index.css, etc.

    -

    resolve.alias

    +

    resolve.alias

    • Default value: {}

    Configure parsing alias, example:

    -
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });
    +
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });

    alias is prefix replacement, for the above example /@/pages will be replaced by /root/src/pages.

    If you want an exact match, you can add $, for example stream$ will only replace stream, but not stream/xxx.

    If you want to use regex, you can use $__farm_regex:, for example $__farm_regex:^/(utils)$ will replace /utils to /root/src/utils.

    -

    resolve. mainFields

    +

    resolve. mainFields

    • default: ["exports", "browser", "module", "main"]

    When parsing dependencies under node_modules, the fields and order configured in mainFields will be parsed from package.json. For package.json

    -
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }
    +
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }

    Will use es/index.js first (if the path exists), and will continue to search backwards if it does not exist.

    -

    resolve.conditions

    +

    resolve.conditions

    Configuration is not currently supported.

    - +
    • default: true

    When parsing a file, whether to track the real directory corresponding to the symlink, and start parsing the next dependency from the real directory. If pnpm is used to manage dependencies, this option must be configured as true.

    -

    resolve. strictExports

    +

    resolve. strictExports

    • default: false

    Whether to strictly follow the exports defined in exports in package.json. If set to true, when exports is defined in package.json, but exports does not define the corresponding export, an error will be reported directly. If set to true, it will continue to try other entries according to mainFields.

    -

    define

    +

    define

    • Default value: {}

    Global variable injection, the configured variable name and value will be injected into the product at compile time. Farm injects process.env.NODE_ENV and some variables used by Farm itself such as FARM_HMR_PORT by default

    -
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123,
    },
    },
    });
    -

    external

    +
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123,
    },
    },
    });
    +

    external

    • default: []
    • type: (string | Record<string, string>)[]

    Configure the imports that are external, and the imports that are external will not appear in the compiled product. However, the corresponding import statement will not be deleted. You need to customize how to deal with external, otherwise an error will be reported at runtime. If targetEnv is an external module under node, it will automatically try to require the module.

    It needs to be configured in a regular way, for example:

    -
    export default defineConfig({
    compilation: {
    external: ["^stream$", { jquery: "Jquery" }],
    },
    });
    -

    externalNodeBuiltins

    +
    export default defineConfig({
    compilation: {
    external: ["^stream$", { jquery: "Jquery" }],
    },
    });
    +

    externalNodeBuiltins

    • default: true

    External module.builtinModules or not, by default, all builtin modules like fs will be external. You can also set externalNodeBuiltins as array to specify the modules to external manually:

    -
    export default defineConfig({
    compilation: {
    externalNodeBuiltins: ["^stream$"],
    },
    });
    -

    mode

    +
    export default defineConfig({
    compilation: {
    externalNodeBuiltins: ["^stream$"],
    },
    });
    +

    mode

    • default: development for start, watch commands, production for build commands

    Configure the compilation mode. In order to optimize the performance during development, if there is no manual configuration of production optimization related options (minify, tree shake, etc.), the production environment optimization such as compression and tree shake will be disabled by default under development. In production mode enabled.

    -

    runtime

    +

    runtime

    Configure Farm runtime capabilities. The types are as follows:

    -
    interface FarmRuntimeOptions {
    runtime?: {
    path: string;
    plugins?: string[];
    namespace?: string;
    isolate?: boolean;
    };
    }
    -

    runtime.path

    +
    interface FarmRuntimeOptions {
    runtime?: {
    path: string;
    plugins?: string[];
    namespace?: string;
    isolate?: boolean;
    };
    }
    +

    runtime.path

    • Default value: The path of Farm's built-in runtime

    Customize a Runtime to replace Farm's built-in Runtime.

    -
    warning

    It is not recommended to configure this option under normal circumstances, because once this option is configured, the pointed runtime needs all

    -

    runtime.plugins

    +
    warning

    It is not recommended to configure this option under normal circumstances, because once this option is configured, the pointed runtime needs all

    +

    runtime.plugins

    • Default value: The path of Farm's built-in runtime-plugin-hmr

    Configure the Runtime plug-in, through the Runtime plug-in, you can intervene in Runtime behavior, such as module loading, resource loading, etc. For details, please refer to: WIP.

    -

    runtime.namespace

    +

    runtime.namespace

    • default: name field of project package.json

    Configure the namespace of Farm Runtime to ensure that the execution of different products under the same window or global can be isolated from each other. By default, the name field of the project package.json is used as the namespace.

    -

    runtime.isolate

    +

    runtime.isolate

    • default: false

    By default, runtime files in html are written inline. If you want to reduce the size of the html file by popping it up as a separate file, then you can set this attribute to true. If set to true, the farm entry script will be emitted as a separate file.

    -

    assets

    -

    assets.include

    +

    assets

    +

    assets.include

    • default: []

    Additional file suffixes that are regarded as static resources, such as the following example, txt will be regarded as posture resources, and will be treated as static resources when importing txt files:

    -
    export default defineConfig({
    compilation: {
    assets: {
    include: ["txt"],
    },
    },
    });
    -

    script

    -

    script.target

    +
    export default defineConfig({
    compilation: {
    assets: {
    include: ["txt"],
    },
    },
    });
    +

    script

    +

    script.target

    • Default value: esnext (dynamically adjusted according to the iteration of Farm)

    Configure Farm to parse the AST of js/jsx/ts/tsx and support the ES syntax version when generating code. Possible values: es5, es6, es2015 - es2023, esnext

    -

    script.parser

    +

    script.parser

    • default: same as SWC

    Configure the behavior of SWC when parsing AST, configuration item reference: https://swc.rs/docs/configuration/compilation#jscparser

    -

    script.plugins

    +

    script.plugins

    • default: []
    @@ -214,9 +214,9 @@

    script.p
  • filters: Which modules to execute the plug-in, must be configured, support resolvedPaths and moduleTypes these two filter items, if both are specified at the same time, take the union.
  • An example of a configuration that supports JSX for a Vue project is as follows:

    -
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };
    -

    script.decorators

    -
    export interface DecoratorsConfig {
    legacyDecorator: boolean;
    decoratorMetadata: boolean;
    /**
    * The version of the decorator proposal to use. 2021-12 or 2022-03
    * @default 2021-12
    */
    decoratorVersion: "2021-12" | "2022-03" | null;
    /**
    * @default []
    */
    includes: string[];
    /**
    * @default ["node_modules/"]
    */
    excludes: string[];
    }
    +
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };
    +

    script.decorators

    +
    export interface DecoratorsConfig {
    legacyDecorator: boolean;
    decoratorMetadata: boolean;
    /**
    * The version of the decorator proposal to use. 2021-12 or 2022-03
    * @default 2021-12
    */
    decoratorVersion: "2021-12" | "2022-03" | null;
    /**
    * @default []
    */
    includes: string[];
    /**
    * @default ["node_modules/"]
    */
    excludes: string[];
    }

    It's recommended to use default decorators configuration of Farm, unless you want to improve performance, you can set includes and excludes.

    Options:

      @@ -226,36 +226,36 @@

      scrip
    • includes: default to []. If you want to include modules that are excluded, you can set this option. Regex supported.
    • excludes: default to ['node_modules/']. Modules under these paths are ignored when transform decorators. Regex supported
    -

    css

    -

    css.modules

    +

    css

    +

    css.modules

    Configure Farm CSS Modules.

    -
    interface FarmCssModulesConfig {
    // Configure which paths will be processed as css modules, using regular strings
    // defaults to `.module.css` or `.module.scss` or `.module.less`
    paths?: string[];
    // configure the generated css class name, the default is `[name]-[hash]`
    indentName?: string;
    }
    -
    css.modules.paths
    +
    interface FarmCssModulesConfig {
    // Configure which paths will be processed as css modules, using regular strings
    // defaults to `.module.css` or `.module.scss` or `.module.less`
    paths?: string[];
    // configure the generated css class name, the default is `[name]-[hash]`
    indentName?: string;
    }
    +
    css.modules.paths
    • default: ["\\.module\\.(css|scss|sass|less)"]

    Configure which paths correspond to modules that will be treated as CSS Modules. A regular string needs to be configured. Defaults to files ending in .module.(css|scss|sass|less).

    -
    css.modules.identName
    +
    css.modules.identName
    • default: [name]-[hash]

    Configure the generated CSS Modules class name, the default is [name]-[hash], [name], [hash] are placeholders (also all currently supported placeholders). [name] means the original class name, [hash] means the hash of the modified css file id.

    -

    css.prefixer

    +

    css.prefixer

    Configure CSS compatibility prefixes, such as -webkit-.

    -
    interface FarmCssPrefixer {
    targets?: string[] | string | BrowserTargetsRecord;
    }

    type BrowserTargetsRecord = Partial<
    Record<
    | "chrome"
    | "opera"
    | "edge"
    | "firefox"
    | "safari"
    | "ie"
    | "ios"
    | "android"
    | "node"
    | "electron",
    string
    >
    > & { [key: string]: string };
    -
    css.prefixer.targets
    +
    interface FarmCssPrefixer {
    targets?: string[] | string | BrowserTargetsRecord;
    }

    type BrowserTargetsRecord = Partial<
    Record<
    | "chrome"
    | "opera"
    | "edge"
    | "firefox"
    | "safari"
    | "ie"
    | "ios"
    | "android"
    | "node"
    | "electron",
    string
    >
    > & { [key: string]: string };
    +
    css.prefixer.targets
    • Default value: undefined

    Configure which target browsers or browser versions to enable, for example:

    -
    import { defineConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
    },
    },
    },
    });
    -

    html

    -

    html.base

    +
    import { defineConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
    },
    },
    },
    });
    +

    html

    +

    html.base

    • Default value: undefined

    All HTML entries will inherit html.base, for details, refer to Guide - HTML

    -

    sourcemap

    +

    sourcemap

    • default: true
    @@ -267,25 +267,25 @@

    sourcemapall: generate sourcemap for all files, and generate a separate sourcemap file
  • all-inline: Generate sourcemaps for all files, and inline sourcemaps into the product, do not generate separate files
  • -

    partialBundling

    +

    partialBundling

    Configure the behavior of Farm's partial bundling. For details, please refer to Partial Bundling

    -
    export interface FarmPartialBundlingConfig {
    targetConcurrentRequests?: number;
    targetMinSize?: number;
    targetMaxSize?: number;
    groups?: {
    name: string;
    test: string[];
    groupType?: "mutable" | "immutable";
    resourceType?: "all" | "initial" | "async";
    }[];
    enforceResources?: {
    name: string;
    test: string[];
    }[];
    enforceTargetConcurrentRequests?: boolean;
    enforceTargetMinSize?: boolean;
    immutableModules?: string[];
    }
    -

    partialBundling.targetConcurrentRequests

    +
    export interface FarmPartialBundlingConfig {
    targetConcurrentRequests?: number;
    targetMinSize?: number;
    targetMaxSize?: number;
    groups?: {
    name: string;
    test: string[];
    groupType?: "mutable" | "immutable";
    resourceType?: "all" | "initial" | "async";
    }[];
    enforceResources?: {
    name: string;
    test: string[];
    }[];
    enforceTargetConcurrentRequests?: boolean;
    enforceTargetMinSize?: boolean;
    immutableModules?: string[];
    }
    +

    partialBundling.targetConcurrentRequests

    • default: 25

    Farm tries to generate resource numbers as closer as possible to this config value for initial resource loading or a dynamic resource loading.

    -

    partialBundling.targetMinSize

    +

    partialBundling.targetMinSize

    • default: 20 * 1024 bytes, 20 KB

    The minimum size of each generated resources before minify and gzip. Note that targetMinSize will not be satisfied if ModuleBucket's size is less than targetMinSize, ModuleBucket will be given priority. Config enforceTargetMinSize can be used to enforce size.

    -

    partialBundling.targetMaxSize

    +

    partialBundling.targetMaxSize

    • default: 1500 * 1024 bytes, 1500 KB

    The maximum size of generated resources before minify and gzip.

    -

    partialBundling.groups

    +

    partialBundling.groups

    • default: []
    @@ -297,8 +297,8 @@

  • groupType: mutable or immutable, this group only applies to the specified type of modules.
  • resourceType: all, initial or async, this group only applies to the specified type of resources.
  • -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    groups: [
    {
    name: "vendor-react",
    test: ["node_modules/"],
    },
    ],
    },
    },
    });
    -

    partialBundling.enforceResources

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    groups: [
    {
    name: "vendor-react",
    test: ["node_modules/"],
    },
    ],
    },
    },
    });
    +

    partialBundling.enforceResources

    • default: []
    @@ -308,123 +308,123 @@

    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: "index",
    test: [".+"],
    },
    ],
    },
    },
    });

    -
    warning

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    -

    partialBundling.enforceTargetConcurrentRequests

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: "index",
    test: [".+"],
    },
    ],
    },
    },
    });
    +
    warning

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    +

    partialBundling.enforceTargetConcurrentRequests

    • default: false

    Enforce target concurrent requests for every resource loading, when true, smaller resource will be merged into bigger resource to meet the target concurrent requests. this may cause issue for css resource, be careful to use this option.

    -

    partialBundling.enforceTargetMinSize

    +

    partialBundling.enforceTargetMinSize

    • default: false

    Enforce target min size for every resource, when tue, smaller resource will be merged into bigger resource to meet the target concurrent requests. this may cause issue for css resource, be careful to use this option

    -

    partialBundling.immutableModules

    +

    partialBundling.immutableModules

    • default: ['node_modules']

    Regex array to match the immutable modules.

    -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });
    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });

    Immutable module can affect bundling and incoming persistent cache, be careful if you want to change it.

    -

    partialBundling.immutableModulesWeight

    +

    partialBundling.immutableModulesWeight

    • default: 0.8

    Default to 0.8, means the output bundles of immutable module takes 80%. for example, if targetConcurrentRequest is 25,then immutable bundles files numbers are 25 * 80% = 20. This option is used isolate your mutable and immutable module, if you modified your business code, bundles generating from node_modules won't be affected.

    -

    lazyCompilation

    +

    lazyCompilation

    • default: true in development mode, false in build mode

    Whether to enable lazy compilation, configure to false to close. See lazy compilation.

    -

    treeShaking

    +

    treeShaking

    • default: false in development mode, true in build mode

    Whether to enable tree shake, set to false to close. See Tree Shake.

    -

    minify

    +

    minify

    • default: false in development mode, true in build mode

    Whether to enable compression, the product will be compressed and confused after it is turned on. See Minification.

    -
    type MinifyOptions = boolean | {
    compress?: ToSnakeCaseProperties<TerserCompressOptions> | boolean;
    mangle?: ToSnakeCaseProperties<TerserMangleOptions> | boolean;
    };
    +
    type MinifyOptions = boolean | {
    compress?: ToSnakeCaseProperties<TerserCompressOptions> | boolean;
    mangle?: ToSnakeCaseProperties<TerserMangleOptions> | boolean;
    };

    The compress and mangle options is the same as swc's minify config.

    -

    minify.compress

    +

    minify.compress

    compress option

    -

    minify.mangle

    +

    minify.mangle

    compress variable parameters

    -

    minify.include

    +

    minify.include

    • default: []
    • type: string[]

    contains modules that need to be compressed, defaults to all, only takes effect when minify.mode is minify-module.

    -

    minify.exclude

    +

    minify.exclude

    • default: ["*.min.js"]
    • type: string[]

    exclude unnecessary compression modules, only takes effect when minify.mode is minify-module.

    -

    minify.mode

    +

    minify.mode

    • default: 'minify-module'
    • type: 'minify-module' | 'minify-resource-pot'

    minify-module module level minify, you can control which modules need to be minified through parameters, the compression is more refined and the efficiency is better

    minify-resource-pot ResourcePot level minify, specific modules cannot be controlled through parameters

    -

    presetEnv

    +

    presetEnv

    • default: false in development mode, true in build mode
    -
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };
    +
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };

    By default, polyfills will not be injected into modules under node_modules, if necessary, please use include to add polyfills.

    -

    presetEnv.include

    +

    presetEnv.include

    • default: []

    Include additional modules that require polyfill, configure regular strings, for example include: ['node_modules/(es6-package|my-package)/']

    -

    presetEnv. exclude

    +

    presetEnv. exclude

    • default: ['node_modules/']

    Configure modules that do not require polyfill, and configure regular strings, such as exclude: ['custom-path/(es5-package|my-package)/']. By default node_modules is excluded, if you need to include excluded modules, it is recommended to use include

    -

    presetEnv.options

    +

    presetEnv.options

    • default: downgrade to ES5

    Options passed to swc preset env, see https://swc.rs/docs/configuration/compilation#env.

    -

    persistentCache

    +

    persistentCache

    • default: true

    Options for Persistent Cache. Configuring it false to disable cache.

    -
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    -

    persistentCache.namespace

    +
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    +

    persistentCache.namespace

    • default: farm-cache

    Namespace for the cache, caches under different namespace will be isolated.

    -

    persistentCache.cacheDir

    +

    persistentCache.cacheDir

    • default: node_modules/.farm/cache

    Cache store directory.

    -

    persistentCache.buildDependencies

    +

    persistentCache.buildDependencies

    • default: farm.config.ts and all its deep dependencies

    File path or package name that may affect the compilation, for example, plugins. By default, farm.config.ts/js/mjs and all of its deep dependencies will be treated as build dependencies, if any of these files changed, all cache will be invalidated.

    it can be a file path or a package name, for example:

    -
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    -

    persistentCache.moduleCacheKeyStrategy

    +
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    +

    persistentCache.moduleCacheKeyStrategy

    • default: { timestamp: true, hash: true }
    @@ -433,17 +433,17 @@

    persistentCache.envs

    +

    persistentCache.envs

    Envs used to invalidate cache, if the configured env changed, then all cache will be invalidated.

    -

    progress

    +

    progress

    • default: true

    Enable progress bar or not.

    -

    comments

    +

    comments

    • default: license
    @@ -452,6 +452,6 @@

    comments

    +
    \ No newline at end of file diff --git a/docs/config/configuring-farm/index.html b/docs/config/configuring-farm/index.html index 72b66ec3a..0e561d3be 100644 --- a/docs/config/configuring-farm/index.html +++ b/docs/config/configuring-farm/index.html @@ -8,33 +8,33 @@ - - - + + + -
    Version: 1.0.0

    Configuring Farm

    -

    Config File Spec

    +
    Version: 1.0.0

    Configuring Farm

    +

    Config File Spec

    By default, Farm reads the configuration from the farm.config.ts|js|mjs file in the project root directory, an example configuration file:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // compiled root directory
    // compile options
    compilation: {
    //...
    },
    // Dev Server options
    server: {
    hmr: true,
    //...
    },
    // plugin configuration
    plugins: [],
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // compiled root directory
    // compile options
    compilation: {
    //...
    },
    // Dev Server options
    server: {
    hmr: true,
    //...
    },
    // plugin configuration
    plugins: [],
    });

    For config options details, refer to:

    • Compiler Options: Configuring compiler options(compilation field), like input, output, css compilation, bundling rules and so on.
    • Dev Server Options: Configuring dev server options(server field), like port, host, protocol and so on.
    • Shared Options: Configuring shared options between compiler options and dev server options, like root, env and so on.
    -
    note

    You can also use farm start/build -c my-config.ts to use a custom file as config file.

    -

    Loading Ts Config File

    +
    note

    You can also use farm start/build -c my-config.ts to use a custom file as config file.

    +

    Loading Ts Config File

    Farm support load ts config file like farm.config.ts out of box. Farm will bundle farm.config.ts and it's local ts dependencies into farm-config.xxx.mjs file first and load it from disk. Because Farm compiles the farm.config.ts into mjs file, you CAN NOT use __dirname or __filename in your farm.config.ts, use import.meta.url instead.

    Or you can use farm.config.mjs or farm.config.cjs with @type to support types avoid bundling farm.config.ts:

    -
    farm.config.mjs
    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    // ...
    }
    -

    Examples

    -

    Input and Output

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    input: {
    index: './src/index.html',
    about: './src/about.html',
    },
    output: {
    path: 'build',
    publicPath: process.env.NODE_ENV === 'production' ? 'https://my-cdn.com' : '/'
    }
    },
    });
    +
    farm.config.mjs
    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    // ...
    }
    +

    Examples

    +

    Input and Output

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    input: {
    index: './src/index.html',
    about: './src/about.html',
    },
    output: {
    path: 'build',
    publicPath: process.env.NODE_ENV === 'production' ? 'https://my-cdn.com' : '/'
    }
    },
    });

    In above example, we configured ./src/index.html and ./src/about.html as input, then output the compiled resources to build dir.

    -

    Dev Server Port

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    port: 9801
    }
    });
    -

    Disable Default Optimizations

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    lazyCompilation: false,
    persistentCache: false,
    minify: false,
    treeShake: false
    },
    });
    +

    Dev Server Port

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    port: 9801
    }
    });
    +

    Disable Default Optimizations

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    lazyCompilation: false,
    persistentCache: false,
    minify: false,
    treeShake: false
    },
    });
    \ No newline at end of file diff --git a/docs/config/dev-server/index.html b/docs/config/dev-server/index.html index f44c2a4ce..e90d12905 100644 --- a/docs/config/dev-server/index.html +++ b/docs/config/dev-server/index.html @@ -8,92 +8,92 @@ - - - + + + -
    Version: 1.0.0

    Dev Server Options

    -

    DevServer Options - server

    +
    Version: 1.0.0

    Dev Server Options

    +

    DevServer Options - server

    Configure the behavior of Farm Dev Server. Example:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    server: {
    port: 9000,
    //...
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    server: {
    port: 9000,
    //...
    },
    });

    type:

    -
    export interface UserServerConfig {
    headers?: OutgoingHttpHeaders | undefined;
    port?: number;
    https?: SecureServerOptions;
    protocol?: 'http' | 'https';
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string | boolean;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    middlewares?: DevServerMiddleware[];
    writeToDisk?: boolean;
    }
    -

    port

    +
    export interface UserServerConfig {
    headers?: OutgoingHttpHeaders | undefined;
    port?: number;
    https?: SecureServerOptions;
    protocol?: 'http' | 'https';
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string | boolean;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    middlewares?: DevServerMiddleware[];
    writeToDisk?: boolean;
    }
    +

    port

    • default: 9000

    The port the DevServer listens on.

    -

    https

    +

    https

    • default: undefined

    Enable TLS + HTTP2. The value is options that passes to http2.createSecureServer.

    -
    note

    Note that a valid certificate is needed if https enabled.

    -

    headers

    +
    note

    Note that a valid certificate is needed if https enabled.

    +

    headers

    • default: undefined

    Setup global http response headers for the DevServer.

    -
    import { defineConfig } from '@farmfe/core'

    export default defineConfig({
    server: {
    headers: {
    'Accept': 'xxxx'
    }
    }
    })
    -

    strictPort

    +
    import { defineConfig } from '@farmfe/core'

    export default defineConfig({
    server: {
    headers: {
    'Accept': 'xxxx'
    }
    }
    })
    +

    strictPort

    • default: false

    By default, Farm will automatically resolve to a new port when given port is used. For example, if 9001 is used, then 9001 will be tried. But if strictPort is true, a error will be thrown when port conflicts, instead of try other ports automatically.

    -

    cors

    +

    cors

    • default: false

    Configure @koa/cors options.

    -

    spa

    +

    spa

    • default: true

    Enable fallback to index.html or not.

    -

    hmr

    +

    hmr

    • default: true for start command, false for other commands

    Enable HMR. After enabling the HMR capability, it will monitor the changes of the modules involved in the compilation process. When the modules change, it will automatically trigger recompilation and push the results to Farm Runtime for update. HMR can also be configured through an object, for example:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // All dev server options are under server
    server: {
    hmr: {
    // Configure the port for web socket listening
    port: 9802
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    -

    hmr.port

    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // All dev server options are under server
    server: {
    hmr: {
    // Configure the port for web socket listening
    port: 9802
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    +

    hmr.port

    • default: 9801

    The port the Web Socket server listens on

    -

    hmr.host

    +

    hmr.host

    • default: localhost

    Host on which the Web Socket server listens.

    -

    proxy

    +

    proxy

    • Default value: undefined

    Configure server proxy. farm uses http-proxy as a proxy for the development server. Based on http-proxy implementation, specific options refer to its documentation, example:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    -

    open

    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    +

    open

    • default: false

    After the compilation is completed, the browser is automatically opened to the corresponding page.

    -

    host

    +

    host

    • default: localhost

    The host that the Dev Server listens on.

    -

    middlewares

    +

    middlewares

    • default: []

    Configuring middlewares for the dev server.

    -
    import { defineConfig } from "@farmfe/core";
    import compression from 'koa-compress';

    export default defineConfig({
    server: {
    middlewares: [
    compression
    ]
    },
    });
    +
    import { defineConfig } from "@farmfe/core";
    import compression from 'koa-compress';

    export default defineConfig({
    server: {
    middlewares: [
    compression
    ]
    },
    });

    Note that a middleware is a function that returns a koa middleware.

    -

    writeToDisk

    +

    writeToDisk

    • default: false
    -

    By default the compiled resources are stored and served in memory, set writeToDisk to true to emitted dev resources to the disk.

    +

    By default the compiled resources are stored and served in memory, set writeToDisk to true to emitted dev resources to the disk.

    \ No newline at end of file diff --git a/docs/config/shared/index.html b/docs/config/shared/index.html index 3ca9db544..98b4f5011 100644 --- a/docs/config/shared/index.html +++ b/docs/config/shared/index.html @@ -8,53 +8,53 @@ - - - + + + -
    Version: 1.0.0

    Shared Options

    +
    Version: 1.0.0

    Shared Options

    Configure shared options for Both Farm's DevServer and Compiler. Example:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    root: process.cwd(),
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    root: process.cwd(),
    });

    Type:

    -
    export interface UserConfig {
    /** current root of this project, default to current working directory */
    root?: string;
    clearScreen?: boolean;
    envDir?: string;
    envPrefix?: string | string[];
    /** Files under this dir will always be treated as static assets. serve it in dev, and copy it to output.path when build */
    publicDir?: string;
    /** js plugin(which is a javascript object) and rust plugin(which is string refer to a .farm file or a package) */
    plugins?: (RustPlugin | JsPlugin | JsPlugin[])[];
    /** vite plugins */
    vitePlugins?: (object | (() => { vitePlugin: any; filters: string[] }))[];
    // /** config related to compilation */
    // compilation?: Pick<InternalConfig, AvailableUserConfigKeys>;
    // /** config related to dev server */
    // server?: UserServerConfig;
    }
    -

    root

    +
    export interface UserConfig {
    /** current root of this project, default to current working directory */
    root?: string;
    clearScreen?: boolean;
    envDir?: string;
    envPrefix?: string | string[];
    /** Files under this dir will always be treated as static assets. serve it in dev, and copy it to output.path when build */
    publicDir?: string;
    /** js plugin(which is a javascript object) and rust plugin(which is string refer to a .farm file or a package) */
    plugins?: (RustPlugin | JsPlugin | JsPlugin[])[];
    /** vite plugins */
    vitePlugins?: (object | (() => { vitePlugin: any; filters: string[] }))[];
    // /** config related to compilation */
    // compilation?: Pick<InternalConfig, AvailableUserConfigKeys>;
    // /** config related to dev server */
    // server?: UserServerConfig;
    }
    +

    root

    • default: process.cwd()

    Configure the root directory for project compilation. All relative paths are relative to root during compilation.

    -

    clearScreen

    +

    clearScreen

    • default: true

    Whether to clear the screen when start to compile the project.

    -

    envDir

    +

    envDir

    • default: <root>

    Configuring the directory to load .env, .env.development, .env.production files. By default it's the same as root.

    -
    import { defineConfig } from '@farmfe/core';
    import { resolve } from 'path';
    export default defineConfig({
    envPrefix: ['FARM_', 'CUSTOM_PREFIX_', 'NEW_'],
    envDir: resolve(process.cwd(), './env'),
    });
    +
    import { defineConfig } from '@farmfe/core';
    import { resolve } from 'path';
    export default defineConfig({
    envPrefix: ['FARM_', 'CUSTOM_PREFIX_', 'NEW_'],
    envDir: resolve(process.cwd(), './env'),
    });

    In above example, will load .env, .env.development, .env.production files from <root>/env directory.

    -

    envPrefix

    +

    envPrefix

    • default: ['FARM_', 'VITE_']

    Env variables starts with envPrefix will be injected define automatically.

    -

    publicDir

    +

    publicDir

    • default: public

    Files under publicDir will always be treated as static assets. serve it in dev, and copy it to output.path when build.

    For example, you can add static assets like font to public dir and using them as /xxx.ttf.

    -

    plugins

    +

    plugins

    • default: []

    Configure Farm Plugins. See Using Farm Plugins

    -

    vitePlugins

    +

    vitePlugins

    • default: []
    -

    Configure Vite/Rollup/Unplugin plugins. See Using Vite Plugins

    +

    Configure Vite/Rollup/Unplugin plugins. See Using Vite Plugins

    \ No newline at end of file diff --git a/docs/contribution/index.html b/docs/contribution/index.html index a45666050..e0c7da390 100644 --- a/docs/contribution/index.html +++ b/docs/contribution/index.html @@ -8,22 +8,22 @@ - - - + + + -
    Version: 1.0.0

    Contribution Guide

    +
    Version: 1.0.0

    Contribution Guide

    Thank you for your interest in contributing to Farm!. Before submitting your contribution, please make sure to take a moment and read through the following guidelines.

    -

    Code of Conduct

    +

    Code of Conduct

    All contributors are expected to follow our Code of Conduct.

    -

    Bug reports

    +

    Bug reports

    As farm is currently in the process of rapid development iteration, some unexpected problems may be encountered in the process of development.

    We can't fix what we don't know about, so please report problems and unexpected behavior.

    You can open a new issue by following new-issues and choosing one of the issue templates.

    -

    Feature requests

    +

    Feature requests

    Please feel free to open an issue using the feature request template.

    -

    Pull Request Guidelines

    +

    Pull Request Guidelines

    • Please adhere to the code style that you see around the location you are working on.

      @@ -44,7 +44,7 @@

      Pull

      When you are done with your work, verify that it works locally with pnpm run ready

    -

    Setup

    +

    Setup

    -

    Development Environment Setup

    -

    Dependencies

    +
      git remote add upstream https://github.com/farm-fe/farm.git
    git fetch upstream
    git branch --set-upstream-to=upstream/main main
    +

    Development Environment Setup

    +

    Dependencies

    • Install Rust using rustup.

      @@ -70,21 +70,21 @@

      DependenciesPnpm version 8+

    -

    IDE

    +

    IDE

    We recommend that you use vscode for development and recommend two necessary plugins that you need to install

    • rust-analyzer support rust language
    • biome farm use biome to detect and format the code

    You can install them in the extension

    -

    Setup Other Dependencies

    +

    Setup Other Dependencies

    • Install protoc for building sass-embedded.

    TIP: When you run pnpm bootstrap and you use mac or linux systems, farm will automatically install protoc for you system

    -

    Start running

    +

    Start running

    Farm development is very simple. You only need to execute pnpm bootstrap in the root directory for development.

    -
    npm
    yarn
    pnpm
    bun
    npm bootstrap
    +
    npm
    yarn
    pnpm
    bun
    npm bootstrap
    • use pnpm bootstrap to install dependencies and build core packages with series of initialization operations.

      @@ -100,26 +100,26 @@

      Start running<

    When you are developing node side code, the root directory executes pnpm start to debug the code in real time, and when you are developing rust side code, the root directory executes pnpm start:rs to debug the code in real time.

    -
    npm
    yarn
    pnpm
    bun
    npm start   // node side
    -
    npm
    yarn
    pnpm
    bun
    npm start:rs   // rust side
    -

    Testing

    +
    npm
    yarn
    pnpm
    bun
    npm start   // node side
    +
    npm
    yarn
    pnpm
    bun
    npm start:rs   // rust side
    +

    Testing

    We also need to test two parts, a set of Rust tests and a set of Node tests. Make sure all the tests pass before you submit the code.

    -

    Rust Testing

    +

    Rust Testing

    • Input cargo test in the root directory will run all the test cases.
    -
    # root path or crates path
    cargo test
    -

    Node Testing

    +
    # root path or crates path
    cargo test
    +

    Node Testing

    • Input pnpm test in the root directory to run all test cases based on vitest.
    -
    # root path
    pnpm test
    -

    Quickly create plugins through scaffold

    +
    # root path
    pnpm test
    +

    Quickly create plugins through scaffold

    If you want to develop a plugin for farm, farm provides a scaffolding to help you quickly create a plugin, which you can create with the following command. You can go to the cd packages/ cli directory, run npm link or global installation @ farmfe/ cli to use this CLI, after the installation is complete, You can create a plugin through farm plugin create. Farm supports the creation of rust and js plugins.

    -
    $ farm plugin create <plugin-name> # create a plugin support js or rust
    -

    Pull Request Preface Tip

    +
    $ farm plugin create <plugin-name> # create a plugin support js or rust
    +

    Pull Request Preface Tip

    Farm is divided into two parts: the JavaScript side and the Rust side:

    • @@ -130,6 +130,6 @@

      Pul

      the Rust side: see code in the crates and rust-plugins directory. contains core (compilation context, plugin drivers, etc.), compiler (compile process, HMR update, etc.), and plugins.

    • -
    +
    \ No newline at end of file diff --git a/docs/features/css/index.html b/docs/features/css/index.html index 3e20df5d2..1f62a938b 100644 --- a/docs/features/css/index.html +++ b/docs/features/css/index.html @@ -8,76 +8,76 @@ - - - + + + -
    Version: 1.0.0

    Css/Sass/Less

    +
    Version: 1.0.0

    Css/Sass/Less

    Farm support Css out of box, just import the css file:

    -
    import './index.css';
    +
    import './index.css';

    Then farm will auto enable HMR for css module, and generating bundled resources for css.

    -

    Css Modules

    +

    Css Modules

    Farm support css modules out of box, the modules end with .module.css|less|scss|sass will be treated as css modules by default.

    -
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    -
    index.module.css
    .main {
    color: green;
    }
    +
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    +
    index.module.css
    .main {
    color: green;
    }

    You can configuring css modules by css.modules. for example you can set css.modules.paths to ['.css|sass|less|scss'] then all css files will be treated as css modules.

    -

    Css Pre-Processor

    +

    Css Pre-Processor

    Farm provide official sass, less, postcss plugins to support css pre-processor.

    -

    Sass

    +

    Sass

    Farm sass plugin is a Rust Plugin and use sass-embeded(we may migrate to grass in the future).

    Steps to compile sass/scss modules in Farm.

    1. Install dependencies
    -
    # npm or yarn or pnpm, choose your favorite package manager
    pnpm add -D @farmfe/plugin-sass
    +
    # npm or yarn or pnpm, choose your favorite package manager
    pnpm add -D @farmfe/plugin-sass
    1. Configure the plugin
    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // ...
    plugins: ['@farmfe/plugin-sass'] // to use a rust plugin, just configure its package name as a string
    // if you want to specify options for plugin-sass, use
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // ...
    plugins: ['@farmfe/plugin-sass'] // to use a rust plugin, just configure its package name as a string
    // if you want to specify options for plugin-sass, use
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    });
    1. Import sass module
    -
    import './index.scss';
    +
    import './index.scss';

    To use sass with css modules, change the file name from index.scss to index.module.scss, see css modules.

    @farmfe/plugin-sass supports a lot of options, use the array syntax of plugins to specify options for plugin sass:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // if you want to specify options for plugin-sass, use
    plugins: [
    [
    '@farmfe/plugin-sass',
    // all supported options as below
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    });
    -

    Less

    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // if you want to specify options for plugin-sass, use
    plugins: [
    [
    '@farmfe/plugin-sass',
    // all supported options as below
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    });
    +

    Less

    Farm less plugin is a Js Plugin. Steps to compile less modules in Farm.

    1. Install dependencies
    -
    # npm or yarn or pnpm, choose your favorite package manager
    pnpm add -D @farmfe/js-plugin-less
    +
    # npm or yarn or pnpm, choose your favorite package manager
    pnpm add -D @farmfe/js-plugin-less
    1. Configure the plugin
    -
    import { defineConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default defineConfig({
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    });
    +
    import { defineConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default defineConfig({
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    });
    1. Import sass module
    -
    import './index.less';
    +
    import './index.less';

    To use sass with css modules, change the file name from index.less to index.module.less, see css modules

    -

    Postcss

    +

    Postcss

    The Farm postcss plugin is a JS plugin. The steps to introduce postcss in Farm are as follows:

    1. Install dependencies
    -
    # npm or yarn or pnpm, choose your favorite package manager
    pnpm add -D @farmfe/js-plugin-postcss
    +
    # npm or yarn or pnpm, choose your favorite package manager
    pnpm add -D @farmfe/js-plugin-postcss
    1. Configure the plugin
    -
    import { defineConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    //...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    });
    +
    import { defineConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    //...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    });
    1. Configure postcss.config.js and import the required postcss plugins
    -
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    -

    Css Prefixer

    +
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    +

    Css Prefixer

    Farm supports css prefixer out of box, you can configure it using compilation.css.prefixer.

    -
    note

    css.prefix.targets will be set automatically when output.targetEnv. Normally set output.targetEnv would be enough.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });
    +
    note

    css.prefix.targets will be set automatically when output.targetEnv. Normally set output.targetEnv would be enough.

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });

    Then for input code:

    -
    div {
    display: flex;
    }
    +
    div {
    display: flex;
    }

    output code:

    -
    div{display:-ms-flexbox;display:flex}
    +
    div{display:-ms-flexbox;display:flex}
    \ No newline at end of file diff --git a/docs/features/dev-server/index.html b/docs/features/dev-server/index.html index 0fb7d1bc7..bfcfbaf6c 100644 --- a/docs/features/dev-server/index.html +++ b/docs/features/dev-server/index.html @@ -8,32 +8,32 @@ - - - + + + -
    Version: 1.0.0

    DevServer and HMR

    +
    Version: 1.0.0

    DevServer and HMR

    Farm provides DevServer and enabled HMR in development by default.

    -

    Configuring Dev Server

    +

    Configuring Dev Server

    Farm provides a lot of useful options to configure dev server. All dev server options are configured by server.

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    server: {
    port: 9801,
    cors: true,
    proxy: {
    // ...
    },
    open: true,
    }
    })
    -
    note

    If you are built tools on top of farm, refer to Javascript API for creating a Dev Server programmatically.

    -

    Dev Server Middlewares

    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    server: {
    port: 9801,
    cors: true,
    proxy: {
    // ...
    },
    open: true,
    }
    })
    +
    note

    If you are built tools on top of farm, refer to Javascript API for creating a Dev Server programmatically.

    +

    Dev Server Middlewares

    You can use middlewares to handle dev server requests. For example:

    -
    farm.config.ts
    import { Middleware } from 'koa';
    import { Server, defineConfig } from '@farmfe/core';

    export function headers(devSeverContext: Server): Middleware {
    const { config } = devSeverContext;
    if (!config.headers) return;

    return async (ctx, next) => {
    if (config.headers) {
    for (const name in config.headers) {
    ctx.set(name, config.headers[name] as string | string[]);
    }
    }
    await next();
    };
    }

    export default defineConfig({
    server: {
    middlewares: [
    headers
    ]
    }
    })
    +
    farm.config.ts
    import { Middleware } from 'koa';
    import { Server, defineConfig } from '@farmfe/core';

    export function headers(devSeverContext: Server): Middleware {
    const { config } = devSeverContext;
    if (!config.headers) return;

    return async (ctx, next) => {
    if (config.headers) {
    for (const name in config.headers) {
    ctx.set(name, config.headers[name] as string | string[]);
    }
    }
    await next();
    };
    }

    export default defineConfig({
    server: {
    middlewares: [
    headers
    ]
    }
    })

    In above example, a Farm middleware is a function that expose Koa Middleware. Common Koa middlewares can be used directly, for example:

    -
    import { defineConfig } from "@farmfe/core";
    import compression from 'koa-compress';

    export default defineConfig({
    server: {
    middlewares: [
    compression
    ]
    },
    });
    -

    Hot Module Replacement(HMR)

    +
    import { defineConfig } from "@farmfe/core";
    import compression from 'koa-compress';

    export default defineConfig({
    server: {
    middlewares: [
    compression
    ]
    },
    });
    +

    Hot Module Replacement(HMR)

    Farm provides a Vite-compatible HMR API. If you are framework authors, leverage the API to update your Application instance, precise without reloading the page.

    • For React, React Refresh are enabled automatically by official plugins @farmfe/plugin-react.
    • For Vue, Solid and other frameworks, it's HMR are supported by there plugins like @vitejs/plugin-vue, vite-plugin-solid and so on.

    Farm provides official templates that set all these capabilities up already, create an app via create-farm then all HMR abilities are ready.

    -
    note
      +
      note
    +
    \ No newline at end of file diff --git a/docs/features/env/index.html b/docs/features/env/index.html index f909c5864..687bebe0f 100644 --- a/docs/features/env/index.html +++ b/docs/features/env/index.html @@ -8,39 +8,39 @@ - - - + + + -
    Version: 1.0.0

    Environment Variables and Modes

    +
    Version: 1.0.0

    Environment Variables and Modes

    Farm distinguishes between development and production environments through process.env.NODE_ENV.

    In different environments, environment variables are replaced statically, so use static constants to represent environment variables instead of dynamic expressions.

    -

    .env file

    +

    .env file

    Farm uses dotenv to load your additional environment variables, such as .env files. By default .env file are loaded from root, you can use envDir to customize.

    -
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0
    +
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0

    Farm loads the file .env via dotenv, and loads it into process.env and finally injects it into define.

    -
    danger

    In order to ensure the security of the client, preventing the environment variables in the current system from being exposed to the client Farm will only identify some important environment variables that start with FARM_VITE_ (In order to better compatible with vite and its ecological environment).

    +
    danger

    In order to ensure the security of the client, preventing the environment variables in the current system from being exposed to the client Farm will only identify some important environment variables that start with FARM_VITE_ (In order to better compatible with vite and its ecological environment).

    Farm expands environment variables through dotenv-expand. For development only envs use .env.development, for production only envs use .env.production, for custom mode passed by --mode <stage>, load from .env.<stage> file.

    • If you want to customize the directory to load .env file, you can configure envDir.
    • If you want to customize the prefix of env variables which are injected to define, you can configure envPrefix.
    -

    envPrefix

    +

    envPrefix

    • default value: FARM_VITE_

    Customize the prefix of the env variable by configuring envPrefix. Env variables start with envPrefix will be injected into define automatically. For example, in the .env file:

    -
    // .env
    FARM_CUSTOM_VERSION=1.0.0
    APP_VERSION=0.1.0
    +
    // .env
    FARM_CUSTOM_VERSION=1.0.0
    APP_VERSION=0.1.0

    Then FARM_CUSTOM_VERSION will be injected, but not APP_VERSION, in your business code:

    -
    export function MyComp() {
    const farmCustomVersion = FARM_CUSTOM_VERSION;
    return <div>Farm Custom Version: {farmCustomVersion}</div>
    }
    +
    export function MyComp() {
    const farmCustomVersion = FARM_CUSTOM_VERSION;
    return <div>Farm Custom Version: {farmCustomVersion}</div>
    }

    FARM_CUSTOM_VERSION will be replaced by '1.0.0' automatically.

    -

    envDir

    +

    envDir

    • default value: <root>

    The directory to load env file. By default Farm load env file from root.

    -
    export defineConfig({
    envDir: './env'
    })
    -

    For above config example, Farm will load .env, .env.development, etc from <root>/env dir.

    +
    export defineConfig({
    envDir: './env'
    })
    +

    For above config example, Farm will load .env, .env.development, etc from <root>/env dir.

    \ No newline at end of file diff --git a/docs/features/html/index.html b/docs/features/html/index.html index 5f4cc6216..85d53daa0 100644 --- a/docs/features/html/index.html +++ b/docs/features/html/index.html @@ -8,31 +8,31 @@ - - - + + + -
    Version: 1.0.0

    Html

    -

    Basic Usage

    +
    Version: 1.0.0

    Html

    +

    Basic Usage

    Farm support compile Html out of box, and you should use Html as entry when build a web project, for example:

    -
    farm.config.ts
    import type { defineConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    -
    note

    If the input is not specified, default to { index: 'index.html' }.

    +
    farm.config.ts
    import type { defineConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    +
    note

    If the input is not specified, default to { index: 'index.html' }.

    and in ./index.html, a <script src="./xxx"> should be used to refer to your script entry.

    -
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>
    +
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>

    and you can also use <link href="./xxx"> to refer to your global css.

    Farm will transform these scripts and links to final production resources when compiling. Note that you have to use relative path when you want to refer to a local module, for example <script src="./index.tsx"></script> will refer to a local module and compile it, but <script src="/index.tsx"></script> or <script src="https://xxx.com/index.tsx"></script> would not.

    -
    tip

    The script and link can refer to any module types that farm support, for example, js, jsx, ts, tsx, or other module types supported by plugins. You can use as many scripts or links as you want.

    -

    Multi Page App

    +
    tip

    The script and link can refer to any module types that farm support, for example, js, jsx, ts, tsx, or other module types supported by plugins. You can use as many scripts or links as you want.

    +

    Multi Page App

    If you are building a Multi Page Application, just configure multiple html input, for example:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    },
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    },
    });

    Farm will compile these pages in parallel, and all dependencies of these pages will be shared too.

    -

    Inherit html template

    +

    Inherit html template

    Farm supports inherit html template by using html.base config, which is helpful when building a multi-page application with html shared.

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });

    Then add a base.html, placeholder {{children}} will be replaced by children's content.

    -
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- using children placeholder and it will be replaced -->
    {{children}}
    </body>
    </html>
    +
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- using children placeholder and it will be replaced -->
    {{children}}
    </body>
    </html>

    Inherit ./base.html:

    -
    ./src/home.html
    <!-- Other fields are inherit from ../base.html -->
    <script src="./index.tsx"></script>
    +
    ./src/home.html
    <!-- Other fields are inherit from ../base.html -->
    <script src="./index.tsx"></script>
    \ No newline at end of file diff --git a/docs/features/lazy-compilation/index.html b/docs/features/lazy-compilation/index.html index 6d5c0daa9..dca62bb8e 100644 --- a/docs/features/lazy-compilation/index.html +++ b/docs/features/lazy-compilation/index.html @@ -8,25 +8,25 @@ - - - + + + -
    Version: 1.0.0

    Lazy Compilation

    +
    Version: 1.0.0

    Lazy Compilation

    When comes to a big project, you may want to split them into small pieces and load on demand. This can be achieved by dynamic imports.

    -
    const page = React.lazy(() => import('./page')); // lazy load page
    +
    const page = React.lazy(() => import('./page')); // lazy load page

    By default, Farm will lazy compile these dynamic imports in development, only compile them when the module is really executed. Lazy compilation can really speedup the compiling of a large project.

    -
    note

    Lazy Compilation are always disabled for production build.

    +
    note

    Lazy Compilation are always disabled for production build.

    Note that it is important to use the dynamic import properly to make lazy compilation work better. For example, if one of your page has a big dependencies, but this dependencies won't be used until this page rendered, then it is necessary to make sure that this big dependencies are dynamic imported, so it won't be compiled util the page rendered.

    -

    Configuring Lazy Compilation

    +

    Configuring Lazy Compilation

    Using compilation.lazyCompilation to enable or disable it:

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    lazyCompilation: true,
    },
    });
    -

    How Lazy Compilation Work

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    lazyCompilation: true,
    },
    });
    +

    How Lazy Compilation Work

    When lazy compilation is enabled, Farm will analyze all of your dynamic import first, for example:

    -
    const page = React.lazy(() => import('./page'));
    +
    const page = React.lazy(() => import('./page'));

    Farm will treat ./page as a module that should be lazy compiled and won't compile it, instead, Farm will return a virtual placeholder module for ./page like:

    -
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // return a promise, this promise will be resolved when lazy compilation finished.
    let promise = Promise.resolve();

    // it has lazy been lazy compiling
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // request the dev server for lazy compilation
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    -

    Above example illustrated a basic structure of that virtual placeholder module. When the placeholder executed, it will request the dev server to compile this module and its dependencies. After getting the lazy compiled result from dev server, the placeholder module will patch these changes to Farm's runtime module system.

    +
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // return a promise, this promise will be resolved when lazy compilation finished.
    let promise = Promise.resolve();

    // it has lazy been lazy compiling
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // request the dev server for lazy compilation
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    +

    Above example illustrated a basic structure of that virtual placeholder module. When the placeholder executed, it will request the dev server to compile this module and its dependencies. After getting the lazy compiled result from dev server, the placeholder module will patch these changes to Farm's runtime module system.

    \ No newline at end of file diff --git a/docs/features/script/index.html b/docs/features/script/index.html index 2d9e96fe4..23f9414fa 100644 --- a/docs/features/script/index.html +++ b/docs/features/script/index.html @@ -8,55 +8,55 @@ - - - + + + -
    Version: 1.0.0

    TS/TSX

    +
    Version: 1.0.0

    TS/TSX

    Farm support compiling Js/Jsx/Ts/Tsx out of box, and compile Jsx/Tsx to React by default.

    -
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }
    +
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }

    Farm using SWC to compile scripts, and Farm has set reasonable default configurations for script compilation. Also, you can use compilation.script to configure how to compile your script file. see compilation.script for details.

    -

    Configuring Swc Parser

    +

    Configuring Swc Parser

    You can configuring the SWC Parser through compilation.script.parser. Refer to https://swc.rs/docs/configuration/compilation#jscparser.

    For example, if you want to enable decorator, you can set compilation.script.parser.esConfig.decorators(or tsConfig.decorators if the module is TS):

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    });
    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    });

    By default Farm set jsx: true for .jsx|.tsx files. Other field are default to SWC's defaults.

    -

    Configuring Target

    +

    Configuring Target

    Using compilation.script.target to configure your target env when running your project, Farm set it based on output.targetEnv.

    -
    note

    Farm set compilation.script.target automatically based on output.targetEnv. Normally you should not set target manually, use output.targetEnv would be enough.

    +
    note

    Farm set compilation.script.target automatically based on output.targetEnv. Normally you should not set target manually, use output.targetEnv would be enough.

    This option can be used along with compilation.presetEnv to gracefully downgrade your project for old browsers. For example, you can set target to ES5 and enable presetEnv, then your project will be fully downgrade to ES5.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    });
    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    });

    Refer to Syntax Downgrade and Polyfill for more about presetEnv and target.

    -

    Decorators

    +

    Decorators

    Decorators is disabled by default, you can set compilation.script.parser.tsConfig.decorators to true to enable decorators.

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // support decorators
    decorators: true,
    },
    },
    // configuring decorators
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // support decorators
    decorators: true,
    },
    },
    // configuring decorators
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });

    Farm provide a example for supporting decorators, see https://github.com/farm-fe/farm/tree/main/examples/decorators By default, Farm won't transform decorators for modules under node_modules, refer to compilation.script.decorators.excludes.

    -

    Using SWC Plugins

    +

    Using SWC Plugins

    SWC Plugins can be used directly in Farm, for example, we use swc-plugin-vue-jsx to compiling vue jsx in Farm:

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import jsPluginVue from "@farmfe/js-plugin-vue";

    export default defineConfig({
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    });
    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import jsPluginVue from "@farmfe/js-plugin-vue";

    export default defineConfig({
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    });

    Refer to Using Plugins for more details.

    -

    Vite-style import.meta.glob

    +

    Vite-style import.meta.glob

    Farm fully support Vite-style import.meta.glob, see glob import.

    for example:

    -
    const modules = import.meta.glob("./dir/*.js");
    +
    const modules = import.meta.glob("./dir/*.js");

    The above will be transformed into the following:

    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };
    +
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };

    Using { eager: true }:

    -
    const modules = import.meta.glob("./dir/*.js", { eager: true });
    +
    const modules = import.meta.glob("./dir/*.js", { eager: true });

    The above will be transformed into the following:

    -
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };
    +
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };

    multiple patterns are supported:

    -
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);
    +
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);

    negative patterns are also supported:

    -
    const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    };
    -
    note
      +
      const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
      +
      // code produced by Farm
      const modules = {
      "./dir/foo.js": () => import("./dir/foo.js"),
      };
      +
      note
      • You should also be aware that all the arguments in the import.meta.glob must be passed as literals. You can NOT use variables or expressions in them.
      • import.meta.glob transformed by Farm in compile time, it does not exist in runtime.
      • -
    +
    \ No newline at end of file diff --git a/docs/features/sourcemap/index.html b/docs/features/sourcemap/index.html index d52051b00..8620e1f0a 100644 --- a/docs/features/sourcemap/index.html +++ b/docs/features/sourcemap/index.html @@ -8,16 +8,16 @@ - - - + + + -
    Version: 1.0.0

    Source Map

    +
    Version: 1.0.0

    Source Map

    Farm supports Source Map, which is automatically enabled by default. Sourcemap can be enable or disable via the compilation.sourcemap option.

    -
    note

    Farm will not generate sourcemap for files under node_modules by default, if you want to generate sourcemap for files under node_modules, configure compilation.sourcemap to all.

    +
    note

    Farm will not generate sourcemap for files under node_modules by default, if you want to generate sourcemap for files under node_modules, configure compilation.sourcemap to all.

    Using compilation.sourcemap to configuring sourcemap generation:

    -
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };

    All options are as below:

    • true: Only generate sourcemap for files not under node_modules, and generate a separate sourcemap file
    • @@ -26,6 +26,6 @@
    • all: generate sourcemap for all files, and generate a separate sourcemap file
    • all-inline: Generate source maps for all files, and inline source maps into the product, do not generate separate files
    -
    note

    For plugin authors, if you transform the code in transform hook or renderResourcePot hook, you should return the source map of your transformation to ensure source map is correct. Farm maintains a source map chain of plugins to trace the final resources back to the real original code.

    +
    note

    For plugin authors, if you transform the code in transform hook or renderResourcePot hook, you should return the source map of your transformation to ensure source map is correct. Farm maintains a source map chain of plugins to trace the final resources back to the real original code.

    \ No newline at end of file diff --git a/docs/features/static/index.html b/docs/features/static/index.html index 16549a1cf..f7ff472a9 100644 --- a/docs/features/static/index.html +++ b/docs/features/static/index.html @@ -8,30 +8,30 @@ - - - + + + -
    Version: 1.0.0

    Static Assets

    +
    Version: 1.0.0

    Static Assets

    Farm treat modules that is not treated as code as Static Assets, for example, images like png/svg/etc, text files like txt/xlsx/etc. This document describes how Farm deal with these assets.

    -

    url

    +

    url

    Import a image:

    -
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }
    +
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }

    Default to use url method when import a image. When using url methods to import a image, the image will be emitted to the output dir directly, and the image module itself will be compiled to a js module like:

    -
    export default '/rocket.<content hash>.svg'
    +
    export default '/rocket.<content hash>.svg'

    using compilation.output.assetFilename to config your asset name。

    -

    inline

    +

    inline

    Using query ?inline to tell Farm that you want to inline your assets,then the assets will be transformed to base64,for example:

    -
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    -

    raw

    +
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    +

    raw

    Using query ?raw to tell Farm that you want to read the raw string of the assets, for example

    -
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    -

    Configuring Assets

    +
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    +

    Configuring Assets

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    assetFilename: 'assets/[resourceName].[hash].[ext]', // [] is a placeholder, Farm currently only these three kind of placeholders
    },
    assets: {
    include: ['txt'] // extra static asset extension
    }
    }
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    assetFilename: 'assets/[resourceName].[hash].[ext]', // [] is a placeholder, Farm currently only these three kind of placeholders
    },
    assets: {
    include: ['txt'] // extra static asset extension
    }
    }
    });
    \ No newline at end of file diff --git a/docs/frameworks/electron/index.html b/docs/frameworks/electron/index.html index 4a4108c26..6a9c58a4b 100644 --- a/docs/frameworks/electron/index.html +++ b/docs/frameworks/electron/index.html @@ -8,26 +8,26 @@ - - - + + + -
    Version: 1.0.0

    Electron

    +
    Version: 1.0.0

    Electron

    Create a Electron project based on Farm.

    Farm provides two approaches to support creating Electron projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Electron project following the current documentation
    -

    Creating a Electron Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Electron Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Electron template in Select Framework

    After selecting Electron, you can continue to select all sub templates already supported by Farm

    -
    - React
    - Vue
    - Preact
    - Svelte
    - Solid
    +
    - React
    - Vue
    - Preact
    - Svelte
    - Solid

    You can choose the framework you want to use to run on electron, farm wrote electron js plugin

    such as react template

    -
    import { defineConfig } from '@farmfe/core';
    import electron from '@farmfe/js-plugin-electron';

    export default defineConfig({
    plugins: [
    '@farmfe/plugin-react',
    electron({
    main: {
    input: 'electron/main.ts',
    },
    preload: {
    input: 'electron/preload.ts',
    },
    }),
    ]
    });

    -

    For more example details: Electron Example

    +
    import { defineConfig } from '@farmfe/core';
    import electron from '@farmfe/js-plugin-electron';

    export default defineConfig({
    plugins: [
    '@farmfe/plugin-react',
    electron({
    main: {
    input: 'electron/main.ts',
    },
    preload: {
    input: 'electron/preload.ts',
    },
    }),
    ]
    });

    +

    For more example details: Electron Example

    \ No newline at end of file diff --git a/docs/frameworks/lit/index.html b/docs/frameworks/lit/index.html index 6bd93d168..a7997cd79 100644 --- a/docs/frameworks/lit/index.html +++ b/docs/frameworks/lit/index.html @@ -8,23 +8,23 @@ - - - + + + -
    Version: 1.0.0

    Lit

    +
    Version: 1.0.0

    Lit

    Create a Lit project based on Farm.

    Farm provides two approaches to support creating Lit projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Lit project following the current documentation
    -

    Creating a Lit Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Lit Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Lit template in Select Framework

    If you use lit then we need to configure the decorator

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    presetEnv: false,
    script: {
    plugins: [],
    target: 'es2022',
    parser: {
    tsConfig: {
    decorators: true,
    dts: false,
    noEarlyErrors: false,
    tsx: false
    }
    }
    }
    }
    });

    -

    For more example details: React Example

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    presetEnv: false,
    script: {
    plugins: [],
    target: 'es2022',
    parser: {
    tsConfig: {
    decorators: true,
    dts: false,
    noEarlyErrors: false,
    tsx: false
    }
    }
    }
    }
    });

    +

    For more example details: React Example

    \ No newline at end of file diff --git a/docs/frameworks/nestjs/index.html b/docs/frameworks/nestjs/index.html index 6af29aaec..7cce84554 100644 --- a/docs/frameworks/nestjs/index.html +++ b/docs/frameworks/nestjs/index.html @@ -8,25 +8,25 @@ - - - + + + -
    Version: 1.0.0

    NestJs

    +
    Version: 1.0.0

    NestJs

    Create a NestJs project based on Farm.

    Farm provides two approaches to support creating NestJs projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a NestJs project following the current documentation
    -

    Creating a NestJs Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a NestJs Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select NestJs template in Select Framework

    The nestjs project uses farmup to start and build the project. Farmup is built based on farm to simplify the way you run ts files in node js.

    After downloading the template, run pnpm dev to start the nestjs project

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    Start enjoying the development experience of millisecond builds

    -

    For more example details: React Example

    +

    For more example details: React Example

    \ No newline at end of file diff --git a/docs/frameworks/preact/index.html b/docs/frameworks/preact/index.html index 86246390e..3003e65ba 100644 --- a/docs/frameworks/preact/index.html +++ b/docs/frameworks/preact/index.html @@ -8,29 +8,29 @@ - - - + + + -
    Version: 1.0.0

    Preact

    +
    Version: 1.0.0

    Preact

    Create a Preact project based on Farm.

    Farm provides two approaches to support creating Preact projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Preact project following the current documentation
    -

    Creating a Preact Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Preact Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Preact template in Select Framework

    -
    Preact

    For Preact support, Farm recommends using Vite plugins.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Preact from "vite-plugin-preact";

    export default defineConfig({
    plugins: [Preact()],
    });
    +
    Preact

    For Preact support, Farm recommends using Vite plugins.

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Preact from "vite-plugin-preact";

    export default defineConfig({
    plugins: [Preact()],
    });

    If you want to start DevServer

    -
    npm
    yarn
    pnpm
    bun
    npm dev
    +
    npm
    yarn
    pnpm
    bun
    npm dev

    If you need to run the build production environment product command

    -
    npm
    yarn
    pnpm
    bun
    npm build
    +
    npm
    yarn
    pnpm
    bun
    npm build

    If you need to preview your build product

    -
    npm
    yarn
    pnpm
    bun
    npm preview
    -

    For more example details: Preact Example

    +
    npm
    yarn
    pnpm
    bun
    npm preview
    +

    For more example details: Preact Example

    \ No newline at end of file diff --git a/docs/frameworks/react/index.html b/docs/frameworks/react/index.html index aafdaeeb5..ef2f58be6 100644 --- a/docs/frameworks/react/index.html +++ b/docs/frameworks/react/index.html @@ -8,37 +8,37 @@ - - - + + + -
    Version: 1.0.0

    React

    +
    Version: 1.0.0

    React

    Create a React project based on Farm.

    Farm provides two approaches to support creating React projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a React project following the current documentation
    -

    Creating a React Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a React Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select React template in Select Framework

    Farm requires the registration of the @farmfe/plugin-react plugin to support React projects.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: ['@farmfe/plugin-react'],
    });
    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: ['@farmfe/plugin-react'],
    });

    The @farmfe/plugin-react plugin is written in Rust, so you do not need to explicitly import it; you can register it by passing a string package name.

    -

    Integrating emotion

    +

    Integrating emotion

    You can support emotion by registering the @swc/plugin-emotion plugin.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    plugins: [
    {
    name: '@swc/plugin-emotion',
    options: {},
    filters: {
    moduleTypes: ['tsx'],
    },
    },
    ],
    },
    },
    plugins: [['@farmfe/plugin-react', { "importSource": "@emotion/react" }]],
    });

    -
    src/index.tsx
    import { css } from '@emotion/react';

    const color = 'white';

    export function Main() {
    return (
    <div
    onClick={() => setCount((c) => c + 1)}
    css={css`
    padding: 32px;
    background-color: hotpink;
    font-size: 24px;
    border-radius: 4px;
    &:hover {
    color: ${color};
    }
    `}
    >
    {a}: {count}
    </div>
    );
    }
    -

    Integrating svgr

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    plugins: [
    {
    name: '@swc/plugin-emotion',
    options: {},
    filters: {
    moduleTypes: ['tsx'],
    },
    },
    ],
    },
    },
    plugins: [['@farmfe/plugin-react', { "importSource": "@emotion/react" }]],
    });

    +
    src/index.tsx
    import { css } from '@emotion/react';

    const color = 'white';

    export function Main() {
    return (
    <div
    onClick={() => setCount((c) => c + 1)}
    css={css`
    padding: 32px;
    background-color: hotpink;
    font-size: 24px;
    border-radius: 4px;
    &:hover {
    color: ${color};
    }
    `}
    >
    {a}: {count}
    </div>
    );
    }
    +

    Integrating svgr

    SVGR is a tool for transforming svgs into React components. Farm offers a Js plugin to support SVGR.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    export default defineConfig(async (env) => {
    return {
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: process.env.NODE_ENV === 'development',
    development: process.env.NODE_ENV === 'development'
    }
    ],
    farmJsPluginSvgr()
    ]
    };
    });


    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    export default defineConfig(async (env) => {
    return {
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: process.env.NODE_ENV === 'development',
    development: process.env.NODE_ENV === 'development'
    }
    ],
    farmJsPluginSvgr()
    ]
    };
    });


    If you want to start DevServer

    -
    npm
    yarn
    pnpm
    bun
    npm dev
    +
    npm
    yarn
    pnpm
    bun
    npm dev

    If you need to run the build production environment product command

    -
    npm
    yarn
    pnpm
    bun
    npm build
    +
    npm
    yarn
    pnpm
    bun
    npm build

    If you need to preview your build product

    -
    npm
    yarn
    pnpm
    bun
    npm preview
    -

    For more example details: React Example

    +
    npm
    yarn
    pnpm
    bun
    npm preview
    +

    For more example details: React Example

    \ No newline at end of file diff --git a/docs/frameworks/solid/index.html b/docs/frameworks/solid/index.html index 1cdf3540c..426aac3b0 100644 --- a/docs/frameworks/solid/index.html +++ b/docs/frameworks/solid/index.html @@ -8,29 +8,29 @@ - - - + + + -
    Version: 1.0.0

    Solid

    +
    Version: 1.0.0

    Solid

    Create a Solid project based on Farm.

    Farm provides two approaches to support creating Solid projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Solid project following the current documentation
    -

    Creating a Solid Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Solid Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Solid template in Select Framework

    -
    Solid

    For Solid support, Farm recommends using Vite plugins.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import solid from 'vite-plugin-solid';

    export default defineConfig({
    vitePlugins: [
    () => ({
    vitePlugin: solid(),
    filters: ['\\.tsx$', '\\.jsx$']
    })
    ]
    });
    +
    Solid

    For Solid support, Farm recommends using Vite plugins.

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import solid from 'vite-plugin-solid';

    export default defineConfig({
    vitePlugins: [
    () => ({
    vitePlugin: solid(),
    filters: ['\\.tsx$', '\\.jsx$']
    })
    ]
    });

    If you want to start DevServer

    -
    npm
    yarn
    pnpm
    bun
    npm dev
    +
    npm
    yarn
    pnpm
    bun
    npm dev

    If you need to run the build production environment product command

    -
    npm
    yarn
    pnpm
    bun
    npm build
    +
    npm
    yarn
    pnpm
    bun
    npm build

    If you need to preview your build product

    -
    npm
    yarn
    pnpm
    bun
    npm preview
    -

    For more example details: Solid Example

    +
    npm
    yarn
    pnpm
    bun
    npm preview
    +

    For more example details: Solid Example

    \ No newline at end of file diff --git a/docs/frameworks/svelte/index.html b/docs/frameworks/svelte/index.html index 8d62928ab..8a793378b 100644 --- a/docs/frameworks/svelte/index.html +++ b/docs/frameworks/svelte/index.html @@ -8,30 +8,30 @@ - - - + + + -
    Version: 1.0.0

    Svelte

    +
    Version: 1.0.0

    Svelte

    Create a Svelte project based on Farm.

    Farm provides two approaches to support creating Svelte projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Svelte project following the current documentation
    -

    Creating a Svelte Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Svelte Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Svelte template in Select Framework

    -
    Svelte

    For Svelte support, Farm recommends using Vite plugins.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core'
    import { svelte } from '@sveltejs/vite-plugin-svelte'

    export default defineConfig({
    vitePlugins: [svelte()],
    })

    -
    svelte.config.ts
    import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'

    export default {
    preprocess: vitePreprocess(),
    }
    +
    Svelte

    For Svelte support, Farm recommends using Vite plugins.

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core'
    import { svelte } from '@sveltejs/vite-plugin-svelte'

    export default defineConfig({
    vitePlugins: [svelte()],
    })

    +
    svelte.config.ts
    import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'

    export default {
    preprocess: vitePreprocess(),
    }

    If you want to start DevServer

    -
    npm
    yarn
    pnpm
    bun
    npm dev
    +
    npm
    yarn
    pnpm
    bun
    npm dev

    If you need to run the build production environment product command

    -
    npm
    yarn
    pnpm
    bun
    npm build
    +
    npm
    yarn
    pnpm
    bun
    npm build

    If you need to preview your build product

    -
    npm
    yarn
    pnpm
    bun
    npm preview
    -

    For more example details: Svelte Example

    +
    npm
    yarn
    pnpm
    bun
    npm preview
    +

    For more example details: Svelte Example

    \ No newline at end of file diff --git a/docs/frameworks/tauri/index.html b/docs/frameworks/tauri/index.html index 301c3d6b5..8f3bdacc5 100644 --- a/docs/frameworks/tauri/index.html +++ b/docs/frameworks/tauri/index.html @@ -8,20 +8,20 @@ - - - + + + -
    Version: 1.0.0

    Tauri

    +
    Version: 1.0.0

    Tauri

    Create a Tauri project based on Farm.

    Farm provides two approaches to support creating Tauri projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Tauri project following the current documentation
    -

    Creating a Tauri Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Tauri Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Tauri template in Select Framework

    1. @@ -33,8 +33,8 @@

      Cre

    In your terminal, cd into the new Tauri project folder.

    Update the file with the following content:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: ['@farmfe/plugin-react'],
    server: {
    port: 1420
    }
    });

    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: ['@farmfe/plugin-react'],
    server: {
    port: 1420
    }
    });

    then run pnpm tauri dev

    -

    For more example details: React Example

    +

    For more example details: React Example

    \ No newline at end of file diff --git a/docs/frameworks/vanilla/index.html b/docs/frameworks/vanilla/index.html index d4f6fb514..98f32caba 100644 --- a/docs/frameworks/vanilla/index.html +++ b/docs/frameworks/vanilla/index.html @@ -8,27 +8,27 @@ - - - + + + -
    Version: 1.0.0

    Vanilla

    +
    Version: 1.0.0

    Vanilla

    Create a Vanilla project based on Farm.

    Farm provides two approaches to support creating Vanilla projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Vanilla project following the current documentation
    -

    Creating a Vanilla Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Vanilla Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Vanilla template in Select Framework

    Using the vanilla template you do not need to install any other framework dependencies, just run dev to start devServer

    -
    npm
    yarn
    pnpm
    bun
    npm dev
    +
    npm
    yarn
    pnpm
    bun
    npm dev

    If you need to run the build production environment product command

    -
    npm
    yarn
    pnpm
    bun
    npm build
    +
    npm
    yarn
    pnpm
    bun
    npm build

    If you need to preview your build product

    -
    npm
    yarn
    pnpm
    bun
    npm preview
    -

    For more example details: React Example

    +
    npm
    yarn
    pnpm
    bun
    npm preview
    +

    For more example details: React Example

    \ No newline at end of file diff --git a/docs/frameworks/vue/index.html b/docs/frameworks/vue/index.html index 64c46ecf5..e7557e09b 100644 --- a/docs/frameworks/vue/index.html +++ b/docs/frameworks/vue/index.html @@ -8,31 +8,31 @@ - - - + + + -
    Version: 1.0.0

    Vue

    +
    Version: 1.0.0

    Vue

    Create a Vue project based on Farm.

    Farm provides two approaches to support creating Vue projects:

    • Use the create-farm scaffold to create a scaffold project
    • You can manually create a Vue project following the current documentation
    -

    Creating a Vue Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    Creating a Vue Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Vue template in Select Framework

    -
    warning

    Currently, Farm uses Vite plugins for both vue2 and vue3 and vue2.7 compilation. Also the development of Rust Vue plugin fervid is also underway.

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Vue from '@vitejs/plugin-vue'

    export default defineConfig({
    vitePlugins: [Vue()],
    });
    -

    Integrating jsx

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import VueJsx from '@vitejs/plugin-vue-jsx'

    export default defineConfig({
    vitePlugins: [VueJsx()],
    });
    +
    warning

    Currently, Farm uses Vite plugins for both vue2 and vue3 and vue2.7 compilation. Also the development of Rust Vue plugin fervid is also underway.

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Vue from '@vitejs/plugin-vue'

    export default defineConfig({
    vitePlugins: [Vue()],
    });
    +

    Integrating jsx

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import VueJsx from '@vitejs/plugin-vue-jsx'

    export default defineConfig({
    vitePlugins: [VueJsx()],
    });

    If you want to start DevServer

    -
    npm
    yarn
    pnpm
    bun
    npm dev
    +
    npm
    yarn
    pnpm
    bun
    npm dev

    If you need to run the build production environment product command

    -
    npm
    yarn
    pnpm
    bun
    npm build
    +
    npm
    yarn
    pnpm
    bun
    npm build

    If you need to preview your build product

    -
    npm
    yarn
    pnpm
    bun
    npm preview
    -

    For more example details: Vue Example

    +
    npm
    yarn
    pnpm
    bun
    npm preview
    +

    For more example details: Vue Example

    \ No newline at end of file diff --git a/docs/migration/from-vite/index.html b/docs/migration/from-vite/index.html index dc291080d..a22064fd5 100644 --- a/docs/migration/from-vite/index.html +++ b/docs/migration/from-vite/index.html @@ -8,13 +8,13 @@ - - - + + + -
    Version: 1.0.0

    Migrate From Vite

    -
    note

    Vite plugins like unocss are deeply integrated with Vite, these plugins may not be compatible with Farm due to the difference of internal design. You can try other method like unocss postcss plugin as walk-around.

    +
    Version: 1.0.0

    Migrate From Vite

    +
    note

    Vite plugins like unocss are deeply integrated with Vite, these plugins may not be compatible with Farm due to the difference of internal design. You can try other method like unocss postcss plugin as walk-around.

    Migrating from Vite is really simple as Farm is Vite-compatible. All you need to do is transforming vite.config.ts to farm.config.ts:

    • Refer to Configuring Farm for mapping farm config options to vite config options.
    • @@ -25,6 +25,6 @@
    • Some Vite config options is not needed in Farm, like optimizeDeps, you can ignore these options when migrating to Farm.
    • For SSR, you need to refactor it to Farm SSR
    -

    We have migrated a Real Vite Admin Project to Farm. Check this migration example for details.

    +

    We have migrated a Real Vite Admin Project to Farm. Check this migration example for details.

    \ No newline at end of file diff --git a/docs/plugins/community-plugins/index.html b/docs/plugins/community-plugins/index.html index 64ac77e5c..7dd78fa7c 100644 --- a/docs/plugins/community-plugins/index.html +++ b/docs/plugins/community-plugins/index.html @@ -8,17 +8,17 @@ - - - + + + -
    Version: 1.0.0

    Community Plugins

    -

    Vite/Rollup Plugins

    +
    Version: 1.0.0

    Community Plugins

    +

    Vite/Rollup Plugins

    Farm support Vite/Rollup plugins out of box. So Vite/Rollup or unplugin plugins can be used in Farm directly.

    -
    tip

    Farm recommends to write Farm Plugins instead of Vite/Rollup plugins for Farm. Because Farm Plugins have the best compatibility and performance. Still, PR welcome if you developed a Farm compatible plugin and you want to list it here.

    +
    tip

    Farm recommends to write Farm Plugins instead of Vite/Rollup plugins for Farm. Because Farm Plugins have the best compatibility and performance. Still, PR welcome if you developed a Farm compatible plugin and you want to list it here.

    using vitePlugins in farm.config.ts to configure Vite/Rollup plugins.

    -
    import { UserConfig } from "@farmfe/core";
    import vue from "@vitejs/plugin-vue";
    import vueJsx from "@vitejs/plugin-vue-jsx";

    const config: UserConfig = {
    vitePlugins: [vue(), vueJsx()],
    };
    +
    import { UserConfig } from "@farmfe/core";
    import vue from "@vitejs/plugin-vue";
    import vueJsx from "@vitejs/plugin-vue-jsx";

    const config: UserConfig = {
    vitePlugins: [vue(), vueJsx()],
    };
    -

    unplugin

    -
    note

    Currently you can use unplugin/farm, unplugin/vite and unplugin/rollup in Farm. If you are using unplugin/vite or unplugin/rollup, some attributes may not have been fully adapted, or the Farm team believes that the api does not have the adaptation conditions, you can provide issues.

    -
    import Icons from "unplugin-icons/vite";
    import IconsResolver from "unplugin-icons/resolver";
    import Components from "unplugin-vue-components/rollup";
    import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
    import { FileSystemIconLoader } from "unplugin-icons/loaders";

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: "vue3",
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, (svg) =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    ),
    },
    scale: 1,
    defaultClass: "inline-block",
    }),
    Components({
    dts: "src/typings/components.d.ts",
    types: [{ from: "vue-router", names: ["RouterLink", "RouterView"] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({
    customCollections: [collectionName],
    componentPrefix: VITE_ICON_PREFIX,
    }),
    ],
    }),
    ],
    };
    +

    unplugin

    +
    note

    Currently you can use unplugin/farm, unplugin/vite and unplugin/rollup in Farm. If you are using unplugin/vite or unplugin/rollup, some attributes may not have been fully adapted, or the Farm team believes that the api does not have the adaptation conditions, you can provide issues.

    +
    import Icons from "unplugin-icons/vite";
    import IconsResolver from "unplugin-icons/resolver";
    import Components from "unplugin-vue-components/rollup";
    import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
    import { FileSystemIconLoader } from "unplugin-icons/loaders";

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: "vue3",
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, (svg) =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    ),
    },
    scale: 1,
    defaultClass: "inline-block",
    }),
    Components({
    dts: "src/typings/components.d.ts",
    types: [{ from: "vue-router", names: ["RouterLink", "RouterView"] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({
    customCollections: [collectionName],
    componentPrefix: VITE_ICON_PREFIX,
    }),
    ],
    }),
    ],
    };

    All unplugin are supported in Farm:

    +
    \ No newline at end of file diff --git a/docs/plugins/official-plugins/dsv/index.html b/docs/plugins/official-plugins/dsv/index.html index 37a2d4a7d..0147dd600 100644 --- a/docs/plugins/official-plugins/dsv/index.html +++ b/docs/plugins/official-plugins/dsv/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/plugin-dsv

    +
    Version: 1.0.0

    @farmfe/plugin-dsv

    🍣 A Farm plugin which converts .csv and .tsv files into JavaScript modules.

    -

    Requirements

    +

    Requirements

    This plugin requires an LTS Node version (v18.0.0+) and Farm v1.0.0+.

    -

    Installation

    -
    npm
    yarn
    pnpm
    bun
    npm add @farmfe/plugin-dsv
    -

    Usage

    +

    Installation

    +
    npm
    yarn
    pnpm
    bun
    npm add @farmfe/plugin-dsv
    +

    Usage

    Create a farm.config.js configuration file and import the plugin:

    -
    import { defineConfig } from '@farmfe/core';
    import dsv from '@farmfe/plugin-dsv';

    export default defineConfig({
    plugins: [
    [
    dsv()
    ]
    ],
    });
    -

    Practical Example

    +
    import { defineConfig } from '@farmfe/core';
    import dsv from '@farmfe/plugin-dsv';

    export default defineConfig({
    plugins: [
    [
    dsv()
    ]
    ],
    });
    +

    Practical Example

    Suppose that you have a CSV (or TSV!) file which contains some information on delicious fruits:

    -
    type,count
    apples,7
    pears,4
    bananas,5
    +
    type,count
    apples,7
    pears,4
    bananas,5

    And suppose you'd like to import that CSV as an Array within some part of your code. After adding the plugin (as shown above), you may import (or require) the CSV file directly. The import will provide an Array of Objects representing rows from the CSV file:

    -
    import fruit from './fruit.csv';

    console.log(fruit);
    // [
    // { type: 'apples', count: '7' },
    // { type: 'pears', count: '4' },
    // { type: 'bananas', count: '5' }
    // ]
    +
    import fruit from './fruit.csv';

    console.log(fruit);
    // [
    // { type: 'apples', count: '7' },
    // { type: 'pears', count: '4' },
    // { type: 'bananas', count: '5' }
    // ]
    \ No newline at end of file diff --git a/docs/plugins/official-plugins/js-dts/index.html b/docs/plugins/official-plugins/js-dts/index.html index c417e0b70..fd6a08ee2 100644 --- a/docs/plugins/official-plugins/js-dts/index.html +++ b/docs/plugins/official-plugins/js-dts/index.html @@ -8,18 +8,18 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/js-plugin-dts

    +
    Version: 1.0.0

    @farmfe/js-plugin-dts

    Support Generate .d.ts files for Farm. This plugin is used for building tools and libraries, generate .d.ts for your typescript code.

    -

    Installation

    -
    npm install @farmfe/js-plugin-dts
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    -

    Options

    -
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    +

    Installation

    +
    npm install @farmfe/js-plugin-dts
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    +

    Options

    +
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    \ No newline at end of file diff --git a/docs/plugins/official-plugins/js-less/index.html b/docs/plugins/official-plugins/js-less/index.html index aead4a0bf..bb7ad9944 100644 --- a/docs/plugins/official-plugins/js-less/index.html +++ b/docs/plugins/official-plugins/js-less/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/js-plugin-less

    +
    Version: 1.0.0

    @farmfe/js-plugin-less

    Support less for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-less less
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    -

    Options

    -
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    lessOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-less less
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    +

    Options

    +
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    lessOptions

    Less options. See less options.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by less. default to { resolvedPaths: ['\\.less$'] } for load and { moduleTypes: ['less'] } for transform.

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-less$'],
    moduleTypes: ['less']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    implementation package name of less. Default to less.

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    Additional data to be added to every less file. Example:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }

    For less file:

    -
    index.less
    .foo {
    color: @primary-color;
    }
    +
    index.less
    .foo {
    color: @primary-color;
    }

    additionalData will be added to the top of the file:

    -
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }
    +
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }

    Function form:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    \ No newline at end of file diff --git a/docs/plugins/official-plugins/js-postcss/index.html b/docs/plugins/official-plugins/js-postcss/index.html index 412d8fcbc..ac1998cc1 100644 --- a/docs/plugins/official-plugins/js-postcss/index.html +++ b/docs/plugins/official-plugins/js-postcss/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/js-plugin-postcss

    +
    Version: 1.0.0

    @farmfe/js-plugin-postcss

    Support postcss for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-postcss postcss
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    -

    Options

    -
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    -

    postcssLoadConfig

    +

    Installation

    +
    npm install @farmfe/js-plugin-postcss postcss
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    +

    Options

    +
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    +

    postcssLoadConfig

    Farm uses postcss-load-config to load postcss config, so you can use postcss-load-config's options. Refer to postcss-load-config.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by postcss. default to { moduleTypes: ['css'] }.

    -

    implementation

    -

    implementation package name of postcss. Default to postcss.

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-css$'],
    moduleTypes: ['css']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    +

    implementation package name of postcss. Default to postcss.

    \ No newline at end of file diff --git a/docs/plugins/official-plugins/js-sass/index.html b/docs/plugins/official-plugins/js-sass/index.html index 13eb44973..9c184510c 100644 --- a/docs/plugins/official-plugins/js-sass/index.html +++ b/docs/plugins/official-plugins/js-sass/index.html @@ -8,24 +8,24 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/js-plugin-sass

    +
    Version: 1.0.0

    @farmfe/js-plugin-sass

    Support sass for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-sass sass
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    -

    Options

    -
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    sassOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-sass sass
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    +

    Options

    +
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    sassOptions

    Sass options. See sass options for more details.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by sass. Default to { resolvedPaths: ['\\.(s[ac]ss)$'] } for load and { moduleTypes: ['sass'] } for transform.

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-sass$'],
    moduleTypes: ['sass']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    implementation package name of sass. Default to sass. If you want to use sass-embedded, you can set it to sass-embedded.

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    -
    note

    You should install sass-embedded manually.

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    +
    note

    You should install sass-embedded manually.

    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    Additional data to be added to every sass file. Example:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }

    For sass file:

    -
    index.scss
    .foo {
    color: @primary-color;
    }
    +
    index.scss
    .foo {
    color: @primary-color;
    }

    additionalData will be added to the top of the file:

    -
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }
    +
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }

    Function form:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    -

    globals

    -

    Global sass files. These files will be added to the top of every sass file. It's the same as additionalData but more convenient.

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    +

    globals

    +

    Global sass files. These files will be added to the top of every sass file. It's the same as additionalData but more convenient.

    \ No newline at end of file diff --git a/docs/plugins/official-plugins/js-svgr/index.html b/docs/plugins/official-plugins/js-svgr/index.html index a72b8a46b..d33743418 100644 --- a/docs/plugins/official-plugins/js-svgr/index.html +++ b/docs/plugins/official-plugins/js-svgr/index.html @@ -8,29 +8,29 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/js-plugin-svgr

    +
    Version: 1.0.0

    @farmfe/js-plugin-svgr

    Support React SVG Components for Farm.

    -

    Installation

    -
    npm install @farmfe/js-plugin-svgr
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    -

    Options

    -
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    -

    svgrOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-svgr
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    +

    Options

    +
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    +

    svgrOptions

    See svgr options for more details.

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    Which files should be processed by svgr. Default to { resolvedPaths: ['\\.svg$'] }.

    • resolvedPaths: Only files under these paths will be processed. Support regex.

    Example:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    \ No newline at end of file diff --git a/docs/plugins/official-plugins/overview/index.html b/docs/plugins/official-plugins/overview/index.html index 8da836ea6..8005a5638 100644 --- a/docs/plugins/official-plugins/overview/index.html +++ b/docs/plugins/official-plugins/overview/index.html @@ -8,15 +8,15 @@ - - - + + + -
    Version: 1.0.0

    Overview

    +
    Version: 1.0.0

    Overview

    Farm officially provides a lot of useful plugins, including Rust plugins and JS plugins. Rust plugins are much faster than Js plugins, we recommend to use Rust plugins whenever possible.

    -
    tip

    Refer to Using Plugins for how to use plugins in Farm.

    -

    Rust Plugins

    +
    tip

    Refer to Using Plugins for how to use plugins in Farm.

    +

    Rust Plugins

    -

    Js Plugins

    +

    Js Plugins

    -

    Community Plugins

    +

    Community Plugins

    If official plugins doesn't meet your needs, you can try Community Plugins

    -

    And of course check out awesome-farm - you can also submit a PR to list your plugins there.

    +

    And of course check out awesome-farm - you can also submit a PR to list your plugins there.

    \ No newline at end of file diff --git a/docs/plugins/official-plugins/react-components/index.html b/docs/plugins/official-plugins/react-components/index.html index 99b38d9fc..c7678d037 100644 --- a/docs/plugins/official-plugins/react-components/index.html +++ b/docs/plugins/official-plugins/react-components/index.html @@ -8,19 +8,19 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/plugin-react-components

    +
    Version: 1.0.0

    @farmfe/plugin-react-components

    On-demand components auto importing for React.

    -

    Installation

    -
    npm install @farmfe/plugin-react-components
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-react-components
    +

    Usage

    @farmfe/plugin-react-components is a Rust plugin, you only need to configure its package name in plugins field in farm.config.ts.

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', { /** options here */}]
    }
    -

    Features

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', { /** options here */}]
    }
    +

    Features

    • 💚 Supports React out-of-the-box.
    • ✨ Supports both components and directives.
    • @@ -29,24 +29,24 @@

      FeaturesBuilt-in resolvers for popular UI libraries.

    -

    Usage

    +

    Usage

    Use components in templates as you would usually do, it will import components on demand, and there is no import and component registration required anymore! If you register the parent component asynchronously (or lazy route), the auto-imported components will be code-split along with their parent.

    It will automatically turn this

    -
    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }
    +
    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }

    into this

    -
    import HelloWorld from './src/components/HelloWorld'

    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }
    +
    import HelloWorld from './src/components/HelloWorld'

    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }

    Note By default this plugin will import components in the src/components path. You can customize it using the dirs option.

    -

    TypeScript

    +

    TypeScript

    To get TypeScript support for auto-imported components.

    -
    Components({
    dts: true, // enabled by default if `typescript` is installed
    })
    +
    Components({
    dts: true, // enabled by default if `typescript` is installed
    })

    Once the setup is done, a components.d.ts will be generated and updates automatically with the type definitions. Feel free to commit it into git or not as you want.

    Make sure you also add components.d.ts to your tsconfig.json under include.

    -

    Importing from UI Libraries

    +

    Importing from UI Libraries

    We have several built-in resolvers for popular UI libraries like Ant Design, Arco Design, and Material UI, where you can enable them by:

    Supported Resolvers:

    -
    // farm.config.js

    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', {
    local: true,
    resolvers:[
    {
    module: "antd",
    prefix: "Ant"
    },
    {
    module:"@arco-design/web-react",
    prefix: "Arco",
    import_style: true // style/index.js
    }
    ]
    }]
    }
    -

    Configuration

    +
    // farm.config.js

    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', {
    local: true,
    resolvers:[
    {
    module: "antd",
    prefix: "Ant"
    },
    {
    module:"@arco-design/web-react",
    prefix: "Arco",
    import_style: true // style/index.js
    }
    ]
    }]
    }
    +

    Configuration

    The following show the default values of the configuration component

    -
    {
    // relative paths to the directory to search for components.
    dirs: ['src/components'],

    // resolvers for custom components.
    resolvers: [],

    /**
    * Components are introduced with Absolute or Relative path.
    *
    * @default Absolute
    */
    import_mode: "Absolute"

    /**
    * Is it valid for local components
    *
    * @default true
    */
    local: true,

    /**
    * import style `style/index.js` , also accepts a path for custom path (<Component>/**) with components
    *
    * @default false
    */
    importStyle?: boolean | string

    // generate `components.d.ts` global declarations,
    // also accepts a path for custom filename
    // default: `true` if package typescript is installed
    dts: true,

    // Filters for transforming targets (components to insert the auto import)
    // Note these are NOT about including/excluding components registered - use `Regex` for that
    include: ["src/components"],
    exclude: ["node_modules"],
    }
    +
    {
    // relative paths to the directory to search for components.
    dirs: ['src/components'],

    // resolvers for custom components.
    resolvers: [],

    /**
    * Components are introduced with Absolute or Relative path.
    *
    * @default Absolute
    */
    import_mode: "Absolute"

    /**
    * Is it valid for local components
    *
    * @default true
    */
    local: true,

    /**
    * import style `style/index.js` , also accepts a path for custom path (<Component>/**) with components
    *
    * @default false
    */
    importStyle?: boolean | string

    // generate `components.d.ts` global declarations,
    // also accepts a path for custom filename
    // default: `true` if package typescript is installed
    dts: true,

    // Filters for transforming targets (components to insert the auto import)
    // Note these are NOT about including/excluding components registered - use `Regex` for that
    include: ["src/components"],
    exclude: ["node_modules"],
    }
    \ No newline at end of file diff --git a/docs/plugins/official-plugins/react/index.html b/docs/plugins/official-plugins/react/index.html index 490b81692..835190b65 100644 --- a/docs/plugins/official-plugins/react/index.html +++ b/docs/plugins/official-plugins/react/index.html @@ -8,19 +8,19 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/plugin-react

    +
    Version: 1.0.0

    @farmfe/plugin-react

    Support React Jsx and React Refresh for Farm.

    -

    Installation

    -
    npm install @farmfe/plugin-react react-refresh
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-react react-refresh
    +

    Usage

    @farmfe/plugin-react is a Rust plugin, you only need to configure its package name in plugins field in farm.config.ts.

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    -

    Options

    -

    See SWC Transform React Options.

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    +

    Options

    +

    See SWC Transform React Options.

    \ No newline at end of file diff --git a/docs/plugins/official-plugins/sass/index.html b/docs/plugins/official-plugins/sass/index.html index 4e5483276..ff4ec962a 100644 --- a/docs/plugins/official-plugins/sass/index.html +++ b/docs/plugins/official-plugins/sass/index.html @@ -8,23 +8,23 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/plugin-sass

    +
    Version: 1.0.0

    @farmfe/plugin-sass

    Support Sass for Farm.

    -

    Installation

    -
    npm install @farmfe/plugin-sass
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-sass
    +

    Usage

    @farmfe/plugin-sass is a Rust plugin, you only need to configure its package name in plugins field in farm.config.ts.

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    -

    Options

    -

    additionalData

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    +

    Options

    +

    additionalData

    • Type: string
    -

    Add extra content to the head of each sass file, such as an @import '@/styles/variables.scss'; statement.

    +

    Add extra content to the head of each sass file, such as an @import '@/styles/variables.scss'; statement.

    \ No newline at end of file diff --git a/docs/plugins/official-plugins/strip/index.html b/docs/plugins/official-plugins/strip/index.html index fb36a96ad..b4e48064b 100644 --- a/docs/plugins/official-plugins/strip/index.html +++ b/docs/plugins/official-plugins/strip/index.html @@ -8,52 +8,52 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/plugin-strip

    +
    Version: 1.0.0

    @farmfe/plugin-strip

    🍣 A Farm rust plugin to remove debugger statements and functions like assert.equal and console.log from your code.

    -

    Requirements

    +

    Requirements

    This plugin requires an LTS Node version (v18.0.0+) and Farm v1.0.0+.

    -

    Installation

    -
    npm install @farmfe/plugin-strip
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-strip
    +

    Usage

    Create a farm.config.js configuration file and import the plugin:

    -
    import { defineConfig } from '@farmfe/core';
    import strip from '@farmfe/plugin-strip';

    export default defineConfig({
    // ...
    plugins: [
    [
    strip({
    // plugin options
    functions:[ 'console.*', 'assert.*' ],
    labels: ['unittest']
    })
    ]
    ],
    // ...
    });
    -

    Options

    -

    include

    +
    import { defineConfig } from '@farmfe/core';
    import strip from '@farmfe/plugin-strip';

    export default defineConfig({
    // ...
    plugins: [
    [
    strip({
    // plugin options
    functions:[ 'console.*', 'assert.*' ],
    labels: ['unittest']
    })
    ]
    ],
    // ...
    });
    +

    Options

    +

    include

    Type: String | RegExp | Array[...String|RegExp]
    Default: ['**/*.js']
    Example: include: '**/*.(mjs|js)',

    A pattern, or array of patterns, which specify the files in the build the plugin should operate on.

    -

    exclude

    +

    exclude

    Type: String | RegExp | Array[...String|RegExp]
    Default: []
    Example: exlude: 'tests/**/*',

    A pattern, or array of patterns, which specify the files in the build the plugin should ignore.

    -

    debugger

    +

    debugger

    Type: Boolean
    Default: true
    Example: debugger: false,

    If true instructs the plugin to remove debugger statements.

    -

    functions

    +

    functions

    Type: Array[...String]
    Default: [ 'console.*', 'assert.*' ]
    Example: functions: [ 'console.log', 'MyClass.Test' ],

    Specifies the functions that the plugin will target and remove.

    Note: specifying functions that are used at the begining of a chain, such as 'a().b().c()', will result in '(void 0).b().c()' which will generate an error at runtime.

    -

    labels

    +

    labels

    Type: Array[...String]
    Default: []
    Example: labels: ['unittest'],

    Specifies the labeled blocks or statements that the plugin will target and remove.

    Note: the ':' is implied and should not be specified in the config.

    -

    sourceMap

    +

    sourceMap

    Type: Boolean
    Default: true
    Example: sourceMap: false,

    -

    If true, instructs the plugin to update source maps accordingly after removing configured targets from the bundle.

    +

    If true, instructs the plugin to update source maps accordingly after removing configured targets from the bundle.

    \ No newline at end of file diff --git a/docs/plugins/official-plugins/virtual/index.html b/docs/plugins/official-plugins/virtual/index.html index 404f12301..6146b3397 100644 --- a/docs/plugins/official-plugins/virtual/index.html +++ b/docs/plugins/official-plugins/virtual/index.html @@ -8,22 +8,22 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/plugin-virtual

    +
    Version: 1.0.0

    @farmfe/plugin-virtual

    Inspired By @rollup/plugin-virtual

    A rust plugin for farm to easily use virtual module

    -

    Installation

    -
    npm install @farmfe/plugin-virtual
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-virtual
    +

    Usage

    farm.config.ts

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-virtual',
    {
    'virtual-module': 'export const a = 1',
    'src/01.js': 'export const module01 = "virtual-module"',
    },
    ],
    ],
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-virtual',
    {
    'virtual-module': 'export const a = 1',
    'src/01.js': 'export const module01 = "virtual-module"',
    },
    ],
    ],
    });

    index.js

    -
    import { a } from 'virtual-module';
    +
    import { a } from 'virtual-module';

    src/02.js

    -
    import { module01 } from './01.js';
    +
    import { module01 } from './01.js';
    \ No newline at end of file diff --git a/docs/plugins/official-plugins/yaml/index.html b/docs/plugins/official-plugins/yaml/index.html index 1a2a0b106..87be8624e 100644 --- a/docs/plugins/official-plugins/yaml/index.html +++ b/docs/plugins/official-plugins/yaml/index.html @@ -8,20 +8,20 @@ - - - + + + -
    Version: 1.0.0

    @farmfe/plugin-yaml

    +
    Version: 1.0.0

    @farmfe/plugin-yaml

    Inspired By @rollup/plugin-yaml

    🍣 A Farm plugin which Converts YAML files to ES6 modules.

    -

    Installation

    -
    npm install @farmfe/plugin-yaml
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-yaml
    +

    Usage

    farm.config.ts

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-yaml',
    {
    documentMode: 'single' | 'multi', // default single
    include: Regex, // default None,
    exclude: Regex, // default None
    },
    ],
    ],
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-yaml',
    {
    documentMode: 'single' | 'multi', // default single
    include: Regex, // default None,
    exclude: Regex, // default None
    },
    ],
    ],
    });

    notice:

    -

    include or exclude is Regex not glob For example **/01.yaml is not illegal。What is right is like ".*\\/01.yaml"

    +

    include or exclude is Regex not glob For example **/01.yaml is not illegal。What is right is like ".*\\/01.yaml"

    \ No newline at end of file diff --git a/docs/plugins/writing-plugins/js-plugin/index.html b/docs/plugins/writing-plugins/js-plugin/index.html index e0f7864a1..b30827ad6 100644 --- a/docs/plugins/writing-plugins/js-plugin/index.html +++ b/docs/plugins/writing-plugins/js-plugin/index.html @@ -8,21 +8,21 @@ - - - + + + -
    Version: 1.0.0

    Writing JavaScript Plugins

    +
    Version: 1.0.0

    Writing JavaScript Plugins

    A JavaScript plugin is simply a pure JavaScript object that defines a set of property hooks:

    -
    // farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    plugins: [
    // a plugin object
    {
    name: "my-resolve-plugin",
    priority: 1000, // the priority of this plugin, the larger the value, the earlier the execution. Normally internal plugins is 100.
    resolve: {
    filters: {
    // Only execute the hook when following conditions satisfied
    sources: ["\\./index.ts"], // a regex array
    importers: ["None"],
    },
    executor: async (param) => {
    // this hook executor
    console.log(param); // resolve params
    // return the resolve result
    return {
    resolvedPath: "virtual:my-module",
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // load, transform are similar to resolve, refer to their types
    ],
    });
    +
    // farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    plugins: [
    // a plugin object
    {
    name: "my-resolve-plugin",
    priority: 1000, // the priority of this plugin, the larger the value, the earlier the execution. Normally internal plugins is 100.
    resolve: {
    filters: {
    // Only execute the hook when following conditions satisfied
    sources: ["\\./index.ts"], // a regex array
    importers: ["None"],
    },
    executor: async (param) => {
    // this hook executor
    console.log(param); // resolve params
    // return the resolve result
    return {
    resolvedPath: "virtual:my-module",
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // load, transform are similar to resolve, refer to their types
    ],
    });

    If you want to pass args to your plugins,you can use a closure.

    -
    // my-resolve-plugin.ts
    export function myResolvePlugin(options: Options) {
    const { xx } = options;

    return {
    name: "my-resolve-plugin",
    resolve: {
    // ...
    },
    };
    }

    // farm.config.ts
    import { defineConfig } from "@farmfe/core";
    import { myResolvePlugin } from "./myResolvePlugin.ts";

    export default defineConfig({
    // ...
    plugins: [myResolvePlugin({ xx: "xx" })],
    });
    -
    note
      +
      // my-resolve-plugin.ts
      export function myResolvePlugin(options: Options) {
      const { xx } = options;

      return {
      name: "my-resolve-plugin",
      resolve: {
      // ...
      },
      };
      }

      // farm.config.ts
      import { defineConfig } from "@farmfe/core";
      import { myResolvePlugin } from "./myResolvePlugin.ts";

      export default defineConfig({
      // ...
      plugins: [myResolvePlugin({ xx: "xx" })],
      });
      +
      note
      • See Create Plugin to create a new plugin quickly based on official plugin templates.
      • This document only covers how to create, develop and publish a js plugin, for more detail about the plugin hooks, see Js Plugin Hooks.
      -

      Conventions

      +

      Conventions

      For farm specific js plugins:

      -

      Concepts

      +

      Concepts

      Before you start to write your js plugin, you should know the following concepts:

      • filters: Cause Js Plugins are much slower than Rust Plugins, your js plugin need to set explicit filters to avoid unnecessary call for js plugins hook. For example, you should set transform.filters.moduleTypes = ['js'] to make sure that the transform hook of your js plugin only runs for .js/mjs/cjs files.
      • @@ -44,27 +44,27 @@

        ConceptsFilters

        +

        Filters

        Cause Js Plugins are much slower than Rust Plugins, Farm use filters to control the execution of js plugin hooks. The plugin hook executes only when given filters matched to improve performance. filters is neccessary for some commonly used hooks, such as resolve, load, transform, etc.

        For example, if you want to transform css files, you can use transform.filters.moduleTypes = ['css'] to make sure that the transform hook of your js plugin only runs for .css files:

        -
        const myCssPlugin = {
        name: "my-css-plugin",
        transform: {
        filters: {
        // Only execute the hook when following conditions satisfied
        // resolvedPaths: ["\\./index.ts"], // a regex array to match the resolvedPaths
        moduleTypes: ["css"],
        },
        executor: async (param) => {
        // transform css
        },
        },
        };
        -

        Module Type

        +
        const myCssPlugin = {
        name: "my-css-plugin",
        transform: {
        filters: {
        // Only execute the hook when following conditions satisfied
        // resolvedPaths: ["\\./index.ts"], // a regex array to match the resolvedPaths
        moduleTypes: ["css"],
        },
        executor: async (param) => {
        // transform css
        },
        },
        };
        +

        Module Type

        In Farm, every thing is First Class Citizens, so Farm designs module_type to identify the type of a module and handle different kinds of ModuleTypes in different plugins.

        module_type returned by load hook, and can be transformed by transform hook. Farm supports js/ts/jsx/tsx, css, html, json, static assets(png, svg, etc) natively. For these module types, you can return them directly in load or transform hook directly. But if you want to handle custom module types, you may need to implement ohter hooks like parse, render_resource_pot_modules, generate resources, etc to control how to parse, render and generate resources for the custom module types.

        -
        note

        Js Plugins don't support parse, render_resource_pot_modules, generate resources hooks, you have to use Rust Plugins to handle custom module types.

        -

        Create Plugin

        +
        note

        Js Plugins don't support parse, render_resource_pot_modules, generate resources hooks, you have to use Rust Plugins to handle custom module types.

        +

        Create Plugin

        Farm provides official templates to help your create your js plugins quickly:

        -
        pnpm create farm-plugin
        +
        pnpm create farm-plugin

        then follow the prompts to create your plugin.

        or you can create a plugin derectly by running the following command:

        -
        pnpm create farm-plugin my-farm-plugin --type js
        +
        pnpm create farm-plugin my-farm-plugin --type js

        Above command will create new js plugin with name my-farm-plugin in the current directory. --type can be rust or js

        -

        Develop Plugin

        +

        Develop Plugin

        After creating the plugin, you can start to develop your plugin. The plugin is a pure JavaScript object that defines a set of property hooks:

        -
        // import { readFileSync } from 'node:fs';
        import type { JsPlugin } from '@farmfe/core';

        interface Options {
        /* Your options here */
        }

        export default function farmPlugin(options: Options): JsPlugin {
        return {
        name: '<FARM-JS-PLUGIN-NPM-NAME>',
        /* Your plugin hooks here: */

        // transform: {
        // filters: {
        // moduleTypes: ['js']
        // },
        // async executor(params) {
        // const { content } = params;
        // return {
        // content,
        // moduleType: 'js'
        // };
        // }
        // },
        // finish: {
        // executor() {}
        // }
        };
        }
        -
        tip

        For more detail about the plugin hooks, see Js Plugin Hooks.

        +
        // import { readFileSync } from 'node:fs';
        import type { JsPlugin } from '@farmfe/core';

        interface Options {
        /* Your options here */
        }

        export default function farmPlugin(options: Options): JsPlugin {
        return {
        name: '<FARM-JS-PLUGIN-NPM-NAME>',
        /* Your plugin hooks here: */

        // transform: {
        // filters: {
        // moduleTypes: ['js']
        // },
        // async executor(params) {
        // const { content } = params;
        // return {
        // content,
        // moduleType: 'js'
        // };
        // }
        // },
        // finish: {
        // executor() {}
        // }
        };
        }
        +
        tip

        For more detail about the plugin hooks, see Js Plugin Hooks.

        Run npm run dev to compile the plugin and watch for changes. Run npm run build to build the plugin.

        -

        Publish Plugin

        -

        A js plugin package is a normal npm package, you can publish it to npm registry by running npm publish.

    +

    Publish Plugin

    +

    A js plugin package is a normal npm package, you can publish it to npm registry by running npm publish.

    \ No newline at end of file diff --git a/docs/plugins/writing-plugins/overview/index.html b/docs/plugins/writing-plugins/overview/index.html index 300bff221..4762c55db 100644 --- a/docs/plugins/writing-plugins/overview/index.html +++ b/docs/plugins/writing-plugins/overview/index.html @@ -8,18 +8,18 @@ - - - + + + -
    Version: 1.0.0

    Overview

    +
    Version: 1.0.0

    Overview

    To use a Rust plugin, configuring plugins in farm.config.ts.

    -
    import { defineFarmConfig } from '@farmfe/core';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    +
    import { defineFarmConfig } from '@farmfe/core';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    Farm support both rust plugins and js plugins:

    +
    \ No newline at end of file diff --git a/docs/plugins/writing-plugins/runtime-plugin/index.html b/docs/plugins/writing-plugins/runtime-plugin/index.html index 6e389c24a..25021a667 100644 --- a/docs/plugins/writing-plugins/runtime-plugin/index.html +++ b/docs/plugins/writing-plugins/runtime-plugin/index.html @@ -8,57 +8,57 @@ - - - + + + -
    Version: 1.0.0

    Writing Runtime Plugin

    +
    Version: 1.0.0

    Writing Runtime Plugin

    A Farm runtime plugin is a pure javascript object that define a set of hooks to enhance Farm runtime. Example:

    -
    /**
    * HMR client as a Farm Runtime Plugin
    */
    import type { Plugin } from '@farmfe/runtime';
    import { createHotContext } from './hot-module-state';
    import { HmrClient } from './hmr-client';

    let hmrClient: HmrClient;
    // export a Farm runtime plugin object
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // define hooks
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    moduleCreated(module) {
    // create a hot context for each module
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };
    +
    /**
    * HMR client as a Farm Runtime Plugin
    */
    import type { Plugin } from '@farmfe/runtime';
    import { createHotContext } from './hot-module-state';
    import { HmrClient } from './hmr-client';

    let hmrClient: HmrClient;
    // export a Farm runtime plugin object
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // define hooks
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    moduleCreated(module) {
    // create a hot context for each module
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };

    Above it's a runtime plugin that supports HMR for Farm. Essentials:

    • A runtime plugin entry file should export a default object that defines a set of hooks. e.g export default <Plugin>{/*...*/}
    • name is required to identify the plugin, make sure name is unique
    • A hook is a method that defined in the exported object.
    -
    note

    See @farmfe/runtime-plugin-hmr for full implementation of above examples.

    -

    Caveat

    +
    note

    See @farmfe/runtime-plugin-hmr for full implementation of above examples.

    +

    Caveat

    You should make your runtime plugin as simple as possible. You SHOULD NOT:

    • Use big dependencies from node_modules, this would make your farm plugin very large, it's really bad for performance.
    • Use new features like top level await as these runtime related features are hard to polyfill for low level runtime.

    It's really recommended to make sure your runtime plugin as small and simple as possible.

    -
    tip

    import.meta.xxx will be compiled to module.meta.xxx, you can append values to module.meta in runtime plugins to enhance import.meta. For example, module.meta.hot = createHotContext(module.id, hmrClient) makes import.meta.hot available.

    -

    Conventions

    +
    tip

    import.meta.xxx will be compiled to module.meta.xxx, you can append values to module.meta in runtime plugins to enhance import.meta. For example, module.meta.hot = createHotContext(module.id, hmrClient) makes import.meta.hot available.

    +

    Conventions

    A Farm runtime plugin name should be prefixed by farm-runtime-plugin, e.g farm-runtime-plugin-xxx.

    -
    note

    Both plugin.name and package name(Only if you publish your plugin as a package) should be prefixed.

    -

    Using Runtime Plugins

    +
    note

    Both plugin.name and package name(Only if you publish your plugin as a package) should be prefixed.

    +

    Using Runtime Plugins

    Use compilation.runtime.plugins to configure runtime plugins for your project:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // relative path
    './src/my-plugin1.ts',
    // absolute path
    '/root/project/src/my-plugin2.ts',
    // package name
    '@scope/plugin-package-from-node-modules'
    ]
    }
    }
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // relative path
    './src/my-plugin1.ts',
    // absolute path
    '/root/project/src/my-plugin2.ts',
    // package name
    '@scope/plugin-package-from-node-modules'
    ]
    }
    }
    });

    You can configure runtime plugin item by 3 ways:

    • relative path: Path that is relative to root, e.g ./src/my-plugin1.ts will try load plugin from <root>/src/my-plugin1.ts.
    • absolute path: e.g /root/project/src/my-plugin2.ts. (Absolute path should be C:\project\src\my-plugin2.ts on windows).
    • package name: Farm will try load this package from node_modules, e.g @scope/plugin-package-from-node-modules.
    -

    Writing Runtime Plugins

    -
    tip

    Farm support loading .ts file directly, so you can configure a .ts file(or a package whose entry is a ts file) in runtime.plugins directly.

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // configuring ts file directly
    './src/my-plugin.ts',
    ]
    }
    }
    });
    -

    Create a Plugin

    +

    Writing Runtime Plugins

    +
    tip

    Farm support loading .ts file directly, so you can configure a .ts file(or a package whose entry is a ts file) in runtime.plugins directly.

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // configuring ts file directly
    './src/my-plugin.ts',
    ]
    }
    }
    });
    +

    Create a Plugin

    As we mentioned above, a Farm runtime plugin is a pure javascript object that define a set of hooks, you can just create a ts file like:

    -
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    // ...
    }
    +
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    // ...
    }

    Then define hooks you need in the exported object:

    -
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    moduleCreated(module) {
    // ...
    },
    readModuleCache(module) {
    // ...
    },
    loadResource(resource, targetEnv) {
    // ...
    },
    // ... more hooks as long as you need
    }
    -

    Debug the Plugin

    +
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    moduleCreated(module) {
    // ...
    },
    readModuleCache(module) {
    // ...
    },
    loadResource(resource, targetEnv) {
    // ...
    },
    // ... more hooks as long as you need
    }
    +

    Debug the Plugin

    Configure the plugin you created in runtime.plugins:

    -
    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    './plugins/runtime.ts',
    ]
    }
    }
    });
    +
    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    './plugins/runtime.ts',
    ]
    }
    }
    });

    Then start the Farm project, this plugin will be injected in the runtime of output resources.

    -

    Publish the Plugin(Optional)

    +

    Publish the Plugin(Optional)

    You can publish the runtime plugin to npm registry to share your Farm runtime plugin. Just create a package.json like:

    -
    {
    "name": "@farmfe/runtime-plugin-hmr",
    "version": "3.4.2",
    "description": "Runtime hmr plugin of Farm",
    "main": "src/index.ts",
    // ... ignore other fields
    }
    +
    {
    "name": "@farmfe/runtime-plugin-hmr",
    "version": "3.4.2",
    "description": "Runtime hmr plugin of Farm",
    "main": "src/index.ts",
    // ... ignore other fields
    }

    You can just export ts file using "main": "src/index.ts".

    -

    Runtime Plugin Hooks

    -

    See Runtime Plugin API

    +

    Runtime Plugin Hooks

    +

    See Runtime Plugin API

    \ No newline at end of file diff --git a/docs/plugins/writing-plugins/rust-plugin/index.html b/docs/plugins/writing-plugins/rust-plugin/index.html index c68a12941..c0b3e15a4 100644 --- a/docs/plugins/writing-plugins/rust-plugin/index.html +++ b/docs/plugins/writing-plugins/rust-plugin/index.html @@ -8,14 +8,14 @@ - - - + + + -
    Version: 1.0.0

    Writing Rust Plugins

    +
    Version: 1.0.0

    Writing Rust Plugins

    Rust plugins are the recommended way to write your plugins cause Rust plugins are much faster and powerful than Js Plugins. A Rust plugin is a struct that implements farmfe_core::plugin::Plugin trait, example:

    -
    #![deny(clippy::all)]

    use farmfe_core::{config::Config, plugin::Plugin};

    use farmfe_macro_plugin::farm_plugin;

    // define your rust plugins
    #[farm_plugin]
    pub struct FarmPluginExample {}

    impl FarmPluginExample {
    // a Rust plugin must export a new method that accepts 2 arguments for initialization。
    fn new(config: &Config, options: String) -> Self {
    Self {}
    }
    }
    // Implement Plugin trait to define plugin hooks
    impl Plugin for FarmPluginExample {
    fn name(&self) -> &str {
    "FarmPluginExample"
    }

    // more hooks here
    }
    +
    #![deny(clippy::all)]

    use farmfe_core::{config::Config, plugin::Plugin};

    use farmfe_macro_plugin::farm_plugin;

    // define your rust plugins
    #[farm_plugin]
    pub struct FarmPluginExample {}

    impl FarmPluginExample {
    // a Rust plugin must export a new method that accepts 2 arguments for initialization。
    fn new(config: &Config, options: String) -> Self {
    Self {}
    }
    }
    // Implement Plugin trait to define plugin hooks
    impl Plugin for FarmPluginExample {
    fn name(&self) -> &str {
    "FarmPluginExample"
    }

    // more hooks here
    }

    Note for a Rust plugin struct:

    • The struct must be pub and #[farm_plugin] attribute is required.
    • @@ -23,8 +23,8 @@
    • The struct must export a new method that accepts 2 arguments for initialization, the first argument is &Config and the second argument is String. The new method is called when the plugin is loaded, and the Config is the farm project config, and the String is the plugin options.

    We also provide a Rust plugin example repository: farm-rust-plugin-example.

    -
    note

    This document only covers how to create, develop and publish a rust plugin, for more detail about the plugin hooks, see Plugin Hooks.

    -

    Conventions

    +
    note

    This document only covers how to create, develop and publish a rust plugin, for more detail about the plugin hooks, see Plugin Hooks.

    +

    Conventions

    For farm specific Rust plugins:

    -

    Concepts

    +

    Concepts

    Before you start to write your rust plugin, you should know the following concepts:

    • module_type: The type of the module, it can be js, ts, css, sass, json, etc. Farm supports js/ts/jsx/tsx, css, html, json, static assets(png, svg, etc) natively. module_type is returned by load hook. You can extend natively supported module type by Rust plugins the same as Farm internal plugins.
    • @@ -45,19 +45,19 @@

      ConceptsModule Type

      +

      Module Type

      In Farm, every thing is First Class Citizens, so Farm designs module_type to identify the type of a module and handle different kinds of ModuleTypes in different plugins.

      module_type returned by load hook, and can be transformed by transform hook. Farm supports js/ts/jsx/tsx, css, html, json, static assets(png, svg, etc) natively. For these module types, you can return them directly in load or transform hook directly. But if you want to handle custom module types, you may need to implement ohter hooks like parse, render_resource_pot_modules, generate resources, etc to control how to parse, render and generate resources for the custom module types.

      -

      Create Plugin

      +

      Create Plugin

      Farm provides official templates to help your create your rust plugins quickly:

      -
      pnpm create farm-plugin
      +
      pnpm create farm-plugin

      then follow the prompts to create your plugin.

      or you can create a plugin derectly by running the following command:

      -
      pnpm create farm-plugin my-farm-plugin --type rust
      +
      pnpm create farm-plugin my-farm-plugin --type rust

      Above command will create new rust plugin with name my-farm-plugin in the current directory. --type can be rust or js

      -

      Plugin Project Structure

      +

      Plugin Project Structure

      The plugin project structure is as follows:

      -
      my-farm-plugin
      ├── .github
      │ └── workflows
      | ├── release.yml
      | ├── build.yml
      │ └── ci.yml
      ├── Cargo.toml
      |── .gitignore
      ├── npm
      │ ├── darwin-x64
      │ ├── linux-x64-gnu
      | ├── win32-x64-msvc
      │ └── ...
      ├── package.json
      ├── src
      │ └── lib.rs
      └── rust-toolchain.toml
      +
      my-farm-plugin
      ├── .github
      │ └── workflows
      | ├── release.yml
      | ├── build.yml
      │ └── ci.yml
      ├── Cargo.toml
      |── .gitignore
      ├── npm
      │ ├── darwin-x64
      │ ├── linux-x64-gnu
      | ├── win32-x64-msvc
      │ └── ...
      ├── package.json
      ├── src
      │ └── lib.rs
      └── rust-toolchain.toml

      Notable files and directories:

      • src/lib.rs: The main file of the plugin, where you define your plugin.
      • @@ -68,49 +68,49 @@

        Plu
      • rust-toolchain.toml: The rust toolchain file, it should not be modified manually, it should always using the same version as the farm core.

      Farm provides a tool(@farmfe/plugin-tools) to help you build and publish your rust plugin, see package.json:

      -
      {
      // ...
      "scripts": {
      // build your plugin for current platform
      "build": "farm-plugin-tools build --platform --cargo-name my_farm_plugin -p my_farm_plugin --release",
      // publish all platform packages under npm directory to npm registry
      "prepublishOnly": "farm-plugin-tools prepublish"
      },
      // ...
      }
      +
      {
      // ...
      "scripts": {
      // build your plugin for current platform
      "build": "farm-plugin-tools build --platform --cargo-name my_farm_plugin -p my_farm_plugin --release",
      // publish all platform packages under npm directory to npm registry
      "prepublishOnly": "farm-plugin-tools prepublish"
      },
      // ...
      }

      More detail about building and publishing your plugin, see buidling and publishing sections.

      -

      Develop Plugin

      +

      Develop Plugin

      To develop and test your plugin locally, you should build your plugin for your platform first, run:

      -
      pnpm build
      +
      pnpm build

      Then you can use the built plugin in your farm project by adding the plugin to the plugins field in farm.config.ts:

      -
      import { defineConfig } from '@farmfe/core';

      export default defineConfig({
      plugins: [
      'my-farm-plugin'
      ]
      });
      +
      import { defineConfig } from '@farmfe/core';

      export default defineConfig({
      plugins: [
      'my-farm-plugin'
      ]
      });

      and execute pnpm i in your farm project, and run farm start to start your farm project with your plugin.

      when you make changes to your plugin, you should rebuild your plugin and restart your farm project to see the changes. for example, add load hook to your plugin:

      -
      src/lib.rs
      // ... ignore other code

      impl Plugin for FarmPluginExample {
      fn name(&self) -> &str {
      "FarmPluginExample"
      }

      fn load(
      &self,
      param: &farmfe_core::plugin::PluginLoadHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
      println!(
      "load path: {:?}, id: {:?}",
      param.resolved_path, param.module_id
      );
      Ok(None)
      }
      }
      +
      src/lib.rs
      // ... ignore other code

      impl Plugin for FarmPluginExample {
      fn name(&self) -> &str {
      "FarmPluginExample"
      }

      fn load(
      &self,
      param: &farmfe_core::plugin::PluginLoadHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
      println!(
      "load path: {:?}, id: {:?}",
      param.resolved_path, param.module_id
      );
      Ok(None)
      }
      }

      Then rebuild your plugin with pnpm build and restart your farm project with farm start, you will see the load hook is called when compiling your farm project.

      -
      note

      For more detail about the plugin hooks, see Plugin Hooks.

      -

      Handle ModuleType

      +
      note

      For more detail about the plugin hooks, see Plugin Hooks.

      +

      Handle ModuleType

      module_type is returned by the load hook or transform hook. Your set any module type to the module in the load hook, and the module will be processed by the corresponding plugin that supports the module type.

      For native supported module types, you can just return the module type in the load hook:

      -
      src/lib.rs
      // ... ignore other code

      impl Plugin for FarmPluginExample {
      fn name(&self) -> &str {
      "FarmPluginExample"
      }

      fn load(
      &self,
      param: &farmfe_core::plugin::PluginLoadHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
      // handle virtual module
      if param.module_id.starts_with("virtual:my-css:css") {
      // return module type and content
      Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
      module_type: "css".to_string(),
      content: ".red { color: red; }".to_string(),
      ..Default::default()
      }))
      } else {
      Ok(None)
      }
      }
      }
      +
      src/lib.rs
      // ... ignore other code

      impl Plugin for FarmPluginExample {
      fn name(&self) -> &str {
      "FarmPluginExample"
      }

      fn load(
      &self,
      param: &farmfe_core::plugin::PluginLoadHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
      // handle virtual module
      if param.module_id.starts_with("virtual:my-css:css") {
      // return module type and content
      Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
      module_type: "css".to_string(),
      content: ".red { color: red; }".to_string(),
      ..Default::default()
      }))
      } else {
      Ok(None)
      }
      }
      }

      For non-native supported module types, you should use transform hook to transform the module type to a native supported module type, otherwise you need to implement parse, renderResourcePot hook to handle your custom module type:

      -
      src/lib.rs
      // ... ignore other code

      impl Plugin for FarmPluginExample {
      fn name(&self) -> &str {
      "FarmPluginExample"
      }

      fn transform(
      &self,
      param: &farmfe_core::plugin::PluginTransformHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
      // module type guard is required
      if matches!(param.module_type, ModuleType::Custom("sass")) {
      // compile sass and transform the module type from sass to css
      Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
      module_type: "css".to_string(),
      content: compileSass(param.content),
      ..Default::default()
      }))
      } else {
      Ok(None)
      }
      }
      }
      -
      note

      Module type guard like matches!(param.module_type, ModuleType::Custom("sass")) is required in the transform hook, cause the transform hook will be called for all module types, and you should only handle your custom module type in the transform hook. So do the parse and other hooks.

      +
      src/lib.rs
      // ... ignore other code

      impl Plugin for FarmPluginExample {
      fn name(&self) -> &str {
      "FarmPluginExample"
      }

      fn transform(
      &self,
      param: &farmfe_core::plugin::PluginTransformHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
      // module type guard is required
      if matches!(param.module_type, ModuleType::Custom("sass")) {
      // compile sass and transform the module type from sass to css
      Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
      module_type: "css".to_string(),
      content: compileSass(param.content),
      ..Default::default()
      }))
      } else {
      Ok(None)
      }
      }
      }
      +
      note

      Module type guard like matches!(param.module_type, ModuleType::Custom("sass")) is required in the transform hook, cause the transform hook will be called for all module types, and you should only handle your custom module type in the transform hook. So do the parse and other hooks.

      or implement parse, render_resource_pot_modules hook to handle your custom module type, see how native farm css plugin handle css module type in farm-plugin-css.

      -

      Handle Plugin Options

      +

      Handle Plugin Options

      The rust plugin options can be configured in farm.config.ts:

      -
      import { defineConfig } from '@farmfe/core';

      export default defineConfig({
      plugins: [
      ['my-farm-plugin', {
      // plugin options
      myOption: 'myOption'
      }]
      ]
      });
      +
      import { defineConfig } from '@farmfe/core';

      export default defineConfig({
      plugins: [
      ['my-farm-plugin', {
      // plugin options
      myOption: 'myOption'
      }]
      ]
      });

      The Option will be json serialized and passed to the new method of your plugin, you can handle the options in the new method:

      -
      src/lib.rs
      // ... ignore other code

      // define your rust plugin options
      #[derive(serde::Deserialize)]
      pub struct Options {
      pub my_option: Option<String>,
      }

      impl FarmPluginExample {
      fn new(config: &Config, options: String) -> Self {
      // deserialize the options
      let my_option: Options = serde_json::from_str(&options).unwrap();
      // handle the options...
      Self {}
      }
      }
      +
      src/lib.rs
      // ... ignore other code

      // define your rust plugin options
      #[derive(serde::Deserialize)]
      pub struct Options {
      pub my_option: Option<String>,
      }

      impl FarmPluginExample {
      fn new(config: &Config, options: String) -> Self {
      // deserialize the options
      let my_option: Options = serde_json::from_str(&options).unwrap();
      // handle the options...
      Self {}
      }
      }

      Note that you should add dependencies serde and serde_json to your Cargo.toml to support options deserialization:

      -
      [dependencies]
      # ... ignore other code
      serde = { version = "1.0", features = ["derive"] }
      serde_json = "1.0"
      -
      note

      Non json serializable options are not supported. Which means you can only use types like string, number, boolean, array, object, etc. function options are not supported.

      -

      Using farm_core In Plugin

      +
      [dependencies]
      # ... ignore other code
      serde = { version = "1.0", features = ["derive"] }
      serde_json = "1.0"
      +
      note

      Non json serializable options are not supported. Which means you can only use types like string, number, boolean, array, object, etc. function options are not supported.

      +

      Using farm_core In Plugin

      Farm exposes all core structures and utilities in farmfe_core crate. Refer to the farmfe_core documentation for more detail.

      -
      note

      If you want to use swc structures like Module, Program, etc. in your plugin, you should use farmfe_core::swc_ast that re-exposed by farm core. Cause the swc version used by farm core may be different from the swc version you used in your plugin, and the swc version used by farm core is guaranteed to be compatible with farm core.

      -

      Caveats

      -

      Using SWC In Plugin

      +
      note

      If you want to use swc structures like Module, Program, etc. in your plugin, you should use farmfe_core::swc_ast that re-exposed by farm core. Cause the swc version used by farm core may be different from the swc version you used in your plugin, and the swc version used by farm core is guaranteed to be compatible with farm core.

      +

      Caveats

      +

      Using SWC In Plugin

      Note that your rust plugin should not use any SWC related packages like swc_common, swc_transforms, etc. Cause SWC stores the global state in the process, it may cause dead lock when you use SWC in your plugin.

      Farm recommended to write SWC Plugin if you want to make changes to the AST of your farm project. For how to write SWC plugin, see Write SWC Plugin.

      -

      Choosing Rust toolchain

      +

      Choosing Rust toolchain

      Cause Farm Rust Plugin is a dynamic linked library, you should always use the same version of the rust toolchain as the farm core. The rust toolchain is defined in rust-toolchain.toml, it should not be modified manually. And should should always build your plugin from Rust, cause Farm Core does not support FFI and not promise ABI stability to provide best performance.

      -

      Plugin Compatibility

      +

      Plugin Compatibility

      Farm core maintains a API version that exposes to the plugin. If you met a message like Incompatible Rust Plugin: Current core's version..., it means your plugin is not compatible with the current farm core version. You should update your plugin to the latest version to fix the issue.

      For plugin authors, you should rebuild and publish your plugin for the latest farm core version to make your plugin compatible with the latest farm core version.

      -
      note

      Farm promises API Compatibility for the same major version, for example, if your plugin is compatible with farm core 1.0.0, it should also be compatible with farm core 1.1.0, 1.2.0, etc. which means your plugin will always work for the same major version of farm.

      -

      Cross Build

      +
      note

      Farm promises API Compatibility for the same major version, for example, if your plugin is compatible with farm core 1.0.0, it should also be compatible with farm core 1.1.0, 1.2.0, etc. which means your plugin will always work for the same major version of farm.

      +

      Cross Build

      A Farm Rust Plugin is a platform specific dynamic linked library, you should build your plugin for all platforms you want to support. Farm provided a example for how to build your plugin using github actions, see .github/workflows/build.yml

      By default, A farm rust plugin should be built for the following platforms:

      @@ -126,8 +126,8 @@

      Cross Buildwin32-arm64-msvc

    For a public plugin that published to npm registry, we recommend you to publish your plugin for all platforms above. For a private rust plugin, you can build your plugin for any platform you want to support.

    -
    tip

    Cause a rust plugin is a pure dynamic linked library, if you have questions about how to build your plugin for a specific platform, just google how to build a dynamic linked library for that platform in Rust.

    -

    Publish

    +
    tip

    Cause a rust plugin is a pure dynamic linked library, if you have questions about how to build your plugin for a specific platform, just google how to build a dynamic linked library for that platform in Rust.

    +

    Publish

    Steps to publish your Rust plugin:

    1. Cross build the Rust plugin to dynamic linked library, see Cross Build for detail.
    2. @@ -136,25 +136,25 @@

      Publishgithub actions publish workflow

      -

      Examples

      +

      Examples

      We will use @farmfe/plugin-sass as demostration to a real Rust plugin example. This plugin will support compiling .scss and .sass file in your farm project.

      -

      Define Plugin

      +

      Define Plugin

      Exports a Rust struct named FarmPluginSass.

      -
      src/lib.rs
      use farmfe_macro_plugin::farm_plugin;

      // 1. define a struct with #[farm_plugin] attribute
      #[farm_plugin]
      pub struct FarmPluginSass {
      sass_options: String,
      regex: Regex,
      }

      impl FarmPluginSass {
      // 2. define a new method with 2 arguments
      pub fn new(_config: &Config, options: String) -> Self {
      Self {
      sass_options: options,
      regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
      }
      }
      }
      +
      src/lib.rs
      use farmfe_macro_plugin::farm_plugin;

      // 1. define a struct with #[farm_plugin] attribute
      #[farm_plugin]
      pub struct FarmPluginSass {
      sass_options: String,
      regex: Regex,
      }

      impl FarmPluginSass {
      // 2. define a new method with 2 arguments
      pub fn new(_config: &Config, options: String) -> Self {
      Self {
      sass_options: options,
      regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
      }
      }
      }
      • The struct must be pub and #[farm_plugin] attribute is required.
      • The struct must export a new method that accepts 2 arguments for initialization, the first argument is &Config and the second argument is String.
      -

      Implement Plugin Trait

      +

      Implement Plugin Trait

      Plugin trait is used to define hooks that can hook into Farm compiler.

      -
      use farmfe_core::plugin::Plugin;
      use farmfe_macro_plugin::farm_plugin;

      // 1. define a struct with #[farm_plugin] attribute
      #[farm_plugin]
      pub struct FarmPluginSass {
      sass_options: String,
      regex: Regex,
      }

      impl FarmPluginSass {
      // 2. define a new method with 2 arguments
      pub fn new(_config: &Config, options: String) -> Self {
      Self {
      sass_options: options,
      regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
      }
      }
      }
      // Implement Plugin Trait
      impl Plugin for FarmPluginSass {
      fn name(&self) -> &str {
      "FarmPluginSass"
      }

      // this plugin should be executed before internal plugins
      fn priority(&self) -> i32 {
      101
      }
      }
      -

      Load .scss File

      +
      use farmfe_core::plugin::Plugin;
      use farmfe_macro_plugin::farm_plugin;

      // 1. define a struct with #[farm_plugin] attribute
      #[farm_plugin]
      pub struct FarmPluginSass {
      sass_options: String,
      regex: Regex,
      }

      impl FarmPluginSass {
      // 2. define a new method with 2 arguments
      pub fn new(_config: &Config, options: String) -> Self {
      Self {
      sass_options: options,
      regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
      }
      }
      }
      // Implement Plugin Trait
      impl Plugin for FarmPluginSass {
      fn name(&self) -> &str {
      "FarmPluginSass"
      }

      // this plugin should be executed before internal plugins
      fn priority(&self) -> i32 {
      101
      }
      }
      +

      Load .scss File

      Implement load hook to support load .scss files.

      -
      // ignore other code ...

      // Implement Plugin Trait
      impl Plugin for FarmPluginSass {
      fn name(&self) -> &str {
      "FarmPluginSass"
      }

      // this plugin should be executed before internal plugins
      fn priority(&self) -> i32 {
      101
      }

      fn load(
      &self,
      param: &farmfe_core::plugin::PluginLoadHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
      if param.query.is_empty() && self.regex.is_match(param.resolved_path) {
      let content = fs::read_file_utf8(param.resolved_path);

      if let Ok(content) = content {
      return Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
      content,
      module_type: ModuleType::Custom(String::from("sass")),
      }));
      }
      }

      Ok(None)
      }
      }
      +
      // ignore other code ...

      // Implement Plugin Trait
      impl Plugin for FarmPluginSass {
      fn name(&self) -> &str {
      "FarmPluginSass"
      }

      // this plugin should be executed before internal plugins
      fn priority(&self) -> i32 {
      101
      }

      fn load(
      &self,
      param: &farmfe_core::plugin::PluginLoadHookParam,
      _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      _hook_context: &farmfe_core::plugin::PluginHookContext,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
      if param.query.is_empty() && self.regex.is_match(param.resolved_path) {
      let content = fs::read_file_utf8(param.resolved_path);

      if let Ok(content) = content {
      return Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
      content,
      module_type: ModuleType::Custom(String::from("sass")),
      }));
      }
      }

      Ok(None)
      }
      }

      In the load hook, we only read the file that ends with .scss or .sass, return the file content and maked its module_type as ModuleType::Custom(String::from("sass")).

      -

      Transform sass File

      +

      Transform sass File

      After we load the .scss file, we need to transform it to css in transform hook, then Farm will treat it as css in following process.

      -
      // ignore other code ...
      fn transform(
      &self,
      param: &farmfe_core::plugin::PluginTransformHookParam,
      context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
      // module type guard is neccessary
      if param.module_type == ModuleType::Custom(String::from("sass")) {
      // ... ignore other code

      // parse options
      const options = parse_options(&self.options, param.module_id);
      // compile sass to css
      let compile_result = compileSass(&param.content, options);

      return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
      content: compile_result.css,
      source_map: compile_result.source_map,
      // tell farm compiler that we have transformed this module to css
      module_type: Some(farmfe_core::module::ModuleType::Css),
      ignore_previous_source_map: false,
      }));
      }

      Ok(None)
      }
      -
      tip

      This example only covers how to implement a transformer plugin. For more abilities that Farm support, refer to Plugin Hooks.

    +
    // ignore other code ...
    fn transform(
    &self,
    param: &farmfe_core::plugin::PluginTransformHookParam,
    context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
    ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
    // module type guard is neccessary
    if param.module_type == ModuleType::Custom(String::from("sass")) {
    // ... ignore other code

    // parse options
    const options = parse_options(&self.options, param.module_id);
    // compile sass to css
    let compile_result = compileSass(&param.content, options);

    return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
    content: compile_result.css,
    source_map: compile_result.source_map,
    // tell farm compiler that we have transformed this module to css
    module_type: Some(farmfe_core::module::ModuleType::Css),
    ignore_previous_source_map: false,
    }));
    }

    Ok(None)
    }
    +
    tip

    This example only covers how to implement a transformer plugin. For more abilities that Farm support, refer to Plugin Hooks.

    \ No newline at end of file diff --git a/docs/quick-start/index.html b/docs/quick-start/index.html index 435ec67d8..3a7419471 100644 --- a/docs/quick-start/index.html +++ b/docs/quick-start/index.html @@ -8,40 +8,40 @@ - - - + + + -
    Version: 1.0.0

    Quick Start

    -
    note

    Farm needs Node 16.18.0 and above.

    -

    Online experience

    -

    Edit Farm

    -

    Create a Farm Project

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    -
    Then follow the prompts!

    You can also directly specify the project name and the template you want to use via additional command line options:

    -
    npm
    yarn
    pnpm
    bun
    npm create farm farm-app --template react
    -

    2. Start the Project

    +
    Version: 1.0.0

    Quick Start

    +
    note

    Farm needs Node 16.18.0 and above.

    +

    Online experience

    +

    Edit Farm

    +

    Create a Farm Project

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +
    Then follow the prompts!

    You can also directly specify the project name and the template you want to use via additional command line options:

    +
    npm
    yarn
    pnpm
    bun
    npm create farm farm-app --template react
    +

    2. Start the Project

    Choose the package manager you like, install dependencies, then start the project. Then, start the project:

    -
    npm
    yarn
    pnpm
    bun
    cd farm-app && npm install && npm start
    +
    npm
    yarn
    pnpm
    bun
    cd farm-app && npm install && npm start

    The project will start at http://localhost:9000 by default.

    -

    3. Configuring the Project

    +

    3. Configuring the Project

    The project is configured by farm.config.ts/js/mjs file in the root directory of the project.

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // Options related to the compilation
    compilation: {
    input: {
    // can be a relative path or an absolute path
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Options related to the dev server
    server: {
    port: 9000,
    // ...
    },
    // Additional plugins
    plugins: [],
    });
    -
    note

    See Configuring Farm for details.

    -

    4. Building the project

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // Options related to the compilation
    compilation: {
    input: {
    // can be a relative path or an absolute path
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Options related to the dev server
    server: {
    port: 9000,
    // ...
    },
    // Additional plugins
    plugins: [],
    });
    +
    note

    See Configuring Farm for details.

    +

    4. Building the project

    Build the Farm project as production-ready static files:

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    The built product is downgraded to ES2017 by default, and the product will be compressed and Tree Shake. If you want to preview the build product locally, you can execute npm run preview or npx farm preview.

    -
    note

    See Build For Production for details.

    -

    Next Steps

    +
    note

    See Build For Production for details.

    +

    Next Steps

    -
    +
    \ No newline at end of file diff --git a/docs/tutorials/build/index.html b/docs/tutorials/build/index.html index 197df76a7..3929902a8 100644 --- a/docs/tutorials/build/index.html +++ b/docs/tutorials/build/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 1.0.0

    Build For Production

    +
    Version: 1.0.0

    Build For Production

    By default, Farm has enabled support for the following features for production builds:

    • Tree Shake: Crop and filter irrelevant modules and code
    • @@ -21,23 +21,23 @@
    • Automatically inject Polyfill: Farm downgrades to modern browsers(ES7) by default, if you need legacy browsers support, configuring targetEnv
    • Automatic partial packaging: Based on dependencies and size, the project is partially bundled. For each resource request, about 25 resources are generated to ensure parallel loading performance and improve cache hits rate as much as possible.
    -

    Configuring Output Dir

    +

    Configuring Output Dir

    Add build script in package.json:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build",
    "preview": "farm preview"
    },
    // ...ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build",
    "preview": "farm preview"
    },
    // ...ignore other fields
    }

    Then execute npm run build, the built resources will be emitted to build dir:

    -
    build
    ├─ favicon.ico
    ├─ index.html
    ├─ index_02bc.bd68e90b.js
    ├─ index_02bc.bd68e90b.js.map
    ├─ index_1c74.4b50f73e.js
    ├─ index_7734.440d56a3.js
    ├─ index_880b.4631ecee.js
    ├─ index_8d49.63f7b906.css
    ├─ index_8d49.63f7b906.css.map
    ├─ index_9025.84e1f8e6.js
    ├─ index_ca37.f2c276ef.js
    ├─ index_ef2f.e25349d8.js
    ├─ index_f346.369a7312.js
    +
    build
    ├─ favicon.ico
    ├─ index.html
    ├─ index_02bc.bd68e90b.js
    ├─ index_02bc.bd68e90b.js.map
    ├─ index_1c74.4b50f73e.js
    ├─ index_7734.440d56a3.js
    ├─ index_880b.4631ecee.js
    ├─ index_8d49.63f7b906.css
    ├─ index_8d49.63f7b906.css.map
    ├─ index_9025.84e1f8e6.js
    ├─ index_ca37.f2c276ef.js
    ├─ index_ef2f.e25349d8.js
    ├─ index_f346.369a7312.js

    If you want to custom the path that the resources emitted to, you can use:

    -
    import defineConfig from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    path: 'build',
    filename: 'assets/[name].[hash].[ext]',
    assetsFilename: 'static/[resourceName].[ext]'
    }
    }
    })
    +
    import defineConfig from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    path: 'build',
    filename: 'assets/[name].[hash].[ext]',
    assetsFilename: 'static/[resourceName].[ext]'
    }
    }
    })

    For above example, all js/css will be emitted to build/assets/(example: build/assets/index-ea54.abbe3e.js). All static assets like image will be emitted to build/static(example: build/static/background.png)

    -

    Preview Built Resources

    +

    Preview Built Resources

    After the resources built, you can preview them by npm run preview:

    -
    $ npm run preview

    > 3-build@1.0.0 preview
    > farm preview

    [ Farm ] Using config file at /root/tutorials/3-build-for-production/farm.config.ts
    [ Farm ] preview server running at:

    [ Farm ] > Local: http://localhost:1911/
    [ Farm ] > Network: http://198.18.0.1:1911/
    [ Farm ] > Network: http://10.242.197.146:1911/
    [ Farm ] > Network: http://192.168.1.31:1911/
    +
    $ npm run preview

    > 3-build@1.0.0 preview
    > farm preview

    [ Farm ] Using config file at /root/tutorials/3-build-for-production/farm.config.ts
    [ Farm ] preview server running at:

    [ Farm ] > Local: http://localhost:1911/
    [ Farm ] > Network: http://198.18.0.1:1911/
    [ Farm ] > Network: http://10.242.197.146:1911/
    [ Farm ] > Network: http://192.168.1.31:1911/

    open http://localhost:1911/ to preview your project.

    -

    Browser Compatibility

    +

    Browser Compatibility

    By default, Farm build projects to Modern Browsers that natively support async/await:

    • Chrome >= 62
    • @@ -46,22 +46,22 @@

      Browse
    • Edge >= 79

    You can use output.targetEnv to configuring your target browsers:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    targetEnv: 'browser-legacy'
    }
    }
    })
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    targetEnv: 'browser-legacy'
    }
    }
    })

    In above example, Farm will downgrade the syntax to es5 and inject polyfill automatically. Then we have to install core-js@3 to polyfill injection:

    -
    pnpm add -D core-js@3
    -
    note
      +
      pnpm add -D core-js@3
      +
      note
      • You need to install core-js@3 manually if your target to legacy browsers.
      • If you want to configure browsers targets more precisely, see Syntax Downgrade And Polyfill
      -

      Configure Tree Shake and Minify

      +

      Configure Tree Shake and Minify

      Production optimization like treeShake and minify are disabled by default in development for performance reasons, and enabled by default in production. But if treeShake or minify are configured manually, the default value will be used regardless of development or production.

      For details about tree shake and minify, see:

      -

      Configure Partial Bundling

      -
      note

      Refer to Partial Bundling for details.

      -

      Farm enabled best practice of bundling already, make sure you really need to configure bundles manually. See Partial Bundling for details.

    +

    Configure Partial Bundling

    +
    note

    Refer to Partial Bundling for details.

    +

    Farm enabled best practice of bundling already, make sure you really need to configure bundles manually. See Partial Bundling for details.

    \ No newline at end of file diff --git a/docs/tutorials/create/index.html b/docs/tutorials/create/index.html index cb3f3638a..584146b23 100644 --- a/docs/tutorials/create/index.html +++ b/docs/tutorials/create/index.html @@ -8,35 +8,35 @@ - - - + + + -
    Version: 1.0.0

    Create A Project

    +
    Version: 1.0.0

    Create A Project

    In this chapter, we will create a new Farm React project from scratch, and launch it in development mode.

    -
    note

    In this tutorial, we use pnpm as default package manager. This chapter is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm. See Quick Start.

    -

    Create A Package

    +
    note

    In this tutorial, we use pnpm as default package manager. This chapter is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm. See Quick Start.

    +

    Create A Package

    First we execute pnpm init to create a new package.

    -
    mkdir farm-react && cd farm-react && pnpm init
    +
    mkdir farm-react && cd farm-react && pnpm init

    A package.json file will be autogenerated.

    -

    Install Dependencies

    +

    Install Dependencies

    Install necessary dependencies:

    react and react-dom:

    -
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D
    +
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D

    farm related dependencies:

    -
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react
    +
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react

    There are 3 packages that are necessary for a react project:

    • @farmfe/cli: This package provides commands like farm start, farm build, farm preview, it must be used with @farmfe/core and can not be used separately.
    • @farmfe/core: This package provides Compilation and Dev Server abilities, provides all necessary component for local development and product build. It exports Compiler, DevServer and Watcher, which is used for compile the project, serve the project in development mode and watch the project for Hot Module Replacement.
    • @farmfe/plugin-react: This package provides abilities for React Jsx compilation, and react-refresh support.
    -

    Create Farm Config File

    +

    Create Farm Config File

    Create a farm.config.ts file under project root:

    -
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml
    +
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml

    and add following configuration:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });

    For configuration file above, we use input, output and plugins, which is the most basic configuration in Farm.

    • input: Configure the entry point. Farm will compile and build a module graph from the entries.
    • @@ -44,20 +44,20 @@

      Crea
    • plugins: Configure farm plugins, all extended abilities like React, Vue SFC are supported by plugins. Here we use a Rust Plugin(@farmfe/plugin-react) to support compiling React jsx.

    Check Configuring Farm for more options.

    -
    note

    In above example, we config input as index: './src/index.html', if we do not configure input, it's default to index: './index.html'. And we can configure multiple entries in input, see Multi Page App for details

    -

    Create A Entry Html and Tsx File

    +
    note

    In above example, we config input as index: './src/index.html', if we do not configure input, it's default to index: './index.html'. And we can configure multiple entries in input, see Multi Page App for details

    +

    Create A Entry Html and Tsx File

    Create 2 files src/index.html and src/index.tsx under project root:

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx

    Content of src/index.html is:

    -
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    -
    note

    Note that we must add at least one <script> to refer to a script module.

    +
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    +
    note

    Note that we must add at least one <script> to refer to a script module.

    Content of src/index.tsx is:

    -
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    -

    Start Your Farm Project!

    +
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    +

    Start Your Farm Project!

    Now every thing is ready, add a start script to your package.json:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }

    then run npm start, if farm output following messages, means your project are launched successfully:

    -
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    -

    Open http://localhost:9000 in browser.

    +
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    +

    Open http://localhost:9000 in browser.

    \ No newline at end of file diff --git a/docs/tutorials/overview/index.html b/docs/tutorials/overview/index.html index 028d82995..59fcd2674 100644 --- a/docs/tutorials/overview/index.html +++ b/docs/tutorials/overview/index.html @@ -8,14 +8,14 @@ - - - + + + -
    Version: 1.0.0

    Overview

    +
    Version: 1.0.0

    Overview

    In this tutorial, we will create a Farm react project from scratch, and introducing how to add useful component libraries and Farm plugins.

    -
    note

    Vue project is also fully supported by Farm. You can directly use Vite's @vitejs/plugin-vue in Farm. Farm is compatible with most vite plugins and can use them out of box.

    +
    note

    Vue project is also fully supported by Farm. You can directly use Vite's @vitejs/plugin-vue in Farm. Farm is compatible with most vite plugins and can use them out of box.

    you will learn:

    • How to build a production ready Farm React project from scratch. We will introduce how to add popular component library
    • @@ -23,13 +23,13 @@
    • Farm's daily configurations and commonly used plugins.

    We aim to make you familiar quickly with Farm concepts and ecosystem through this tutorial. And it can also be helpful if you want to migrate from other tools to Farm.

    -
    note

    This tutorial is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm. See Quick Start

    +
    note

    This tutorial is build a Farm react project from scratch, If you are trying to init a new Farm Project rapidly, use our official template with command pnpm create farm. See Quick Start

    Following our tutorial, and open your super-fast Farm develop journey!

    -
    note

    The source code of this tutorial is in farm tutorials

    +
    note

    The source code of this tutorial is in farm tutorials

    \ No newline at end of file diff --git a/docs/tutorials/start/index.html b/docs/tutorials/start/index.html index 0c2d90359..61091ffc2 100644 --- a/docs/tutorials/start/index.html +++ b/docs/tutorials/start/index.html @@ -8,96 +8,96 @@ - - - + + + -
    Version: 1.0.0

    Develop With Farm

    +
    Version: 1.0.0

    Develop With Farm

    In this chapter, we will introduce commonly used configuration and plugins to help you build complex production-ready web project with Farm.

    -
    note

    This chapter reuse the project we created in chapter 1

    +
    note

    This chapter reuse the project we created in chapter 1

    We'll setup our project step by step:

    1. Introduce popular component library antd, and configure necessary plugins for it
    2. Introduce commonly used plugins like postcss, svgr, less and so on.
    3. Configure proxies and other useful dev server options
    -

    Introduce Component Library

    +

    Introduce Component Library

    A component library is often necessary when develop a web project, in this section, we will use ant-design as a demo to show How to add component libraries in Farm.

    We use ant design here only for illustration, you can introduce any component library. Farm does not have objection.

    First we need to install ant-design into our project:

    -
    pnpm add antd # execute under project root
    +
    pnpm add antd # execute under project root

    Ant Design needs Sass, so we also need to install plugins for compiling scss. We can use @farmfe/plugin-sass which is a Rust Plugin officially provided by Farm:

    -
    pnpm add @farmfe/plugin-sass -D
    +
    pnpm add @farmfe/plugin-sass -D

    Then add this plugin to plugins:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: ["@farmfe/plugin-react", "@farmfe/plugin-sass"],
    });
    +
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: ["@farmfe/plugin-react", "@farmfe/plugin-sass"],
    });

    Now Antd is ready, add it to our project:

    -
    import React from "react";
    import { createRoot } from "react-dom/client";

    import { DatePicker } from "antd";

    const container = document.querySelector("#root");
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm. antd DatePicker: <DatePicker />
    </div>
    );
    +
    import React from "react";
    import { createRoot } from "react-dom/client";

    import { DatePicker } from "antd";

    const container = document.querySelector("#root");
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm. antd DatePicker: <DatePicker />
    </div>
    );

    Then execute npm start and open http://localhost:9000 in browser:

    -

    Styling the Project

    +

    Styling the Project

    Now we have successfully introduced a component library into our project. Next we'll learn how to styling.

    -

    Create a Basic Admin Site Layout

    +

    Create a Basic Admin Site Layout

    First we create a new app.tsx next to index.tsx:

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx

    Content of app.tsx(It's demo code from official site of Antd):

    -
    app.tsx
    import React from "react";
    import { Breadcrumb, Layout, Menu, theme } from "antd";

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: "flex", alignItems: "center" }}>
    <div className="demo-logo" />
    <Menu
    theme="dark"
    mode="horizontal"
    defaultSelectedKeys={["2"]}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: "0 50px" }}>
    <Breadcrumb style={{ margin: "16px 0" }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div
    className="site-layout-content"
    style={{ background: colorBgContainer }}
    >
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: "center" }}>
    Ant Design ©2023 Created by Ant UED
    </Footer>
    </Layout>
    );
    };

    export default App;
    +
    app.tsx
    import React from "react";
    import { Breadcrumb, Layout, Menu, theme } from "antd";

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: "flex", alignItems: "center" }}>
    <div className="demo-logo" />
    <Menu
    theme="dark"
    mode="horizontal"
    defaultSelectedKeys={["2"]}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: "0 50px" }}>
    <Breadcrumb style={{ margin: "16px 0" }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div
    className="site-layout-content"
    style={{ background: colorBgContainer }}
    >
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: "center" }}>
    Ant Design ©2023 Created by Ant UED
    </Footer>
    </Layout>
    );
    };

    export default App;

    Then modify index.tsx as:

    -
    index.tsx
    import React from "react";
    import { createRoot } from "react-dom/client";

    import App from "./app";
    // import { DatePicker } from 'antd';

    const container = document.querySelector("#root");
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );
    +
    index.tsx
    import React from "react";
    import { createRoot } from "react-dom/client";

    import App from "./app";
    // import { DatePicker } from 'antd';

    const container = document.querySelector("#root");
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );

    Then we get a Basic admin layout:

    -

    Styling With Css Modules

    +

    Styling With Css Modules

    Farm supports css modules out of box, by default, Farm will treat any .module.(css|scss|less) as css modules. Firstly we create a app.module.scss:

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx

    Content of app.module.scss:

    -
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }
    +
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }

    Then import app.module.scss in app.tsx and save it:

    -
    import styles from "./app.module.scss";
    // ...
    +
    import styles from "./app.module.scss";
    // ...

    Then your page should be updated like below:

    -

    Using Css Preprocessor

    +

    Using Css Preprocessor

    Farm provided official js plugins for postcss(@farmfe/js-plugin-postcss) and less(@farmfe/js-plugin-less) (We have already installed rust plugin sass(@farmfe/plugin-sass) above).

    To use postcss, First we need to install the plugin:

    -
    pnpm add -D @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/js-plugin-postcss

    then configure it in plugins of farm.config.ts:

    -
    farm.config.ts
    // ...
    import farmPluginPostcss from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ... ignore other fields
    plugins: ["@farmfe/plugin-react", "@farmfe/plugin-sass", farmPluginPostcss()],
    });
    +
    farm.config.ts
    // ...
    import farmPluginPostcss from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ... ignore other fields
    plugins: ["@farmfe/plugin-react", "@farmfe/plugin-sass", farmPluginPostcss()],
    });

    Now postcss is fully supported in Farm, you can use popular postcss plugins tailwind, px2rem, etc. We won't cover postcss details here, refer to postcss docs for more details.

    -
    tip

    Refer to Farm Plugins to learn more about Farm plugins.

    -

    Using Public Directory

    +
    tip

    Refer to Farm Plugins to learn more about Farm plugins.

    +

    Using Public Directory

    For assets that don't need compilation, you can put them under public directory. Add a favicon.ico under public:

    -
    .
    ├── ...
    └── public
    └── favicon.icon
    +
    .
    ├── ...
    └── public
    └── favicon.icon

    Then the favicon is available for your website. And you can also put some static assets that can be directly fetched, for example, images:

    -
    .
    ├── ...
    └── public
    ├── favicon.icon
    └── images
    └── background.png
    +
    .
    ├── ...
    └── public
    ├── favicon.icon
    └── images
    └── background.png

    then you can use /images/background.png to fetch the image, for example, <img src="/images/background.png">.

    -
    note

    Using config option publicDir to custom your public directory.

    -

    Configuring publicPath

    +
    note

    Using config option publicDir to custom your public directory.

    +

    Configuring publicPath

    Use compilation.output.publicPath to configuring url prefix for dynamic resources loading and when inject <script> and <link> tags into html. We add following config in farm.config.ts

    -
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    output: {
    publicPath:
    process.env.NODE_ENV === "production" ? "https://cdn.com" : "/",
    },
    },
    // ...
    });
    +
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    output: {
    publicPath:
    process.env.NODE_ENV === "production" ? "https://cdn.com" : "/",
    },
    },
    // ...
    });

    When building, the injected resources url would be https://cdn.com/index-s2f3.s14dqwa.js. For example, in your output html, all <script> and <link> would be:

    -
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>
    +
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>

    and when loading dynamic scripts and css, the dynamic fetched resources url would also be: https://cdn.com/<asset-path>

    -

    Configuring Alias And Externals

    +

    Configuring Alias And Externals

    Alias and externals are also most useful configurations, we can use compilation.resolve.alias and compilation.externals in Farm:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "@/": path.join(process.cwd(), "src"),
    },
    },
    externals: ["node:fs"],
    },
    // ...
    });
    -

    Configuring DevServer

    +
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "@/": path.join(process.cwd(), "src"),
    },
    },
    externals: ["node:fs"],
    },
    // ...
    });
    +

    Configuring DevServer

    You can find server configuration in Farm Dev Server Options.

    -

    Useful Configuration

    +

    Useful Configuration

    Example configuration:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // All dev server options are under server
    server: {
    open: true,
    port: 9001,
    hmr: {
    // Configure the port for web socket listening
    port: 9801
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // All dev server options are under server
    server: {
    open: true,
    port: 9001,
    hmr: {
    // Configure the port for web socket listening
    port: 9801
    // Configure the host for web socket listening
    host: 'localhost',
    // Files to ignore when configuring file monitoring
    ignores: ['auto_generated/*']
    }
    //...
    }
    });

    For above examples, we used following options:

    • open: open the browser with specified port automatically
    • port: set the dev sever port to 9001
    • hmr: set the hmr port and watched files, we ignores file changes under auto_generated directory.
    -

    Setup Proxy

    +

    Setup Proxy

    Configure server proxy. farm uses http-proxy as a proxy for the development server. Based on http-proxy implementation, specific options refer to its documentation, example:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    -

    Configuring root and envDir

    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    +

    Configuring root and envDir

    Use root and envDir to specify your project root and the directory to load env variables. Add following options in farm.config.ts:

    -
    farm.config.ts
    import path from "node:path";
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: path.join(process.cwd(), "client"),
    envDir: "my-env-dir",
    });
    -
    note

    For details about envDir, see Environment Variables and Modes

    +
    farm.config.ts
    import path from "node:path";
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: path.join(process.cwd(), "client"),
    envDir: "my-env-dir",
    });
    +
    note

    For details about envDir, see Environment Variables and Modes

    \ No newline at end of file diff --git a/docs/using-plugins/index.html b/docs/using-plugins/index.html index e13892270..9c2beecbf 100644 --- a/docs/using-plugins/index.html +++ b/docs/using-plugins/index.html @@ -8,12 +8,12 @@ - - - + + + -
    Version: 1.0.0

    Using Plugins

    +
    Version: 1.0.0

    Using Plugins

    There are 4 kinds of plugins supported in Farm:

    • Farm Compilation Plugins: Support both Rust Plugins and Js Plugins, which adopt a rollup-style hooks.
    • @@ -22,66 +22,66 @@
    • Swc Plugins: Swc plugins are supported in Farm out of Box.

    Farm adopt Vite/Rollup ecosystem, Vite/Rollup Plugins can be used directly in Farm.

    -
    tip

    For how to write your own plugins, refer to Writing Plugins

    -

    Farm Compilation Plugins

    +
    tip

    For how to write your own plugins, refer to Writing Plugins

    +

    Farm Compilation Plugins

    First, install the plugins your need, for example:

    -
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss

    Using plugins to configure Farm compilation plugins:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    // Js plugin, configure the plugin object
    farmPostcssPlugin()
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    // Js plugin, configure the plugin object
    farmPostcssPlugin()
    ],
    });

    There are 2 kinds of Farm compilation plugins:

    • Rust Plugins: which is written in Rust and has best performance.
    • Js Plugins: which is written in JS/TS, and it's used for compatibility with current JS ecosystem
    -

    Using Rust Plugins

    +

    Using Rust Plugins

    Using package name to configure a Rust Plugin, for example:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // Rust plugin, configure its package name
    "@farmfe/plugin-sass",
    ],
    });

    For above example, Farm will resolve package @farmfe/plugin-sass and treat it as a Farm Rust Plugin.

    If you want to configure options for rust plugins, you can use array syntax like [packageName, optionsObject], for example:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // using array syntax to configure a rust plugin
    [
    // rust plugin's name
    "@farmfe/plugin-sass",
    // rust plugin's options
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // using array syntax to configure a rust plugin
    [
    // rust plugin's name
    "@farmfe/plugin-sass",
    // rust plugin's options
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });

    Currently Farm supports 2 rust plugins officially:

    • @farmfe/plugin-react: Farm rust plugin for react jsx compilation and react-refresh injection.
    • @farmfe/plugin-sass: Farm rust plugin for scss files compilation, uses sass-embedded internally.
    -
    tip

    To learn more about rust plugins, see Rust Plugins

    -

    Using Js Plugins

    +
    tip

    To learn more about rust plugins, see Rust Plugins

    +

    Using Js Plugins

    Farm JS plugin is a JS object with methods as hooks, for example:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    farmPostcssPlugin({
    // ... configure postcss options
    })
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    farmPostcssPlugin({
    // ... configure postcss options
    })
    ],
    });

    farmPostcssPlugin() returns a plugin object, and you can pass any postcss options by its arguments.

    You can use priority to control the order of your plugins, for example:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    // Js plugin, configure the plugin object
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });

    priority of internal plugin are 100, if you want the plugin execute first, set it larger than 100, otherwise set it smaller than 100.

    If you want to add a Farm JS plugin quickly, you can just configure a plugin object:

    -
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // configure a custom plugin
    {
    // plugin name, required
    name: 'my-first-farm-plugin',
    // this priority of this plugin, bigger value will be executed first, default to 100.
    priority: 1000,
    // define a load hook to determine how to load a more
    load: {
    // to improve performance, modules will be skipped if they don't match the filters.
    filters: {
    // only be executed for .png files.
    resolvedPaths: ['\\.png$']
    },
    // executor callback for this hook
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    -
    note

    filters is required in Farm for js plugins. Because Js Plugin is really slow and we should avoid executing it as much as possible. For those modules that don't match the filters, Farm won't trigger js plugin hook for them at all! Which means Farm can handle them only on Rust side safely and concurrently.

    -
    tip

    To learn more about Farm Js Plugins, refer to JS Plugin

    -

    Using Vite/Rollup/Unplugin Plugins In Farm

    +
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // configure a custom plugin
    {
    // plugin name, required
    name: 'my-first-farm-plugin',
    // this priority of this plugin, bigger value will be executed first, default to 100.
    priority: 1000,
    // define a load hook to determine how to load a more
    load: {
    // to improve performance, modules will be skipped if they don't match the filters.
    filters: {
    // only be executed for .png files.
    resolvedPaths: ['\\.png$']
    },
    // executor callback for this hook
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    +
    note

    filters is required in Farm for js plugins. Because Js Plugin is really slow and we should avoid executing it as much as possible. For those modules that don't match the filters, Farm won't trigger js plugin hook for them at all! Which means Farm can handle them only on Rust side safely and concurrently.

    +
    tip

    To learn more about Farm Js Plugins, refer to JS Plugin

    +

    Using Vite/Rollup/Unplugin Plugins In Farm

    Farm supports Vite plugins out of Box. First you need to install vite plugins,for example:

    -
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D
    +
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D

    Then you can use vite plugins directly by vitePlugins in farm.config.ts.

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });

    To improve performance of vite plugins, you can use function syntax that returns a filters, for example:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // Using function syntax of Vite plugin
    function configureVitePluginVue() {
    // return plugin and its filters
    return {
    // using plugin vue
    vitePlugin: vue(),
    // configuring filters for it. Unmatched module paths will be skipped.
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    configureVitePluginVue
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // Using function syntax of Vite plugin
    function configureVitePluginVue() {
    // return plugin and its filters
    return {
    // using plugin vue
    vitePlugin: vue(),
    // configuring filters for it. Unmatched module paths will be skipped.
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    // configuring vite plugins
    vitePlugins: [
    configureVitePluginVue
    ]
    });

    Using unplugin:

    -
    pnpm add unplugin-auto-import unplugin-vue-components -D
    +
    pnpm add unplugin-auto-import unplugin-vue-components -D

    configuring unplugin in vitePlugins via unplugin/vite or unplugin/rollup:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    -
    note

    Currently you can use unplugin/vite or unplugin/rollup. unplugin/farm will be available as soon as this unplugin PR merged.

    -

    Farm Runtime Plugin

    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    +
    note

    Currently you can use unplugin/vite or unplugin/rollup. unplugin/farm will be available as soon as this unplugin PR merged.

    +

    Farm Runtime Plugin

    Farm has a runtime module system to control how to load and execute modules. Configuring compilation.runtime.plugins to add more runtime plugin, for example:

    -
    export default defineConfig({
    compilation: {
    // configure Farm runtime module system
    runtime: {
    plugins: [
    // a runtime plugin package
    require.resolve('farm-plugin-runtime-mock'),
    // a local runtime plugin
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });
    +
    export default defineConfig({
    compilation: {
    // configure Farm runtime module system
    runtime: {
    plugins: [
    // a runtime plugin package
    require.resolve('farm-plugin-runtime-mock'),
    // a local runtime plugin
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });

    you have to configure a path that point to your runtime plugin's entry. Recommend to a absolute path to avoid path issue.

    -
    tip

    To learn more about runtime plugin refer to Runtime Plugin

    -

    Using SWC Plugins

    +
    tip

    To learn more about runtime plugin refer to Runtime Plugin

    +

    Using SWC Plugins

    Swc Plugin can also be used directly in Farm, Configuring compilation.script.plugins to add SWC plugins, for example:

    -
    import jsPluginVue from '@farmfe/js-plugin-vue';

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [{
    // the package name of the swc plugin
    name: 'swc-plugin-vue-jsx',
    // options of this swc plugin
    options: {
    "transformOn": true,
    "optimize": true
    },
    // plugin execute when the filters are matched.
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    };
    +
    import jsPluginVue from '@farmfe/js-plugin-vue';

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [{
    // the package name of the swc plugin
    name: 'swc-plugin-vue-jsx',
    // options of this swc plugin
    options: {
    "transformOn": true,
    "optimize": true
    },
    // plugin execute when the filters are matched.
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    };

    Each plugin item of the array contains three fields:

    • name: the package name of the swc plugin
    • options: Configuration items passed to swc plugin
    • filters: Which modules to execute the plug-in, must be configured, support resolvedPaths and moduleTypes these two filter items, if both are specified at the same time, take the union.
    -
    note

    SWC plugin may not be compatible with the SWC version(rust crate swc_core v0.90) that Farm uses. If a error occurred, try upgrade the plugin version.

    +
    note

    SWC plugin may not be compatible with the SWC version(rust crate swc_core v0.90) that Farm uses. If a error occurred, try upgrade the plugin version.

    \ No newline at end of file diff --git a/docs/why-farm/index.html b/docs/why-farm/index.html index 103b96cea..eb3d5143e 100644 --- a/docs/why-farm/index.html +++ b/docs/why-farm/index.html @@ -8,15 +8,15 @@ - - - + + + -
    Version: 1.0.0

    Why Farm?

    -

    What is Farm?

    +
    Version: 1.0.0

    Why Farm?

    +

    What is Farm?

    Farm is an extremely fast Rust-based web build tool, like webpack and vite, but much faster. Farm resolves, loads, and transforms all of your assets(js/jsx/ts/tsx, css/sass/less, html, static assets, json, etc), and bundle them into a set of deployable files. Farm is an extremely fast build tool that helps you build faster web/nodejs apps.

    -

    Why Farm?

    +

    Why Farm?

    As web projects scale, build performance has been their major bottleneck. For a huge project compiling with webpack may cost 10 or more minutes and an HMR update may cost 10s or more, heavily reducing development efficiency.

    Then, tools like Vite came out. It uses native ESM and is unbundled for source files in dev mode, pre-bundles dependencies using esbuild, which makes the dev server launch and the HMR very fast.

    But Unbundled is not perfect, there are still big problems when comes to a large project:

    @@ -28,7 +28,7 @@

    Why Farm?

    So I think we just need a fast, powerful, consistent web bundler, which can solve the problems above and fast, then I designed and implemented Farm.

    And Farm is not just a normal bundler re-written in Rust, it has a lot of powerful and progressive designs:

    -

    Farm Design Philosophy

    +

    Farm Design Philosophy

    • Performance first: Everything will be written in Rust for as long as we can; only several parts which are not the performance bottleneck will be written in JS.
    • Consistency first: Make sure that development and production are exactly the same by default. What you see in development will be the same as what you get in production.
    • @@ -37,6 +37,6 @@

      Farm
    • Compatibility: Farm will work with both legacy (ES5) and modern browsers.
    • Rollup style plugin system and vite/rollup compatible js-plugins: Easy to create your own plugins and easy to migrate your plugins/projects from rollup/vite. Support both Rust and JS plugins.
    -

    Farm's goal is to be the real next generation build tool, inherit all advantages from existing tools, and to be fast, powerful, consistent, and provide the best development experience for web developers.

    +

    Farm's goal is to be the real next generation build tool, inherit all advantages from existing tools, and to be fast, powerful, consistent, and provide the best development experience for web developers.

    \ No newline at end of file diff --git a/index.html b/index.html index 5e62cdbd6..49ac5fda2 100644 --- a/index.html +++ b/index.html @@ -8,11 +8,11 @@ - - - + + + -
    ⭐️
    Give Star with Farm Github

    ExtremelyWeb
    Written in

    is a Rust-Based Web Building Engine to Facilitate Your Web Program and JavaScript Library

    Extremely Fast

    Written in Rust, start a React / Vue project in milliseconds and perform an HMR update within 10ms for most situations.

    Incremental Building

    Incremental Building: Support persistent cache, module level cache enabled by default, any module won't be compiled twice until it's changed!

    Rich Features

    Farm support compiling Html, Css, Css Modules, Js/Jsx/Ts/Tsx, Json, Static Assets out of box, support sass, less, postcss, vue, react, solid by official plugins, support lazy compiling, partial bundling and more

    Fully Pluggable and Vite Compatible

    Everything inside Farm is powered by plugins, Supports both Rust and JavaScript plugins. Support Vite plugins out of box.

    Partial Bundling

    Partial Bundling: Bundle your project into a few reasonable bundles, speeding up resource loading without losing caching granularity.

    Consistency and Compatibility

    What you see in development will be the same as what you get in production. Supports both legacy (ES5) and modern browsers.

    +
    ⭐️
    Give Star with Farm Github

    ExtremelyWeb
    Written in

    is a Rust-Based Web Building Engine to Facilitate Your Web Program and JavaScript Library

    Extremely Fast

    Written in Rust, start a React / Vue project in milliseconds and perform an HMR update within 10ms for most situations.

    Incremental Building

    Incremental Building: Support persistent cache, module level cache enabled by default, any module won't be compiled twice until it's changed!

    Rich Features

    Farm supports compiling HTML, CSS, CSS Modules, Js/Jsx/Ts/Tsx, JSON, Static Assets out of the box, supports Sass, Less, PostCSS, Vue, React, Solid by way of official plugins, supports lazy compiling, partial bundling and more

    Fully Pluggable and Vite Compatible

    Everything inside Farm is powered by plugins, Supports both Rust and JavaScript plugins. Support Vite plugins out of box.

    Partial Bundling

    Partial Bundling: Bundle your project into a few reasonable bundles, speeding up resource loading without losing caching granularity.

    Consistency and Compatibility

    What you see in development will be the same as what you get in production. Supports both legacy (ES5) and modern browsers.

    \ No newline at end of file diff --git a/markdown-page/index.html b/markdown-page/index.html index 821e54e9a..90b794c7d 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -8,12 +8,12 @@ - - - + + + -

    Markdown page example

    +

    Markdown page example

    You don't need React to write simple standalone pages.

    \ No newline at end of file diff --git a/search/index.html b/search/index.html index 46f52379c..681f52ce8 100644 --- a/search/index.html +++ b/search/index.html @@ -8,11 +8,11 @@ - - - + + + -

    Search the documentation

    +

    Search the documentation

    \ No newline at end of file diff --git a/team/index.html b/team/index.html index 3241f82e8..cb692eb1a 100644 --- a/team/index.html +++ b/team/index.html @@ -8,11 +8,11 @@ - - - + + + -
    brightwu

    brightwu

    @bytedance

    Author/Lead Maintainer of @farm-fe. Rust && TS && Java..

    Erkelost

    Erkelost

    Rust & Go & Node & Web development ❤️❤️

    shulandmimi

    shulandmimi

    Core team member of Farm.

    Nirvana-Jie

    Nirvana-Jie

    @bytedance

    There are too many things to learn, I can only keep moving forward.

    NidMo

    NidMo

    Core team member of Farm.

    wjq990112

    wjq990112

    Member of @raxjs, @ice-lab and @farm-fe.

    callqh

    callqh

    Javascript & Rust.

    oblador

    oblador

    ╥━━━━━━━━╭━━╮━━┳ ╢╭╮╭━━━━━┫┃▋▋━▅┣ ╢┃╰┫┈┈┈┈┈┃┃┈┈╰┫┣ ╢╰━┫┈┈┈┈┈╰╯╰┳━╯┣ ╢┊┊┃┏┳┳━━┓┏┳┫┊┊┣ ╨━━┗┛┗┛━━┗┛┗┛━━┻

    ysy945

    ysy945

    Core team member of Farm.

    NaturelLee

    NaturelLee

    Core team member of Farm.

    Cherry7

    Cherry7

    @bytedance

    Core team member of Farm & Ant Design Vue.

    +
    brightwu

    brightwu

    @bytedance

    Author/Lead Maintainer of @farm-fe. Rust && TS && Java..

    Erkelost

    Erkelost

    Rust & Go & Node & Web development ❤️❤️

    shulandmimi

    shulandmimi

    Core team member of Farm.

    Nirvana-Jie

    Nirvana-Jie

    @bytedance

    There are too many things to learn, I can only keep moving forward.

    NidMo

    NidMo

    Core team member of Farm.

    wjq990112

    wjq990112

    Member of @raxjs, @ice-lab and @farm-fe.

    callqh

    callqh

    Javascript & Rust.

    oblador

    oblador

    ╥━━━━━━━━╭━━╮━━┳ ╢╭╮╭━━━━━┫┃▋▋━▅┣ ╢┃╰┫┈┈┈┈┈┃┃┈┈╰┫┣ ╢╰━┫┈┈┈┈┈╰╯╰┳━╯┣ ╢┊┊┃┏┳┳━━┓┏┳┫┊┊┣ ╨━━┗┛┗┛━━┗┛┗┛━━┻

    ysy945

    ysy945

    Core team member of Farm.

    NaturelLee

    NaturelLee

    Core team member of Farm.

    Cherry7

    Cherry7

    @bytedance

    Core team member of Farm & Ant Design Vue.

    \ No newline at end of file diff --git a/zh/404.html b/zh/404.html index 580d00925..30ce30808 100644 --- a/zh/404.html +++ b/zh/404.html @@ -8,11 +8,11 @@ - - - + + + -

    找不到页面

    我们找不到您要找的页面。

    请联系原始链接来源网站的所有者,并告知他们链接已损坏。

    +

    找不到页面

    我们找不到您要找的页面。

    请联系原始链接来源网站的所有者,并告知他们链接已损坏。

    \ No newline at end of file diff --git a/zh/assets/css/styles.a7c2456e.css b/zh/assets/css/styles.71429604.css similarity index 91% rename from zh/assets/css/styles.a7c2456e.css rename to zh/assets/css/styles.71429604.css index f493c0b50..ee787255d 100644 --- a/zh/assets/css/styles.a7c2456e.css +++ b/zh/assets/css/styles.71429604.css @@ -1 +1 @@ -@import url(https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown.css);@import url(https://rsms.me/inter/inter.css);.col,.container{padding:0 var(--ifm-spacing-horizontal)}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,.tab_J4Y8{-webkit-user-select:none}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}html[data-theme=dark],html[data-theme=light]{--ifm-menu-color-active:var(--ifm-color-primary-text);--admonition-note-c-color:#ff9ff3;--admonition-code-note-c-bg:#ff9ff350}.theme-admonition,:root{--ifm-alert-color:var(--ifm-font-color-base)}.theme-admonition-note,.theme-admonition-warning{--admonition-bar-c-bg:var(--admonition-bar-note-c-bg);--admonition-link-c:var(--admonition-link-note-c)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50,.from-transparent{--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.bg-fuchsia-600,.bg-gray-100,.bg-gray-500,.bg-neutral-100,.bg-zinc-950{--tw-bg-opacity:1}.toggleButton_IoGO,html{-webkit-tap-highlight-color:transparent}.dark,:root{--dm-mask-bg-color:#656c85cc;--dm-highlight-color:var(--dm-color-brand)}*,.DocSearch-Container,.DocSearch-Container *,.tab_J4Y8{box-sizing:border-box}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--doc-sidebar-width:17.5rem;--dropdown-icon-width:0.625rem;--dropdown-icon-height:0.375rem;--dropdown-icon-gap:0.688rem;--ifm-menu-link-padding-vertical:0.5rem;--sidebar-spacing-horizontal:1.5rem;--ifm-menu-color-background-hover:#0000}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_h4wM{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.items-center,.menuExternalLink_UU74,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width);width:100%}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size);inherit:unset}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList_DbQE{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration);color:#c44cac}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_tb_L .wordWrapButtonIcon_M_ov{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.admonitionHeading_rz2u code,.btn_bvfa{text-transform:none}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover,.enter-to[data-v-3926b6c7],.hash-link:focus,.leave-from[data-v-3926b6c7],:hover>.hash-link{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button,.flex-grow{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_dqoy:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;pointer-events:none;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;transform:translateY(-50%);top:4px}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}:root,[data-theme=dark]{--ifm-footer-background-color:#181818}.footer__links,.mb-4{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color)}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_bY4Y article>:first-child,.docItemContainer_bY4Y header+*,.footer__item{margin-top:0}.admonitionContent_hXXP>:last-child,.collapsibleContent_SYrp p:last-child,.details_Erfu>summary>p:last-child,.footer__items,.tabItem_iV9q>:last-child{margin-bottom:0}[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_Dxmf{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_Erfu[data-collapsed=false].isBrowser_bjSw>summary:before,.details_Erfu[open]:not(.isBrowser_bjSw)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;top:0;bottom:0;visibility:hidden;left:0}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.after\:blur-\[var\(--after-blur\)\]:after,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.flex,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_DkJa,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.h-full,.navbar__logo img,body,html{height:100%}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}#nprogress,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}:root,[data-theme=dark],html[data-theme=light]{--ifm-menu-color-background-active:#ff9ff330}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.DocSearch-Button,.DocSearch-Link,.DocSearch-Prefill,.DocSearch-Reset,.cursor-pointer,.dropdownNavbarItemMobile_viHK,.hover\:cursor-pointer:hover,.pills__item,.tab_J4Y8,.tabs__item{cursor:pointer}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.overflow-x-auto,.tabs{overflow-x:auto}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover,.shadow-\[inset_0_-8px_10px_\#8fdfff1f\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.group:hover .group-hover\:translate-x-0\.5,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.inline-flex,.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_DV6A>li)>.containsTaskList_DV6A{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.transition,.transition-all,.transition-shadow,.transition-transform{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--sidebar-category-c:var(--c-gray-0);--sidebar-border-c:var(--c-gray-90);--ifm-menu-color:var(--c-gray-20);--note-color:#e3e3e3;--admonition-tip-border:var(--c-green-50);--admonition-tip-color:var(--c-green-50);--admonition-note-c-bg:#0000;--admonition-info-c-bg:#0000;--admonition-tip-c-bg:#0000;--admonition-warning-c-bg:#0000;--admonition-caution-c-bg:#0000;--admonition-danger-c-bg:#0000;--admonition-info-c-color:var(--c-blue-50);--admonition-tip-c-color:var(--c-green-50);--admonition-warning-c-color:var(--c-yellow-50);--admonition-caution-c-color:var(--c-orange-50);--admonition-danger-c-color:var(--c-red-50);--ifm-alert-tip-background-color:var(--c-green-50-a);--admonition-code-warning-c-bg:var(--c-yellow-50-a);--admonition-code-info-c-bg:#00163d;--admonition-code-tip-c-bg:#003d11;--admonition-code-caution-c-bg:#3d1200;--admonition-code-danger-c-bg:#3d0003;--ifm-alert-warning-background-color:var(--c-yellow-30-a);--c-brand:#ff73ec90;--c-yellow-50:#f9d76f;--c-yellow-50-a:#ffd75a60;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.302);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}html[data-theme=light]{--sidebar-category-c:var(--c-gray-100);--sidebar-border-c:var(--c-gray-0);--ifm-menu-color:var(--c-indigo-80);--note-color:#241800;--admonition-note-c-bg:linear-gradient(to bottom,var(--ifm-alert-note-background-color),#0000 40%);--admonition-info-c-bg:linear-gradient(to bottom,var(--ifm-alert-info-background-color),#0000 40%);--admonition-tip-c-bg:linear-gradient(to bottom,var(--ifm-alert-tip-background-color),#0000 40%);--admonition-warning-c-bg:linear-gradient(to bottom,var(--ifm-alert-warning-background-color),#0000 40%);--admonition-caution-c-bg:linear-gradient(to bottom,var(--ifm-alert-caution-background-color),#0000 40%);--admonition-danger-c-bg:linear-gradient(to bottom,var(--ifm-alert-danger-background-color),#0000 40%);--admonition-info-c-color:inherit;--admonition-tip-c-color:inherit;--admonition-warning-c-color:inherit;--admonition-caution-c-color:inherit;--admonition-danger-c-color:inherit;--admonition-code-info-c-bg:var(--c-teal-20);--admonition-code-warning-c-bg:var(--c-yellow-20);--admonition-code-tip-c-bg:var(--c-green-20);--admonition-code-caution-c-bg:var(--c-orange-20);--admonition-code-danger-c-bg:var(--c-red-10);--admonition-tip-border:var(--c-green-100);--admonition-tip-color:var(--c-green-100);--ifm-alert-warning-background-color:var(--c-yellow-10);--ifm-alert-tip-background-color:var(--c-green-10);--ifm-alert-danger-background-color:var(--c-red-10);--ifm-alert-note-background-color:#ff9ff360;--ifm-alert-info-background-color:var(--c-teal-10);--ifm-alert-caution-background-color:var(--c-green-10)}[class^=docRoot_]{width:1440px!important}.links_A3uT,.sp-link_GRPb,[class^=docsWrapper_]{display:flex;justify-content:center}#__docusaurus .theme-doc-sidebar-container{background:var(--token-primary-bg-c);border-inline-end:1px solid var(--sidebar-border-c);bottom:0;height:calc(100vh - 60px);margin-block-start:0;position:sticky;top:60px;will-change:auto}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a{align-items:center;display:flex;height:var(--ifm-navbar-height)}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a,#__docusaurus [class^=sidebar_]{padding-inline-end:var(--sidebar-spacing-horizontal);padding-inline-start:var(--sidebar-spacing-horizontal)}#__docusaurus [class^=sidebar_]{max-height:100vh;overflow-y:auto;padding-block-start:1rem;position:static}#__docusaurus [class^=sidebar_]>.menu{overflow-x:initial;padding-block-end:2rem;padding:0}#__docusaurus [class^=sidebarLogo]{display:none!important}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list,.codeBlockStandalone_VnB1,.p-0{padding:0}#__docusaurus .menu__list{transition:height .35s cubic-bezier(.36,.66,.04,1) 25ms!important;will-change:auto!important}#__docusaurus .menu__list .menu__list .menu__link--sublist{margin-inline-start:calc((var(--dropdown-icon-width) + var(--dropdown-icon-gap))*-1)}#__docusaurus .menu__list .menu__list .menu__link--sublist:after,.header-github-link:hover{opacity:.6}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1{padding-inline-start:calc(var(--dropdown-icon-width))}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1>.menu__link{color:var(--sidebar-category-c);font-size:14px;font-weight:500}#__docusaurus .menu__list-item:not(:first-child){margin-block-start:0}#__docusaurus .menu__list-item .menu__list .menu__link{padding-inline-start:calc(var(--dropdown-icon-width) + var(--dropdown-icon-gap));padding:7px 10px}#__docusaurus .menu__list-item-collapsible,.block{display:block}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list>.menu__list-item:last-of-type{padding-block-end:.5rem}#__docusaurus .theme-doc-sidebar-item-category-level-1:last-of-type{margin-block-end:.5rem}#__docusaurus .menu__link{align-items:center;display:flex;font-size:.85rem;font-weight:500;letter-spacing:-.01em;line-height:16px;transition:opacity .2s ease-out}#__docusaurus .menu__link:not(.menu__link--active:not(.menu__link--sublist)){background:initial}#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):active,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):focus,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):hover{opacity:.7}#__docusaurus .menu__link--sublist{align-items:center;display:flex;flex-direction:row-reverse;justify-content:flex-end;margin-block-end:0;padding-inline-end:0;padding-inline-start:0}#__docusaurus .menu__link--sublist:after{background:var(--ifm-menu-link-sublist-icon) center/var(--dropdown-icon-width) var(--dropdown-icon-height);background-repeat:no-repeat;height:var(--dropdown-icon-height);margin-block-end:0;margin-inline-end:var(--dropdown-icon-gap);margin-inline-start:unset;min-width:auto;width:var(--dropdown-icon-width)}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list-item-collapsible .menu__link{color:var(--sidebar-category-c);font-size:.938rem;font-weight:600;line-height:100%}html[data-theme=light] body{--angle:220deg;background-attachment:fixed;background-image:linear-gradient(var(--angle),#fff 15%,rgba(255,159,243,.376) 20%,#fff 25%,#f4eef8 30%,#fff 35%,#f8edf5 40%,#fff 60%);background-size:cover}.theme-admonition{border:none;position:relative;--ifm-alert-padding-horizontal:2rem;--ifm-alert-padding-vertical:1.5rem}.theme-admonition [class^=admonitionHeading_]{font-size:1rem;line-height:1.6;text-transform:capitalize}.theme-admonition [class^=admonitionHeading_] [class^=admonitionIcon_]{display:none}.theme-admonition [class^=admonitionContent_] p a{color:var(--admonition-link-c);text-decoration:underline}.theme-admonition [class^=admonitionContent_] p code{background:var(--admonition-code-c-bg)}.theme-admonition-warning{--admonition-code-c-bg:var(--admonition-code-warning-c-bg);background:#0000;border:2px solid var(--c-yellow-90-a);color:var(--c-yellow-90)}.theme-admonition-note{--admonition-code-c-bg:var(--admonition-code-note-c-bg);background:#0000;border:2px solid var(--c-brand-a);color:var(--c-brand)}.theme-admonition-info{--ifm-alert-background-color:var(--c-teal-210);--admonition-bar-c-bg:var(--admonition-bar-info-c-bg);--admonition-code-c-bg:var(--admonition-code-info-c-bg);--admonition-link-c:var(--admonition-link-info-c);background:#0000;border:2px solid var(--c-teal-60);color:var(--c-teal-90)}.theme-admonition-tip{--admonition-bar-c-bg:var(--admonition-bar-tip-c-bg);--admonition-code-c-bg:var(--admonition-code-tip-c-bg);--admonition-link-c:var(--admonition-link-tip-c);background:#0000;border:2px solid var(--admonition-tip-border);color:var(--admonition-tip-color)}.theme-admonition-caution{--ifm-alert-background-color:var(--admonition-caution-c-bg);--admonition-bar-c-bg:var(--admonition-bar-caution-c-bg);--admonition-code-c-bg:var(--admonition-code-caution-c-bg);--admonition-link-c:var(--admonition-link-caution-c);background:#0000}.theme-admonition-danger,.theme-admonition-important{--admonition-bar-c-bg:var(--admonition-bar-danger-c-bg);--admonition-code-c-bg:var(--admonition-code-danger-c-bg);--admonition-link-c:var(--admonition-link-danger-c)}.theme-admonition-danger{--ifm-alert-background-color:var(--admonition-danger-c-bg);background:#0000;border:2px solid var(--c-red-50-a);color:var(--c-red-50)}.theme-admonition-important{--ifm-alert-background-color:var(--c-lavender-210);background:linear-gradient(to bottom,var(--ifm-alert-background-color),#0000);border:2px solid var(--c-lavender-220)}:root{--admonition-bar-note-c-bg:var(--c-yellow-80);--admonition-bar-info-c-bg:var(--c-blue-80);--admonition-bar-tip-c-bg:var(--c-green-80);--admonition-bar-caution-c-bg:var(--c-orange-80);--admonition-bar-danger-c-bg:var(--c-red-60);--admonition-link-note-c:var(--c-brand);--admonition-link-info-c:var(--c-teal-90);--admonition-link-tip-c:var(--c-green-60);--admonition-color-tip-c:var(--note-color);--admonition-color-note-c:var(--note-color);--admonition-link-caution-c:var(--c-orange-90);--admonition-link-danger-c:var(--c-red-60);--c-black:#000;--c-white:#fff;--c-blue-0:#f0f6ff;--c-blue-10:#e3edff;--c-blue-20:#cddfff;--c-blue-30:#b2ceff;--c-blue-40:#97bdff;--c-blue-50:#7cabff;--c-blue-60:#639bff;--c-blue-70:#4d8dff;--c-blue-80:#3880ff;--c-blue-90:#176bff;--c-blue-100:#0054e9;--c-blue-110:#004dd6;--c-blue-120:#0046c1;--c-blue-130:#003fae;--c-blue-140:#00389b;--c-blue-150:#002d7c;--c-blue-160:#002669;--c-blue-170:#001d52;--c-blue-180:#001740;--c-blue-190:#00112f;--c-blue-200:#000b1f;--c-gray-0:#f3f3f3;--c-gray-10:#e4e4e4;--c-gray-20:#c8c8c8;--c-gray-30:#aeaeae;--c-gray-40:#959595;--c-gray-50:#818181;--c-gray-60:#6d6d6d;--c-gray-70:#5f5f5f;--c-gray-80:#474747;--c-gray-90:#2f2f2f;--c-gray-100:#141414;--c-carbon-0:#eef1f3;--c-carbon-10:#d7dde2;--c-carbon-20:#b4bcc6;--c-carbon-30:#98a2ad;--c-carbon-40:#7d8894;--c-carbon-50:#677483;--c-carbon-60:#556170;--c-carbon-70:#434f5e;--c-carbon-80:#35404e;--c-carbon-90:#222d3a;--c-carbon-100:#03060b;--c-indigo-0:#fbfbfd;--c-indigo-10:#f6f8fc;--c-indigo-20:#e9edf3;--c-indigo-30:#dee3ea;--c-indigo-40:#ced6e0;--c-indigo-50:#b2becd;--c-indigo-60:#92a0b3;--c-indigo-70:#73849a;--c-indigo-80:#445b78;--c-indigo-90:#2d4665;--c-indigo-100:#001a3a;--c-green-0:#f1fdf5;--c-green-10:#deffe7;--c-green-20:#c7fbd5;--c-green-30:#a7f1bb;--c-green-40:#80e89d;--c-green-50:#62e085;--c-green-50-a:#62e08560;--c-green-60:#4ada71;--c-green-70:#2dd55b;--c-green-80:#17c948;--c-green-90:#00ba33;--c-green-100:#00a52d;--c-green-110:#009b2b;--c-green-120:#009128;--c-green-130:#008725;--c-green-140:#007d22;--c-green-150:#00711f;--c-green-160:#00661c;--c-green-170:#00581a;--c-green-180:#004314;--c-green-190:#002f0e;--c-green-200:#001807;--c-lime-0:#f5fff0;--c-lime-10:#ebfee3;--c-lime-20:#ddfcd0;--c-lime-30:#cffbbc;--c-lime-40:#bbf9a2;--c-lime-50:#a3f581;--c-lime-60:#8bf35f;--c-lime-70:#64ec44;--c-lime-80:#4ddf2b;--c-lime-90:#3ad515;--c-lime-100:#27c100;--c-lime-110:#25b400;--c-lime-120:#22a400;--c-lime-130:#1e9200;--c-lime-140:#1a7e00;--c-lime-150:#176d00;--c-lime-160:#135a00;--c-lime-170:#0f4900;--c-lime-180:#0c3900;--c-lime-190:#092c00;--c-lime-200:#061d00;--c-lavender-0:#f7f8ff;--c-lavender-10:#e6ebff;--c-lavender-20:#ced9ff;--c-lavender-30:#b6c6ff;--c-lavender-40:#9fb5ff;--c-lavender-50:#8aa4ff;--c-lavender-60:#7493ff;--c-lavender-70:#597eff;--c-lavender-80:#3c67ff;--c-lavender-90:#194bfd;--c-lavender-100:#0033e8;--c-lavender-110:#002dcc;--c-lavender-120:#0028b8;--c-lavender-130:#0023a2;--c-lavender-140:#002092;--c-lavender-150:#001a79;--c-lavender-160:#001560;--c-lavender-170:#00114e;--c-lavender-180:#000e41;--c-lavender-190:#000a30;--c-lavender-200:#000721;--c-lavender-210:#8aa4ff50;--c-lavender-220:#7493ff40;--c-purple-0:#f4f4ff;--c-purple-10:#e9eaff;--c-purple-20:#d0d2ff;--c-purple-30:#b6b9f9;--c-purple-40:#9a99fc;--c-purple-50:#8482fb;--c-purple-60:#786df9;--c-purple-70:#6e5afd;--c-purple-80:#6030ff;--c-purple-90:#4712fb;--c-purple-100:#3400e6;--c-purple-110:#3000d1;--c-purple-120:#2b00bc;--c-purple-130:#2600a6;--c-purple-140:#20008e;--c-purple-150:#1b0075;--c-purple-160:#15005c;--c-purple-170:#100048;--c-purple-180:#0d0038;--c-purple-190:#0b0030;--c-purple-200:#080022;--c-brand:#8f1a7f;--c-brand-a:#8f1a7f60;--c-pink-0:#ffeff5;--c-pink-10:#ffe3ed;--c-pink-20:#ffd8e5;--c-pink-30:#ffc9db;--c-pink-40:#ffb6d0;--c-pink-50:#ff99bd;--c-pink-60:#ff80ac;--c-pink-70:#ff6098;--c-pink-80:#fb4082;--c-pink-90:#ec216a;--c-pink-100:#da0d56;--c-pink-110:#d0004a;--c-pink-120:#c40046;--c-pink-130:#b30040;--c-pink-140:#a3003b;--c-pink-150:#940035;--c-pink-160:#850030;--c-pink-170:#710029;--c-pink-180:#5f0022;--c-pink-190:#460019;--c-pink-200:#20000b;--c-red-0:#fff1f3;--c-red-10:#ffe6e8;--c-red-20:#ffcfd3;--c-red-30:#feb7bc;--c-red-40:#fc9aa2;--c-red-50:#f9838c;--c-red-50-a:#f9838c60;--c-red-60:#f56570;--c-red-70:#f24c58;--c-red-80:#ef3442;--c-red-90:#e21827;--c-red-100:#d0000f;--c-red-110:#c5000f;--c-red-120:#b3000e;--c-red-130:#9c000c;--c-red-140:#89000b;--c-red-150:#760009;--c-red-160:#650008;--c-red-170:#520006;--c-red-180:#410005;--c-red-190:#300004;--c-red-200:#1d0002;--c-red-210:#f24c5830;--c-red-220:#ef344215;--c-orange-0:#fff5f0;--c-orange-10:#ffede6;--c-orange-20:#ffdfd1;--c-orange-30:#ffd0bc;--c-orange-40:#ffc0a5;--c-orange-50:#ffaf8c;--c-orange-60:#ff9b70;--c-orange-70:#ff8753;--c-orange-80:#ff7336;--c-orange-90:#ff5b13;--c-orange-100:#eb4700;--c-orange-110:#d94200;--c-orange-120:#c93d00;--c-orange-130:#b63700;--c-orange-140:#a53200;--c-orange-150:#8c2a00;--c-orange-160:#772400;--c-orange-170:#5e1c00;--c-orange-180:#481600;--c-orange-190:#341000;--c-orange-200:#1d0900;--c-yellow-0:#fffbef;--c-yellow-10:#fff8e2;--c-yellow-20:#fff4d1;--c-yellow-30:#ffefbd;--c-yellow-30-a:#fcd28550;--c-yellow-40:#ffe9a3;--c-yellow-50:#ffcb2d;--c-yellow-50-a:#ffd75a60;--c-yellow-60:#ffd75a;--c-yellow-60-a:#ffd75a30;--c-yellow-70:#ffce31;--c-yellow-80:#ffc409;--c-yellow-90:#f4b100;--c-yellow-90-a:#f4b10060;--c-yellow-100:#eaa100;--c-yellow-110:#dd9800;--c-yellow-120:#cc8d00;--c-yellow-130:#be8300;--c-yellow-140:#b17a00;--c-yellow-150:#9c6c00;--c-yellow-160:#8a6000;--c-yellow-170:#755100;--c-yellow-180:#5f4100;--c-yellow-190:#452f00;--c-yellow-200:#231800;--c-yellow-210:#ffc40950;--c-yellow-220:#ffce3140;--c-aqua-0:#f0fff9;--c-aqua-10:#e6fff6;--c-aqua-20:#ceffed;--c-aqua-30:#b7fce3;--c-aqua-40:#93f9d5;--c-aqua-50:#79f5c9;--c-aqua-60:#59f0ba;--c-aqua-70:#38e9aa;--c-aqua-80:#1ae19a;--c-aqua-90:#00d287;--c-aqua-100:#00ba78;--c-aqua-110:#00aa6d;--c-aqua-120:#009b63;--c-aqua-130:#00915c;--c-aqua-140:#008152;--c-aqua-150:#016e46;--c-aqua-160:#015d3c;--c-aqua-170:#014f32;--c-aqua-180:#013e28;--c-aqua-190:#012e1e;--c-aqua-200:#011e13;--c-teal-0:#eefeff;--c-teal-10:#dffdff;--c-teal-20:#d0fdff;--c-teal-30:#bbfcff;--c-teal-40:#a2fcff;--c-teal-50:#8bfbff;--c-teal-60:#73f6fb;--c-teal-60-a:#73f6fb60;--c-teal-70:#55ecf2;--c-teal-80:#35e2e9;--c-teal-90:#1bd2d9;--c-teal-100:#00b9c0;--c-teal-110:#01adb4;--c-teal-120:#019fa5;--c-teal-130:#018f94;--c-teal-210:#3dc1d340;--c-teal-220:#3dc1d325;--c-teal-140:#017e83;--c-teal-150:#016d71;--c-teal-160:#015d61;--c-teal-170:#014d4f;--c-teal-180:#013c3e;--c-teal-190:#012c2e;--c-teal-200:#011c1d;--c-cyan-0:#f3faff;--c-cyan-10:#e8f5ff;--c-cyan-20:#d3ecff;--c-cyan-30:#bfe4ff;--c-cyan-40:#a7daff;--c-cyan-50:#8dcfff;--c-cyan-60:#77c6ff;--c-cyan-70:#62bdff;--c-cyan-80:#46b1ff;--c-cyan-90:#24a3ff;--c-cyan-100:#0091fa;--c-cyan-110:#0189ec;--c-cyan-120:#017ed8;--c-cyan-130:#0170c0;--c-cyan-140:#0163aa;--c-cyan-150:#015592;--c-cyan-160:#01487b;--c-cyan-170:#013a64;--c-cyan-180:#012d4d;--c-cyan-190:#011e33;--c-cyan-200:#01121e;--sans-serif:-apple-system,BlinkMacSystemFont,san-francisco,Avenir Next,Segoe UI,Roboto,Noto Sans,Helvetica Neue;--serif:Iowan Old Style,Apple Garamond,Baskerville,Times New Roman;--monospaced:Menlo;--border:#03a9f4;--g1:#0003;--g2:#8f1a7f33;--g3:#1f1f1f33;--ifm-color-primary:#8f1a7f;--ifm-color-primary-dark:#6f1a5f;--ifm-color-primary-text:#6f1a5f;--ifm-color-primary-darker:#5f1a4f;--ifm-color-primary-darkest:#4f1a3f;--ifm-color-primary-light:#9f1a8f;--ifm-color-primary-lighter:#af1a9f;--ifm-color-primary-lightest:#bf1aaf;--ifm-code-font-size:95%;--ifm-border-color:#0000000d;--ifm-background:#00000003;--ifm-announcementBar-height:40px;--ifm-primary-hue-saturation:308 78%;--ifm-primary-hue-saturation-light:308 78%;--accent:113,26,95;--accent-background-card-gradient:linear-gradient(45deg,rgb(var(--accent)),#fda7df 10%,var(--ifm-f-white) 40%);--ifm-f-white:#fff;--ifm-f-re-white:#181818;--ifm-f-white-soft:#f8f8f8;--ifm-f-white-mute:#f2f2f2;--ifm-f-bg-soft:#f6f6f7;--farm--border:rgba(86,86,86,.125);--docsearch-searchbox-background:#8f1a7fb3;--max-layout-width:1680px;--ifm-navbar-link-hover-color:initial;--ifm-navbar-padding-vertical:0;--ifm-navbar-item-padding-vertical:0;--ifm-font-family-base:-apple-system,BlinkMacSystemFont,Inter,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI emoji";--ifm-font-family-monospace:"SFMono-Regular","Roboto Mono",Consolas,"Liberation Mono",Menlo,Courier,monospace;--ifm-menu-link-sublist-icon:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSI2IiBmaWxsPSJub25lIj48cGF0aCBzdHJva2U9IiMwMzA2MEIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjUiIGQ9Ik05IDUgNSAxIDEgNSIvPjwvc3ZnPg==");--z-sidebar:2000;--z-backdrop:1100;--ifm-menu-color-background:#ff9ff310;--docusaurus-highlighted-code-line-bg:#ff9ff310;--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base);--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--dm-color-brand:#3451b2;--dm-color-bg-alt:#f6f6f7;--dm-color-hint:#3c3c43c7;--dm-button-font-size:13px;--dm-button-height:40px;--dm-c-white:#fff;--dm-text-color:#374151;--dm-modal-bg-color:var(--dm-c-white);--dm-divider-color:#f3f4f6;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.container,.w-full{width:100%}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.absolute{position:absolute}.chat-container[data-v-3926b6c7],.relative{position:relative}.inset-0{inset:0}.z-10{z-index:10}.m-auto{margin:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-10{margin-bottom:2.5rem;margin-top:2.5rem}.my-14{margin-bottom:3.5rem;margin-top:3.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-8{margin-bottom:2rem;margin-top:2rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.mt-10{margin-top:2.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.loader_qPMq,.mt-8{margin-top:2rem}.inline,.tags_HSrq{display:inline}.grid{display:grid}.size-3{height:.75rem;width:.75rem}.size-4{height:1rem;width:1rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.documate-button .icon[data-v-956ba6e9],.h-4{height:1rem}.h-52{height:13rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.min-h-\[2rem\]{min-height:2rem}.min-h-\[inherit\]{min-height:inherit}.w-16{width:4rem}.w-20{width:5rem}.w-36{width:9rem}.w-40{width:10rem}.w-6{width:1.5rem}.w-9\/12{width:75%}.w-\[1px\]{width:1px}.max-w-7xl{max-width:80rem}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}@keyframes a{0%,90%,to{background-position:calc(-100% - var(--shimmer-width)) 0}30%,60%{background-position:calc(100% + var(--shimmer-width)) 0}}.animate-shimmer{animation:8s infinite a}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center,.mdxPageWrapper_uWPR{justify-content:center}.justify-between{justify-content:space-between}.gap-10{gap:2.5rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-5{column-gap:1.25rem}.gap-y-12{row-gap:3rem}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.self-start{align-self:flex-start}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[var\(--border-radius\)\]{border-radius:var(--border-radius)}.rounded-\[var\(--card-content-radius\)\]{border-radius:var(--card-content-radius)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-black\/5{border-color:#0000000d}.bg-fuchsia-600{background-color:rgb(192 38 211/var(--tw-bg-opacity))}.bg-gray-100{background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-500{background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-neutral-100{background-color:rgb(245 245 245/var(--tw-bg-opacity))}.bg-white\/40{background-color:#fff6}.bg-zinc-950{background-color:rgb(9 9 11/var(--tw-bg-opacity))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-\[\#ffaa40\]{--tw-gradient-from:#ffaa40 var(--tw-gradient-from-position)}.from-\[\#ffaa40\]\/50{--tw-gradient-from:#ffaa4080 var(--tw-gradient-from-position)}.from-transparent{--tw-gradient-from:#0000 var(--tw-gradient-from-position);--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.via-\[\#9c40ff\],.via-\[\#9c40ff\]\/50{--tw-gradient-to:#9c40ff00 var(--tw-gradient-to-position)}.via-\[\#9c40ff\]{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-\[\#9c40ff\]\/50{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff80 var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-black\/80{--tw-gradient-to:#0000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#000c var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-50\%{--tw-gradient-via-position:50%}.to-\[\#ffaa40\]{--tw-gradient-to:#ffaa40 var(--tw-gradient-to-position)}.to-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4080 var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.bg-\[length\:var\(--bg-size\)_100\%\]{background-size:var(--bg-size) 100%}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.p-2{padding:.5rem}.p-6{padding:1.5rem}.p-\[1px\]{padding:1px}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.text-left{text-align:left}.data_ODnV,.kbd-text[data-v-3926b6c7],.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.tracking-wide{letter-spacing:.025em}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-neutral-600\/50{color:#52525280}.text-transparent{color:#0000}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow-\[inset_0_-8px_10px_\#8fdfff1f\]{--tw-shadow:inset 0 -8px 10px #8fdfff1f;--tw-shadow-colored:inset 0 -8px 10px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter}.transition-all{transition-property:all}.transition-shadow{transition-property:box-shadow}.transition-transform{transition-property:transform}.duration-200{transition-duration:.2s}.duration-300,.hover\:duration-300:hover{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--bg-size\:300\%\]{--bg-size:300%}.\[background-position\:0_0\]{background-position:0 0}.\[background-size\:var\(--shimmer-width\)_100\%\]{background-size:var(--shimmer-width) 100%}.\[border-radius\:inherit\]{border-radius:inherit}.\!\[mask-composite\:subtract\]{-webkit-mask-composite:source-out!important;mask-composite:subtract!important}.\[mask\:linear-gradient\(\#fff_0_0\)_content-box\2c linear-gradient\(\#fff_0_0\)\]{-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0)}[data-theme=dark]{--ifm-f-bg-soft:#252529;--ifm-background-color:#000!important;--ifm-color-primary:#fff;--ifm-color-primary-text:#fff;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--ifm-menu-color-background:#ff9ff340;--ifm-background:#0000004d;--ifm-f-white:#c74040;--ifm-f-re-white:#fff;--ifm-f-white-soft:#222;--ifm-f-white-mute:#282828;--farm--border:#fafafa20;--docusaurus-highlighted-code-line-bg:#8f1a7fb3;--docsearch-primary-color:var(--ifm-color-primary-dark)!important;--docsearch-searchbox-background:#3a3a3a!important}.navbar__title{color:#6f1a5f;font-size:1.5em}.navbar__title:hover{color:#bf1aaf}.header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat;content:"";display:flex;height:20px;width:20px}[data-theme=dark] .header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.bg{background-color:var(--ifm-f-white-soft)}.bg-re{background-color:var(--ifm-f-re-white)}.color{color:var(--ifm-f-white)}.token.color{color:#c44cac}.color-re{color:var(--ifm-f-re-white)}.theme-back-to-top-button{height:50px!important;width:50px!important}[class^=backToTopButton_]:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:3rem 3rem!important;-webkit-mask-size:3rem 3rem!important}.clean-btn:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:1.5rem 1.5rem!important;-webkit-mask-size:1.5rem 1.5rem!important}div[class^=announcementBar_]{--site-announcement-bar-stripe-color1:hsl(var(--ifm-primary-hue-saturation) 85%);--site-announcement-bar-stripe-color2:hsl(var(--ifm-primary-hue-saturation) 95%);background:linear-gradient(45deg,#711a5f,#c44cac 30%,#9f1a8f 60%,#fda7df 80%);color:var(--c-white);font-weight:700;height:var(--ifm-announcementBar-height)}footer[class=footer]{background-color:var(--ifm-f-white-soft)!important}.footer__link-item{gap:6px;line-height:3}.DocSearch-Button-Container,.footer__link-item,.navbar__link{align-items:center;display:flex}.code-block-highlight-line{background-color:var(--docusaurus-highlighted-code-line-bg);border-left:5px solid #c44cac;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.DocSearch-Button{border-radius:8px!important;width:250px}.theme-admonition-warning{color:var(--c-yellow-120)}.theme-admonition-danger{color:var(--c-red-60)}.theme-doc-version-badge{margin:10px 0}.navbar--fixed-top{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background:#0000;box-shadow:0 4px 10px #00000014}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}figure{margin:12px}.after\:absolute:after,.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:left-0:before{content:var(--tw-content);left:0}.before\:right-0:before{content:var(--tw-content);right:0}.before\:top-\[-var\(--border-size\)\]:before{content:var(--tw-content);top:-var(--border-size)}.after\:-z-10:after,.before\:z-\[-10\]:before{content:var(--tw-content);z-index:-10}.after\:block:after,.before\:block:before{content:var(--tw-content);display:block}.after\:h-\[var\(--pseudo-element-height\)\]:after,.before\:h-\[var\(--pseudo-element-height\)\]:before{content:var(--tw-content);height:var(--pseudo-element-height)}.before\:w-full:before{content:var(--tw-content);width:100%}.after\:animate-backgroundPositionSpin:after,.before\:animate-backgroundPositionSpin:before{animation:3s infinite alternate b;content:var(--tw-content)}.before\:bg-\[var\(--pseudo-element-background-image\)\]:before{background-color:var(--pseudo-element-background-image);content:var(--tw-content)}.before\:bg-\[length\:200\%_100\%\]:before{background-size:200% 100%;content:var(--tw-content)}.after\:content-\[\'\'\]:after,.before\:content-\[\'\'\]:before{--tw-content:"";content:var(--tw-content)}.after\:-left-\[var\(--border-size\)\]:after{content:var(--tw-content);left:calc(var(--border-size)*-1)}.after\:-top-\[var\(--border-size\)\]:after{content:var(--tw-content);top:calc(var(--border-size)*-1)}.after\:w-\[var\(--pseudo-element-width\)\]:after{content:var(--tw-content);width:var(--pseudo-element-width)}@keyframes b{0%{background-position:top;content:var(--tw-content)}to{background-position:bottom;content:var(--tw-content)}}.after\:rounded-\[var\(--border-radius\)\]:after{border-radius:var(--border-radius);content:var(--tw-content)}.after\:bg-\[linear-gradient\(0deg\2c var\(--neon-first-color\)\2c var\(--neon-second-color\)\2c var\(--neon-third-color\)\)\]:after{background-image:linear-gradient(0deg,var(--neon-first-color),var(--neon-second-color),var(--neon-third-color));content:var(--tw-content)}.after\:bg-\[length\:100\%_200\%\]:after{background-size:100% 200%;content:var(--tw-content)}.after\:opacity-80:after{content:var(--tw-content);opacity:.8}.after\:blur-\[var\(--after-blur\)\]:after{content:var(--tw-content);--tw-blur:blur(var(--after-blur))}.hover\:bg-neutral-200:hover{--tw-bg-opacity:1;background-color:rgb(229 229 229/var(--tw-bg-opacity))}.hover\:text-neutral-600:hover{--tw-text-opacity:1;color:rgb(82 82 82/var(--tw-text-opacity))}.focus\:text-opacity-80:focus,.hover\:text-opacity-80:hover{--tw-text-opacity:0.8}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover{--tw-shadow:inset 0 -5px 10px #8fdfff3f;--tw-shadow-colored:inset 0 -5px 10px var(--tw-shadow-color)}.group:hover .group-hover\:translate-x-0\.5{--tw-translate-x:0.125rem}.container__nVC{border-radius:6px;contain:content}}.tab-list_aJ1t{display:flex;min-width:100%;overflow-x:scroll;padding:4px 0 8px 8px}.tab_J4Y8{border-bottom:2px solid #0000;margin-bottom:-1px;margin-right:10px;padding:6px 12px;transition:.2s ease-in-out;user-select:none}.tab_J4Y8:last-child{margin-right:0}.selected_erAK{border-color:currentColor}.no-scrollbar_vtMC::-webkit-scrollbar{display:none}.no-scrollbar_vtMC{-ms-overflow-style:none;scrollbar-width:none}.backToTopButton_CW5h{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_CW5h:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_pJBw{opacity:1;transform:scale(1);visibility:visible}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;color:var(--docsearch-muted-color);display:flex;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch-Button-Key--pressed{box-shadow:var(--docsearch-key-pressed-shadow);transform:translate3d(0,1px,0)}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a,.sidebarItemLink_tcbF:hover{text-decoration:none}.DocSearch-Hit[aria-selected=true] mark,.content__jQl a{text-decoration:underline}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset,p[data-v-3926b6c7],ul[data-v-3926b6c7]{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards c;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.sidebar_HzcY,.tableOfContents_HR7E{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}#__docusaurus-base-url-issue-banner-container,.button-placeholder[data-v-3926b6c7],.docSidebarContainer_ZZsd,.loading.hide[data-v-3926b6c7],.navbarSearchContainer_ND2d:empty,.sidebarLogo_vqPK,.themedComponent_kF_f,[data-theme=dark] .lightToggleIcon__XKe,[data-theme=light] .darkToggleIcon_fMED,html[data-announcement-bar-initially-dismissed=true] .announcementBar_egfn,svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon,.tocCollapsibleContent_KIE9 a{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands li,.DocSearch-Commands-Key,.buttons_AeoN{align-items:center;display:flex}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@keyframes c{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container,.skipToContent_izU8{z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_izU8{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem}.skipToContent_izU8:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_rNcS{line-height:0;padding:0}.content__jQl{font-size:85%;padding:5px 0;text-align:center}.content__jQl a{color:inherit}.announcementBar_egfn{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_OBFz{flex:0 0 10px}.announcementBarClose_EolD{align-self:stretch;flex:0 0 30px}.toggle_pkrm{height:2rem;width:2rem}.toggleButton_IoGO{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_IoGO:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_zO9u{cursor:not-allowed}.darkNavbarColorModeToggle_p1rI:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_ucyz,[data-theme=light] .themedComponent--light_WVpI,html:not([data-theme]) .themedComponent--light_WVpI{display:initial}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_L0Og{display:none;margin:0}.iconExternalLink_GQRh{margin-left:.3rem}.docMainContainer_LfAu,.docRoot_CVEc{display:flex;width:100%}.docsWrapper_V_L6{display:flex;flex:1 0 auto}.iconLanguage_VYTf{margin-right:5px;vertical-align:text-bottom}.dark{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-divider-color:#2e2e32}.sp_EK1s .sp-link_GRPb.link_ib43:focus,.sp_EK1s .sp-link_GRPb.link_ib43:hover,body:not(.navigation-with-keyboard) :not(input):focus,input[data-v-3926b6c7],input[data-v-3926b6c7]:focus{outline:0}.enter[data-v-3926b6c7]{transition:opacity .2s ease-out}.enter-from[data-v-3926b6c7],.leave-to[data-v-3926b6c7]{opacity:0}.leave[data-v-3926b6c7]{transition:opacity .1s ease-in}.transition-child-ref[data-v-3926b6c7]{bottom:0;left:0;position:fixed;right:0;top:0;transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dialog[data-v-3926b6c7]{background-color:var(--dm-mask-bg-color);bottom:0;left:0;overflow-y:auto;position:fixed;right:0;top:0;z-index:999999}.dialog-container[data-v-3926b6c7]{padding:1rem}.dialog-panel[data-v-3926b6c7]{background-color:var(--dm-modal-bg-color);border-radius:.75rem;box-shadow:0 25px 50px -12px #00000040;margin:0 auto;max-width:36rem;overflow:hidden;transition-duration:.3s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.magnifying-glass-icon[data-v-3926b6c7]{color:var(--dm-text-color);height:1.25rem;left:1rem;pointer-events:none;position:absolute;top:.875rem;width:1.25rem}.chat-input[data-v-3926b6c7]{background-color:initial;border-width:0;border-bottom:1px solid var(--dm-divider-color);box-sizing:border-box;color:var(--dm-text-color);height:3rem;padding-left:2.75rem;padding-right:1rem;width:100%}.chat-input[data-v-3926b6c7]::placeholder{font-size:1rem}.combobox-options[data-v-3926b6c7]{list-style:none;max-height:20rem;min-height:5rem;overflow-y:auto;padding:1rem;scroll-padding-bottom:.5rem;scroll-padding-top:2.5rem}.combobox-option[data-v-3926b6c7]{cursor:pointer;display:flex;padding:.5rem 1rem;-webkit-user-select:none;user-select:none}.combobox-options-container[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;margin-left:-1rem;margin-right:-1rem;margin-top:.5rem}.active[data-v-3926b6c7]{background-color:var(--dm-highlight-color);color:var(--dm-c-white)}.combobox-options-name[data-v-3926b6c7]{flex:1 1 auto;margin-left:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.loading[data-v-3926b6c7]{align-items:center;display:flex;justify-content:left;padding:1rem 1rem 1rem 2.6rem}.loading-spin[data-v-3926b6c7]{animation:1s linear infinite d;height:1.5rem;margin-right:.5rem;width:1.5rem}.option-icon[data-v-3926b6c7]{flex:none;height:1.5rem;width:1.5rem}.question-anwser-section[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;list-style:none;max-height:20rem;scroll-padding-bottom:.5rem;scroll-padding-top:.5rem}.question-anwser-item[data-v-3926b6c7]{padding-bottom:.875rem;padding-top:.875rem}.question-role-user[data-v-3926b6c7]{display:flex;gap:1.2rem}.question-role-icon[data-v-3926b6c7]{display:inline-block;flex:none;height:1.5rem;width:1.5rem}.documate-logo[data-v-3926b6c7]{height:1.4rem;width:1.4rem}.result-not-found[data-v-3926b6c7]{padding:3.5rem 1.5rem;text-align:center}.result-not-found-text[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.85rem;margin-top:.5rem}.anwser-content[data-v-3926b6c7]{display:flex;gap:1.5rem}.markdown-body[data-v-3926b6c7]{border-width:0;color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;list-style:auto;overflow-wrap:break-word}.footer[data-v-3926b6c7]{align-content:center;align-items:center;border-top:1px solid var(--dm-divider-color);color:var(--dm-text-color);display:flex;flex-wrap:wrap;font-size:.75rem;justify-content:space-between;line-height:1rem;padding:.625rem 1rem}.kbd-wrap[data-v-3926b6c7]{align-content:center;display:flex;justify-content:center}.kbd-text[data-v-3926b6c7],.kbd[data-v-3926b6c7]{align-items:center;display:flex;justify-content:center}.kbd[data-v-3926b6c7]{border-radius:.25rem;border-width:1px;font-weight:600;height:1.25rem;margin-left:.25rem;margin-right:.25rem;width:1.25rem}.esc[data-v-3926b6c7]{width:2rem}.powered-by[data-v-3926b6c7]{align-items:center;color:var(--dm-text-color);display:flex;gap:.25rem;justify-content:center;text-decoration:none}@keyframes d{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.dark .hljs{background:#0d1117;color:#c9d1d9}.dark .hljs-doctag,.dark .hljs-keyword,.dark .hljs-meta .hljs-keyword,.dark .hljs-template-tag,.dark .hljs-template-variable,.dark .hljs-type,.dark .hljs-variable.language_{color:#ff7b72}.dark .hljs-title,.dark .hljs-title.class_,.dark .hljs-title.class_.inherited__,.dark .hljs-title.function_{color:#d2a8ff}.dark .hljs-attr,.dark .hljs-attribute,.dark .hljs-literal,.dark .hljs-meta,.dark .hljs-number,.dark .hljs-operator,.dark .hljs-selector-attr,.dark .hljs-selector-class,.dark .hljs-selector-id,.dark .hljs-variable{color:#79c0ff}.dark .hljs-meta .hljs-string,.dark .hljs-regexp,.dark .hljs-string{color:#a5d6ff}.dark .hljs-built_in,.dark .hljs-symbol{color:#ffa657}.dark .hljs-code,.dark .hljs-comment,.dark .hljs-formula{color:#8b949e}.dark .hljs-name,.dark .hljs-quote,.dark .hljs-selector-pseudo,.dark .hljs-selector-tag{color:#7ee787}.dark .hljs-subst{color:#c9d1d9}.dark .hljs-section{color:#1f6feb;font-weight:700}.dark .hljs-bullet{color:#f2cc60}.dark .hljs-emphasis{color:#c9d1d9;font-style:italic}.dark .hljs-strong{color:#c9d1d9;font-weight:700}.dark .hljs-addition{background-color:#033a16;color:#aff5b4}.dark .hljs-deletion{background-color:#67060c;color:#ffdcd7}.documate-button[data-v-956ba6e9]{align-items:center;cursor:pointer;display:flex;height:var(--dm-button-height);justify-content:flex-start;padding-left:.75rem;padding-right:.75rem;transition:border-color .25s ease-in-out}.navbarHideable_zRUE{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_sWQh{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_P1by{color:red;white-space:pre-wrap}.errorBoundaryFallback_jSVL{color:red;padding:.55rem}.anchorWithStickyNavbar__Jjv{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_KMPm{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_GSFM{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.searchQueryInput_QXFO,.searchVersionInput_Blrj{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_QXFO:focus,.searchVersionInput_Blrj:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_QXFO::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_Ts2M{font-size:.9rem;font-weight:700}.algoliaLogo_Kh6k{max-width:150px}.algoliaLogoPathFill_pnph{fill:var(--ifm-font-color-base)}.searchResultItem_lZq0{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_mfOK{font-weight:400;margin-bottom:0}.searchResultItemPath_HKdS{color:var(--ifm-color-content-secondary);font-size:.8rem;--ifm-breadcrumb-separator-size-multiplier:1}.searchResultItemSummary_lVXw{font-style:italic;margin:.5rem 0 0}.loadingSpinner_gx04{animation:1s linear infinite e;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes e{to{transform:rotate(1turn)}}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}.card-container_mQSC:after,.card_L8bV{background:var(--ifm-f-white-soft);border-radius:10px;box-shadow:0 1px 4px #00000029;width:100%;transition:background-position .35s}.features_t9lD{align-items:center;display:flex;padding:2rem 0;width:100%}.item_fAv5{margin:0 auto;width:100%}.card_L8bV{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;padding:2rem .5rem 0;position:relative;z-index:2}.backgroundImage_M6A8{background:linear-gradient(-45deg,#e67ac6 50%,#47caff 0);border-radius:50%;filter:blur(36px)}.card-container_mQSC{cursor:pointer;justify-content:center;position:relative}.card-container_mQSC:hover:before{animation:16s linear infinite f;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;border-radius:10px;content:"";filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;position:absolute;top:-2px;transition:opacity .3s ease-in-out;width:calc(100% + 4px);z-index:-1000}.card-container_mQSC:after{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;content:"";height:100%;left:0;position:absolute;top:0;z-index:100}.card-container-content_HPWq{position:relative;transition:background-position .35s;z-index:1000}@keyframes f{0%,to{background-position:0 0}50%{background-position:400% 0}}.progress-bar-container_Btve{border:1px solid var(--farm--border);border-radius:4px;box-sizing:initial;height:25px;padding:4px;width:50vw}.progress-bar-inner-container_RjNy{background:#9f1a8f;border-radius:2px;height:25px}.progress-bar_MQ9H{background:linear-gradient(90deg,#c026d3,#d2269e);border-radius:2px;height:100%}.font-mono_qmiE{font-family:Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace}}.main_Gz2F{border:2px solid #272727;border-radius:5px;cursor:pointer;height:50px;overflow:hidden;position:relative;width:200px}.container_GXFn,.layer,canvas{height:100%}.fill_bMTX{background:#ff69b4}.content__pcr,.fill_bMTX{height:100%;left:0;position:absolute;top:0;width:100%}.content__pcr{color:#272727}.container_GXFn,.content__pcr{align-items:center;display:flex;justify-content:center}.tabs_FETH{align-items:center;display:flex;flex-direction:column;justify-content:center;width:100%}canvas{margin:0;padding:0;width:100%}.layer{bottom:0;left:0;width:100%}.layer,span.header{pointer-events:none;position:absolute}span.header{display:inline-block;font-size:9em;font-weight:700;left:50px;line-height:.9em;top:350px;transform:translate3d(0,-50%,0);width:500px}.heroBanner_qdFl{overflow:hidden;padding:3rem 0;position:relative;text-align:center}.banner_IlVB,.banner_d9gt{background:linear-gradient(45deg,#711a5f,#fda7df 70%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:#0000;color:#0000}.farmButton2_X03M,.farmButton_siNL{color:#fff;height:50px;outline:0;z-index:0;cursor:pointer}.btn_bvfa{border-radius:8px;border-width:2px;font-family:Open Sans;font-size:1rem;font-style:normal;font-weight:600;line-height:1.5rem;min-width:130px;padding:12px 20px}.farmButton_siNL{background:#111;border:none;border-radius:10px;position:relative}.farmButton_siNL:before{animation:120s linear infinite g;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .5s ease-in-out;width:calc(100% + 4px)}.farmButton2_X03M:after,.farmButton2_X03M:before,.farmButton_siNL:after,.farmButton_siNL:before{border-radius:10px;content:"";position:absolute;z-index:-1}.farmButton2_X03M:after,.farmButton_siNL:after{background:#111;height:100%;left:0;top:0;width:100%}.fKVWgc_SGll{inset:0;-webkit-mask-image:linear-gradient(#000,#0000);mask-image:linear-gradient(#000,#0000);position:absolute}.farmButton2_X03M{background:#171717;border:none;border-radius:10px;position:relative}.farmButton2_X03M:before{animation:100s linear infinite g;background:linear-gradient(45deg,#ffaa40,#9f1a8f,#ffaa40,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .2s ease-in-out;width:calc(100% + 4px)}@keyframes g{0%,to{background-position:0 0}30%{background-position:400% 0}}.gradientText_nNG0{background:linear-gradient(to bottom right,#000,gray 40%,#fff);-webkit-background-clip:text;color:#0000}.sidebar_HzcY{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.card-main_mTfv,.teamMembersItem_XVAE{height:100%;overflow:hidden;width:100%}.sidebarItemTitle_xInU{font-size:var(--ifm-h3-font-size);font-weight:var(--ifm-font-weight-bold)}.container_Bf5U,.sidebarItemList_T4cF{font-size:.9rem}.sidebarItem_vQne{margin-top:.7rem}.sidebarItemLink_tcbF{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_Tnzw{color:var(--ifm-color-primary)!important}.authorCol_Pb4k{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_yfhS{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_ejJf{margin-left:.3rem;margin-right:.3rem}.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(130px,1fr))}.container_hhjZ{display:grid;gap:40px;margin:0 auto;width:100%}.card-main_mTfv{align-items:center;display:flex;justify-content:center}.card_sVd9{border-radius:8px;transition:box-shadow .5s;will-change:transform}.teamMembersItem_XVAE{border-radius:12px;display:flex;flex-direction:column;gap:2px}.teamMembersItem_XVAE .profile_WQFr{padding:10px}.teamMembersItem_XVAE .avatar_B5t7{cursor:pointer;height:64px;transition:.2s ease-in-out;width:64px}.teamMembersItem_XVAE .name_LD5w{font-size:16px;line-height:24px}.teamMembersItem_XVAE .org_o4tg{font-size:14px;line-height:24px}.teamMembersItem_XVAE .affiliation_rzqG{font-size:14px;line-height:20px;padding-top:4px}.teamMembersItem_XVAE .desc_pfHu{font-size:14px;line-height:20px;padding-top:12px}.teamMembersItem_XVAE .links_A3uT{margin:0 -16px -20px;padding:10px 0 0}.profile_WQFr{align-items:center;display:flex;flex-direction:column;flex-grow:1;gap:20px}.avatar_B5t7{border-radius:50%;flex-shrink:0;margin:0 auto;position:relative}.avatar-img_PAbF{border-radius:50%;bottom:0;left:0;object-fit:cover;position:absolute;right:0;top:0}.name_LD5w{font-weight:600;margin:0}.affiliation_rzqG{font-weight:500;margin:0}.org_o4tg.link_ib43{transition:color .25s}.desc_pfHu{margin:0 auto}.desc_pfHu :deep(a){font-weight:500;text-decoration-style:dotted;transition:color .25s}.links_A3uT{height:56px}.sp-link_GRPb{align-items:center;background-color:var(--ifm-f-white);font-size:14px;font-weight:500;padding:16px;text-align:center;transition:color .25s,background-color .25s}.buttonGroup_EH9s button,.codeBlockContainer_hacD{background:var(--prism-background-color);color:var(--prism-color)}.sp-icon_KrGn{height:16px;margin-right:8px;width:16px;fill:currentColor}.codeBlockContainer_hacD{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_dlr7{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_G6ED{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_MgM5{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_G6ED+.codeBlockContent_dlr7 .codeBlock_MgM5{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_wRYc{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_AT7_{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup_EH9s{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup_EH9s button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup_EH9s button:focus-visible,.buttonGroup_EH9s button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup_EH9s button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_JL7T{counter-increment:a;display:table-row}.codeLineNumber_dqoy{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_dqoy:before{content:counter(a);opacity:.4}.codeLineContent_nqyk{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_WZ8_{opacity:1!important}.copyButtonIcons_fpP_{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_LywX,.copyButtonSuccessIcon_W0Bz{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_W0Bz{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_WZ8_ .copyButtonIcon_LywX{opacity:0;transform:scale(.33)}.copyButtonCopied_WZ8_ .copyButtonSuccessIcon_W0Bz{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_M_ov{height:1.2rem;width:1.2rem}.tag_eQYG{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_eQYG:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_hEyF{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_Mx1W{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_Mx1W:after,.tagWithCount_Mx1W:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_Mx1W:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_Mx1W:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_Mx1W span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_qQMi{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit_KbD1{margin-right:.3em;vertical-align:sub}.details_Erfu{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_Erfu>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_Erfu>summary::-webkit-details-marker{display:none}.details_Erfu>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_SYrp{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.lastUpdated_Eyme{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_z9HT{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_z9HT:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_h18n:after,.tocCollapsibleExpanded_HXYb{transform:none}.tocCollapsible_cvpH{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_KIE9>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_KIE9 ul li{margin:.4rem .8rem}.details_XeDr{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_DV6A{list-style:none}.img_c7M8{height:auto}.tableOfContents_HR7E{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.admonition_lXA4{margin-bottom:1em}.admonitionHeading_rz2u{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);text-transform:uppercase}.admonitionHeading_rz2u:not(:last-child){margin-bottom:.3rem}.admonitionIcon_GXmn{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_GXmn svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.breadcrumbHomeIcon_hi01{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_YqSF{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:375px){.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}}@media (min-width:640px){.container{max-width:640px}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:block{display:block}.sm\:w-40{width:10rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-6{padding-bottom:1.5rem;padding-top:1.5rem}.sm\:pr-4{padding-right:1rem}.sm\:pt-12{padding-top:3rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}.sm\:text-base{font-size:1rem;line-height:1.5rem}.dialog-container[data-v-3926b6c7]{padding:1.5rem}.chat-input[data-v-3926b6c7]{font-size:.875rem;line-height:1.25rem}.result-not-found[data-v-3926b6c7]{padding-left:3.5rem;padding-right:3.5rem}.kbd[data-v-3926b6c7]{margin-left:.5rem;margin-right:.5rem}}@media (min-width:768px){.container{max-width:768px}.md\:order-1{order:1}.md\:order-2{order:2}.md\:col-span-1{grid-column:span 1/span 1}.md\:mt-0{margin-top:0}.button-placeholder[data-v-3926b6c7],.md\:block{display:block}.md\:w-auto{width:auto}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:gap-x-12{column-gap:3rem}.dialog-container[data-v-3926b6c7]{padding:5rem}.documate-button[data-v-956ba6e9]{background:var(--dm-color-bg-alt);border:1px solid #0000;border-radius:.5rem;color:var(--dm-color-hint);font-size:var(--dm-button-font-size);margin-left:2rem}.documate-button .icon[data-v-956ba6e9]{height:var(--dm-button-font-size);margin-right:.2rem}.documate-button[data-v-956ba6e9]:hover{border-color:var(--dm-color-brand)}}@media (min-width:997px){.collapseSidebarButton_L0Og,.expandButton_oNFi{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_EolD,.announcementBarPlaceholder_OBFz{flex-basis:50px}.collapseSidebarButton_L0Og{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_zsCQ{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_WIom,[dir=rtl] .collapseSidebarButtonIcon_zsCQ{transform:rotate(0)}.collapseSidebarButton_L0Og:focus,.collapseSidebarButton_L0Og:hover,.expandButton_oNFi:focus,.expandButton_oNFi:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_iYT8{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_RjaT{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_RjaT{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_qXbw{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_ypQ8{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_fhRN{padding-top:0}.sidebarHidden_g0iV{opacity:0;visibility:hidden}.sidebarLogo_vqPK{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_vqPK img{height:2rem;margin-right:.5rem}.expandButton_oNFi{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_WIom{transform:rotate(180deg)}.docSidebarContainer_ZZsd{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_KBRw{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_OKtC{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_LfAu{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_ZXcV{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_upd9{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.navbarSearchContainer_ND2d{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_Eyme{text-align:right}.tocMobile_CgoI{display:none}.docItemCol_yjpU{max-width:75%!important}}@media (min-width:1024px){.container{max-width:1024px}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:row-start-2{grid-row-start:2}.lg\:h-auto{height:auto}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:justify-end{justify-content:flex-end}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-8{padding-bottom:2rem;padding-top:2rem}.lg\:pt-20{padding-top:5rem}.lg\:text-6xl{font-size:3.75rem;line-height:1}.lg\:text-base{font-size:1rem;line-height:1.5rem}.lg\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (min-width:1536px){.container{max-width:1536px}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_Mvik,.footer__link-separator,.navbar__item,.sidebar_HzcY,.tableOfContents_HR7E{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_ND2d{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_E09O{padding:0 .3rem}}@media only screen and (max-width:996px){.searchQueryColumn_a_BC,.searchResultsColumn_Ts2M{max-width:60%!important}.searchLogoColumn_c1ea,.searchVersionColumn_y88e{max-width:40%!important}.searchLogoColumn_c1ea{padding-left:0!important}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:768px){div[class^=announcementBar_]{height:calc(var(--ifm-announcementBar-height) + 12px)}.navbar__items .documate-button,.navbar__link{display:none!important}.dialog-panel[data-v-3926b6c7]{margin-top:2rem}.powered-by[data-v-3926b6c7]{margin-top:.2rem}.progress-bar-container_Btve,.progress-bar-inner-container_RjNy{height:30px}.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_Dxmf{font-size:2rem}}@media screen and (max-width:576px){.searchQueryColumn_a_BC{max-width:100%!important}.searchVersionColumn_y88e{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@media (max-width:454px){.footer[data-v-3926b6c7]{justify-content:center}}@media (hover:hover){.backToTopButton_CW5h:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-color-scheme:dark){.dark\:border-white\/5{border-color:#ffffff0d}.dark\:bg-\[rgb\(2\2c 2\2c 2\)\]{--tw-bg-opacity:1;background-color:rgb(2 2 2/var(--tw-bg-opacity))}.dark\:bg-black\/40{background-color:#0006}.dark\:bg-neutral-900{--tw-bg-opacity:1;background-color:rgb(23 23 23/var(--tw-bg-opacity))}.dark\:bg-transparent{background-color:initial}.dark\:via-white\/80{--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#fffc var(--tw-gradient-via-position),var(--tw-gradient-to)}.dark\:text-neutral-400\/50{color:#a3a3a380}.dark\:after\:bg-transparent:after,.dark\:before\:bg-transparent:before{background-color:initial;content:var(--tw-content)}.dark\:hover\:bg-neutral-800:hover{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity))}.hover\:dark\:text-neutral-400:hover{--tw-text-opacity:1;color:rgb(163 163 163/var(--tw-text-opacity))}:root{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-mask-bg-color:#656c85cc;--dm-divider-color:#2e2e32;--dm-highlight-color:var(--dm-color-brand)}.hljs{background:#0d1117;color:#c9d1d9}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{background-color:#033a16;color:#aff5b4}.hljs-deletion{background-color:#67060c;color:#ffdcd7}}@media (prefers-color-scheme:light){.hljs{background:#fff;color:#24292e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{background-color:#f0fff4;color:#22863a}.hljs-deletion{background-color:#ffeef0;color:#b31d28}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_egfn,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_CgoI{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_wRYc{white-space:pre-wrap}} \ No newline at end of file +@import url(https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown.css);@import url(https://rsms.me/inter/inter.css);.col,.container{padding:0 var(--ifm-spacing-horizontal)}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,.tab_J4Y8{-webkit-user-select:none}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}html[data-theme=dark],html[data-theme=light]{--ifm-menu-color-active:var(--ifm-color-primary-text);--admonition-note-c-color:#ff9ff3;--admonition-code-note-c-bg:#ff9ff350}.theme-admonition,:root{--ifm-alert-color:var(--ifm-font-color-base)}.theme-admonition-note,.theme-admonition-warning{--admonition-bar-c-bg:var(--admonition-bar-note-c-bg);--admonition-link-c:var(--admonition-link-note-c)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-\[\#ffaa40\],.from-\[\#ffaa40\]\/50,.from-transparent{--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.bg-fuchsia-600,.bg-gray-100,.bg-gray-500,.bg-neutral-100,.bg-zinc-950{--tw-bg-opacity:1}.toggleButton_SA1E,html{-webkit-tap-highlight-color:transparent}.dark,:root{--dm-mask-bg-color:#656c85cc;--dm-highlight-color:var(--dm-color-brand)}*,.DocSearch-Container,.DocSearch-Container *,.tab_J4Y8{box-sizing:border-box}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--doc-sidebar-width:17.5rem;--dropdown-icon-width:0.625rem;--dropdown-icon-height:0.375rem;--dropdown-icon-gap:0.688rem;--ifm-menu-link-padding-vertical:0.5rem;--sidebar-spacing-horizontal:1.5rem;--ifm-menu-color-background-hover:#0000}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_jY3I{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.items-center,.menuExternalLink_givM,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width);width:100%}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size);inherit:unset}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList_u0Lq{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration);color:#c44cac}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_c4T5 .wordWrapButtonIcon_Ci1R{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.admonitionHeading_N477 code,.btn_bvfa{text-transform:none}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover,.enter-to[data-v-3926b6c7],.hash-link:focus,.leave-from[data-v-3926b6c7],:hover>.hash-link{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button,.flex-grow{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_tjKH:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;pointer-events:none;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;transform:translateY(-50%);top:4px}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}:root,[data-theme=dark]{--ifm-footer-background-color:#181818}.footer__links,.mb-4{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color)}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_blJp article>:first-child,.docItemContainer_blJp header+*,.footer__item{margin-top:0}.admonitionContent_o_y9>:last-child,.collapsibleContent_ytpx p:last-child,.details_rMme>summary>p:last-child,.footer__items,.tabItem_FKkE>:last-child{margin-bottom:0}[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_BZZK{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_rMme[data-collapsed=false].isBrowser_hcAL>summary:before,.details_rMme[open]:not(.isBrowser_hcAL)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;top:0;bottom:0;visibility:hidden;left:0}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.after\:blur-\[var\(--after-blur\)\]:after,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.flex,.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_KIGE,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.h-full,.navbar__logo img,body,html{height:100%}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}#nprogress,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}:root,[data-theme=dark],html[data-theme=light]{--ifm-menu-color-background-active:#ff9ff330}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.DocSearch-Button,.DocSearch-Link,.DocSearch-Prefill,.DocSearch-Reset,.cursor-pointer,.dropdownNavbarItemMobile_p8nV,.hover\:cursor-pointer:hover,.pills__item,.tab_J4Y8,.tabs__item{cursor:pointer}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.overflow-x-auto,.tabs{overflow-x:auto}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover,.shadow-\[inset_0_-8px_10px_\#8fdfff1f\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.group:hover .group-hover\:translate-x-0\.5,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.inline-flex,.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_bW6b>li)>.containsTaskList_bW6b{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.transition,.transition-all,.transition-shadow,.transition-transform{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--sidebar-category-c:var(--c-gray-0);--sidebar-border-c:var(--c-gray-90);--ifm-menu-color:var(--c-gray-20);--note-color:#e3e3e3;--admonition-tip-border:var(--c-green-50);--admonition-tip-color:var(--c-green-50);--admonition-note-c-bg:#0000;--admonition-info-c-bg:#0000;--admonition-tip-c-bg:#0000;--admonition-warning-c-bg:#0000;--admonition-caution-c-bg:#0000;--admonition-danger-c-bg:#0000;--admonition-info-c-color:var(--c-blue-50);--admonition-tip-c-color:var(--c-green-50);--admonition-warning-c-color:var(--c-yellow-50);--admonition-caution-c-color:var(--c-orange-50);--admonition-danger-c-color:var(--c-red-50);--ifm-alert-tip-background-color:var(--c-green-50-a);--admonition-code-warning-c-bg:var(--c-yellow-50-a);--admonition-code-info-c-bg:#00163d;--admonition-code-tip-c-bg:#003d11;--admonition-code-caution-c-bg:#3d1200;--admonition-code-danger-c-bg:#3d0003;--ifm-alert-warning-background-color:var(--c-yellow-30-a);--c-brand:#ff73ec90;--c-yellow-50:#f9d76f;--c-yellow-50-a:#ffd75a60;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.302);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}html[data-theme=light]{--sidebar-category-c:var(--c-gray-100);--sidebar-border-c:var(--c-gray-0);--ifm-menu-color:var(--c-indigo-80);--note-color:#241800;--admonition-note-c-bg:linear-gradient(to bottom,var(--ifm-alert-note-background-color),#0000 40%);--admonition-info-c-bg:linear-gradient(to bottom,var(--ifm-alert-info-background-color),#0000 40%);--admonition-tip-c-bg:linear-gradient(to bottom,var(--ifm-alert-tip-background-color),#0000 40%);--admonition-warning-c-bg:linear-gradient(to bottom,var(--ifm-alert-warning-background-color),#0000 40%);--admonition-caution-c-bg:linear-gradient(to bottom,var(--ifm-alert-caution-background-color),#0000 40%);--admonition-danger-c-bg:linear-gradient(to bottom,var(--ifm-alert-danger-background-color),#0000 40%);--admonition-info-c-color:inherit;--admonition-tip-c-color:inherit;--admonition-warning-c-color:inherit;--admonition-caution-c-color:inherit;--admonition-danger-c-color:inherit;--admonition-code-info-c-bg:var(--c-teal-20);--admonition-code-warning-c-bg:var(--c-yellow-20);--admonition-code-tip-c-bg:var(--c-green-20);--admonition-code-caution-c-bg:var(--c-orange-20);--admonition-code-danger-c-bg:var(--c-red-10);--admonition-tip-border:var(--c-green-100);--admonition-tip-color:var(--c-green-100);--ifm-alert-warning-background-color:var(--c-yellow-10);--ifm-alert-tip-background-color:var(--c-green-10);--ifm-alert-danger-background-color:var(--c-red-10);--ifm-alert-note-background-color:#ff9ff360;--ifm-alert-info-background-color:var(--c-teal-10);--ifm-alert-caution-background-color:var(--c-green-10)}[class^=docRoot_]{width:1440px!important}.links_A3uT,.sp-link_GRPb,[class^=docsWrapper_]{display:flex;justify-content:center}#__docusaurus .theme-doc-sidebar-container{background:var(--token-primary-bg-c);border-inline-end:1px solid var(--sidebar-border-c);bottom:0;height:calc(100vh - 60px);margin-block-start:0;position:sticky;top:60px;will-change:auto}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a{align-items:center;display:flex;height:var(--ifm-navbar-height)}#__docusaurus .theme-doc-sidebar-container [class^=sidebarViewport]>a,#__docusaurus [class^=sidebar_]{padding-inline-end:var(--sidebar-spacing-horizontal);padding-inline-start:var(--sidebar-spacing-horizontal)}#__docusaurus [class^=sidebar_]{max-height:100vh;overflow-y:auto;padding-block-start:1rem;position:static}#__docusaurus [class^=sidebar_]>.menu{overflow-x:initial;padding-block-end:2rem;padding:0}#__docusaurus [class^=sidebarLogo]{display:none!important}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list,.codeBlockStandalone_yM_Q,.p-0{padding:0}#__docusaurus .menu__list{transition:height .35s cubic-bezier(.36,.66,.04,1) 25ms!important;will-change:auto!important}#__docusaurus .menu__list .menu__list .menu__link--sublist{margin-inline-start:calc((var(--dropdown-icon-width) + var(--dropdown-icon-gap))*-1)}#__docusaurus .menu__list .menu__list .menu__link--sublist:after,.header-github-link:hover{opacity:.6}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1{padding-inline-start:calc(var(--dropdown-icon-width))}#__docusaurus .menu__list-item.theme-doc-sidebar-item-link-level-1>.menu__link{color:var(--sidebar-category-c);font-size:14px;font-weight:500}#__docusaurus .menu__list-item:not(:first-child){margin-block-start:0}#__docusaurus .menu__list-item .menu__list .menu__link{padding-inline-start:calc(var(--dropdown-icon-width) + var(--dropdown-icon-gap));padding:7px 10px}#__docusaurus .menu__list-item-collapsible,.block{display:block}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list>.menu__list-item:last-of-type{padding-block-end:.5rem}#__docusaurus .theme-doc-sidebar-item-category-level-1:last-of-type{margin-block-end:.5rem}#__docusaurus .menu__link{align-items:center;display:flex;font-size:.85rem;font-weight:500;letter-spacing:-.01em;line-height:16px;transition:opacity .2s ease-out}#__docusaurus .menu__link:not(.menu__link--active:not(.menu__link--sublist)){background:initial}#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):active,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):focus,#__docusaurus .menu__link:not(.menu__link--active):not(.menu__link--sublist):hover{opacity:.7}#__docusaurus .menu__link--sublist{align-items:center;display:flex;flex-direction:row-reverse;justify-content:flex-end;margin-block-end:0;padding-inline-end:0;padding-inline-start:0}#__docusaurus .menu__link--sublist:after{background:var(--ifm-menu-link-sublist-icon) center/var(--dropdown-icon-width) var(--dropdown-icon-height);background-repeat:no-repeat;height:var(--dropdown-icon-height);margin-block-end:0;margin-inline-end:var(--dropdown-icon-gap);margin-inline-start:unset;min-width:auto;width:var(--dropdown-icon-width)}#__docusaurus .theme-doc-sidebar-item-category-level-1>.menu__list-item-collapsible .menu__link{color:var(--sidebar-category-c);font-size:.938rem;font-weight:600;line-height:100%}html[data-theme=light] body{--angle:220deg;background-attachment:fixed;background-image:linear-gradient(var(--angle),#fff 15%,rgba(255,159,243,.376) 20%,#fff 25%,#f4eef8 30%,#fff 35%,#f8edf5 40%,#fff 60%);background-size:cover}.theme-admonition{border:none;position:relative;--ifm-alert-padding-horizontal:2rem;--ifm-alert-padding-vertical:1.5rem}.theme-admonition [class^=admonitionHeading_]{font-size:1rem;line-height:1.6;text-transform:capitalize}.theme-admonition [class^=admonitionHeading_] [class^=admonitionIcon_]{display:none}.theme-admonition [class^=admonitionContent_] p a{color:var(--admonition-link-c);text-decoration:underline}.theme-admonition [class^=admonitionContent_] p code{background:var(--admonition-code-c-bg)}.theme-admonition-warning{--admonition-code-c-bg:var(--admonition-code-warning-c-bg);background:#0000;border:2px solid var(--c-yellow-90-a);color:var(--c-yellow-90)}.theme-admonition-note{--admonition-code-c-bg:var(--admonition-code-note-c-bg);background:#0000;border:2px solid var(--c-brand-a);color:var(--c-brand)}.theme-admonition-info{--ifm-alert-background-color:var(--c-teal-210);--admonition-bar-c-bg:var(--admonition-bar-info-c-bg);--admonition-code-c-bg:var(--admonition-code-info-c-bg);--admonition-link-c:var(--admonition-link-info-c);background:#0000;border:2px solid var(--c-teal-60);color:var(--c-teal-90)}.theme-admonition-tip{--admonition-bar-c-bg:var(--admonition-bar-tip-c-bg);--admonition-code-c-bg:var(--admonition-code-tip-c-bg);--admonition-link-c:var(--admonition-link-tip-c);background:#0000;border:2px solid var(--admonition-tip-border);color:var(--admonition-tip-color)}.theme-admonition-caution{--ifm-alert-background-color:var(--admonition-caution-c-bg);--admonition-bar-c-bg:var(--admonition-bar-caution-c-bg);--admonition-code-c-bg:var(--admonition-code-caution-c-bg);--admonition-link-c:var(--admonition-link-caution-c);background:#0000}.theme-admonition-danger,.theme-admonition-important{--admonition-bar-c-bg:var(--admonition-bar-danger-c-bg);--admonition-code-c-bg:var(--admonition-code-danger-c-bg);--admonition-link-c:var(--admonition-link-danger-c)}.theme-admonition-danger{--ifm-alert-background-color:var(--admonition-danger-c-bg);background:#0000;border:2px solid var(--c-red-50-a);color:var(--c-red-50)}.theme-admonition-important{--ifm-alert-background-color:var(--c-lavender-210);background:linear-gradient(to bottom,var(--ifm-alert-background-color),#0000);border:2px solid var(--c-lavender-220)}:root{--admonition-bar-note-c-bg:var(--c-yellow-80);--admonition-bar-info-c-bg:var(--c-blue-80);--admonition-bar-tip-c-bg:var(--c-green-80);--admonition-bar-caution-c-bg:var(--c-orange-80);--admonition-bar-danger-c-bg:var(--c-red-60);--admonition-link-note-c:var(--c-brand);--admonition-link-info-c:var(--c-teal-90);--admonition-link-tip-c:var(--c-green-60);--admonition-color-tip-c:var(--note-color);--admonition-color-note-c:var(--note-color);--admonition-link-caution-c:var(--c-orange-90);--admonition-link-danger-c:var(--c-red-60);--c-black:#000;--c-white:#fff;--c-blue-0:#f0f6ff;--c-blue-10:#e3edff;--c-blue-20:#cddfff;--c-blue-30:#b2ceff;--c-blue-40:#97bdff;--c-blue-50:#7cabff;--c-blue-60:#639bff;--c-blue-70:#4d8dff;--c-blue-80:#3880ff;--c-blue-90:#176bff;--c-blue-100:#0054e9;--c-blue-110:#004dd6;--c-blue-120:#0046c1;--c-blue-130:#003fae;--c-blue-140:#00389b;--c-blue-150:#002d7c;--c-blue-160:#002669;--c-blue-170:#001d52;--c-blue-180:#001740;--c-blue-190:#00112f;--c-blue-200:#000b1f;--c-gray-0:#f3f3f3;--c-gray-10:#e4e4e4;--c-gray-20:#c8c8c8;--c-gray-30:#aeaeae;--c-gray-40:#959595;--c-gray-50:#818181;--c-gray-60:#6d6d6d;--c-gray-70:#5f5f5f;--c-gray-80:#474747;--c-gray-90:#2f2f2f;--c-gray-100:#141414;--c-carbon-0:#eef1f3;--c-carbon-10:#d7dde2;--c-carbon-20:#b4bcc6;--c-carbon-30:#98a2ad;--c-carbon-40:#7d8894;--c-carbon-50:#677483;--c-carbon-60:#556170;--c-carbon-70:#434f5e;--c-carbon-80:#35404e;--c-carbon-90:#222d3a;--c-carbon-100:#03060b;--c-indigo-0:#fbfbfd;--c-indigo-10:#f6f8fc;--c-indigo-20:#e9edf3;--c-indigo-30:#dee3ea;--c-indigo-40:#ced6e0;--c-indigo-50:#b2becd;--c-indigo-60:#92a0b3;--c-indigo-70:#73849a;--c-indigo-80:#445b78;--c-indigo-90:#2d4665;--c-indigo-100:#001a3a;--c-green-0:#f1fdf5;--c-green-10:#deffe7;--c-green-20:#c7fbd5;--c-green-30:#a7f1bb;--c-green-40:#80e89d;--c-green-50:#62e085;--c-green-50-a:#62e08560;--c-green-60:#4ada71;--c-green-70:#2dd55b;--c-green-80:#17c948;--c-green-90:#00ba33;--c-green-100:#00a52d;--c-green-110:#009b2b;--c-green-120:#009128;--c-green-130:#008725;--c-green-140:#007d22;--c-green-150:#00711f;--c-green-160:#00661c;--c-green-170:#00581a;--c-green-180:#004314;--c-green-190:#002f0e;--c-green-200:#001807;--c-lime-0:#f5fff0;--c-lime-10:#ebfee3;--c-lime-20:#ddfcd0;--c-lime-30:#cffbbc;--c-lime-40:#bbf9a2;--c-lime-50:#a3f581;--c-lime-60:#8bf35f;--c-lime-70:#64ec44;--c-lime-80:#4ddf2b;--c-lime-90:#3ad515;--c-lime-100:#27c100;--c-lime-110:#25b400;--c-lime-120:#22a400;--c-lime-130:#1e9200;--c-lime-140:#1a7e00;--c-lime-150:#176d00;--c-lime-160:#135a00;--c-lime-170:#0f4900;--c-lime-180:#0c3900;--c-lime-190:#092c00;--c-lime-200:#061d00;--c-lavender-0:#f7f8ff;--c-lavender-10:#e6ebff;--c-lavender-20:#ced9ff;--c-lavender-30:#b6c6ff;--c-lavender-40:#9fb5ff;--c-lavender-50:#8aa4ff;--c-lavender-60:#7493ff;--c-lavender-70:#597eff;--c-lavender-80:#3c67ff;--c-lavender-90:#194bfd;--c-lavender-100:#0033e8;--c-lavender-110:#002dcc;--c-lavender-120:#0028b8;--c-lavender-130:#0023a2;--c-lavender-140:#002092;--c-lavender-150:#001a79;--c-lavender-160:#001560;--c-lavender-170:#00114e;--c-lavender-180:#000e41;--c-lavender-190:#000a30;--c-lavender-200:#000721;--c-lavender-210:#8aa4ff50;--c-lavender-220:#7493ff40;--c-purple-0:#f4f4ff;--c-purple-10:#e9eaff;--c-purple-20:#d0d2ff;--c-purple-30:#b6b9f9;--c-purple-40:#9a99fc;--c-purple-50:#8482fb;--c-purple-60:#786df9;--c-purple-70:#6e5afd;--c-purple-80:#6030ff;--c-purple-90:#4712fb;--c-purple-100:#3400e6;--c-purple-110:#3000d1;--c-purple-120:#2b00bc;--c-purple-130:#2600a6;--c-purple-140:#20008e;--c-purple-150:#1b0075;--c-purple-160:#15005c;--c-purple-170:#100048;--c-purple-180:#0d0038;--c-purple-190:#0b0030;--c-purple-200:#080022;--c-brand:#8f1a7f;--c-brand-a:#8f1a7f60;--c-pink-0:#ffeff5;--c-pink-10:#ffe3ed;--c-pink-20:#ffd8e5;--c-pink-30:#ffc9db;--c-pink-40:#ffb6d0;--c-pink-50:#ff99bd;--c-pink-60:#ff80ac;--c-pink-70:#ff6098;--c-pink-80:#fb4082;--c-pink-90:#ec216a;--c-pink-100:#da0d56;--c-pink-110:#d0004a;--c-pink-120:#c40046;--c-pink-130:#b30040;--c-pink-140:#a3003b;--c-pink-150:#940035;--c-pink-160:#850030;--c-pink-170:#710029;--c-pink-180:#5f0022;--c-pink-190:#460019;--c-pink-200:#20000b;--c-red-0:#fff1f3;--c-red-10:#ffe6e8;--c-red-20:#ffcfd3;--c-red-30:#feb7bc;--c-red-40:#fc9aa2;--c-red-50:#f9838c;--c-red-50-a:#f9838c60;--c-red-60:#f56570;--c-red-70:#f24c58;--c-red-80:#ef3442;--c-red-90:#e21827;--c-red-100:#d0000f;--c-red-110:#c5000f;--c-red-120:#b3000e;--c-red-130:#9c000c;--c-red-140:#89000b;--c-red-150:#760009;--c-red-160:#650008;--c-red-170:#520006;--c-red-180:#410005;--c-red-190:#300004;--c-red-200:#1d0002;--c-red-210:#f24c5830;--c-red-220:#ef344215;--c-orange-0:#fff5f0;--c-orange-10:#ffede6;--c-orange-20:#ffdfd1;--c-orange-30:#ffd0bc;--c-orange-40:#ffc0a5;--c-orange-50:#ffaf8c;--c-orange-60:#ff9b70;--c-orange-70:#ff8753;--c-orange-80:#ff7336;--c-orange-90:#ff5b13;--c-orange-100:#eb4700;--c-orange-110:#d94200;--c-orange-120:#c93d00;--c-orange-130:#b63700;--c-orange-140:#a53200;--c-orange-150:#8c2a00;--c-orange-160:#772400;--c-orange-170:#5e1c00;--c-orange-180:#481600;--c-orange-190:#341000;--c-orange-200:#1d0900;--c-yellow-0:#fffbef;--c-yellow-10:#fff8e2;--c-yellow-20:#fff4d1;--c-yellow-30:#ffefbd;--c-yellow-30-a:#fcd28550;--c-yellow-40:#ffe9a3;--c-yellow-50:#ffcb2d;--c-yellow-50-a:#ffd75a60;--c-yellow-60:#ffd75a;--c-yellow-60-a:#ffd75a30;--c-yellow-70:#ffce31;--c-yellow-80:#ffc409;--c-yellow-90:#f4b100;--c-yellow-90-a:#f4b10060;--c-yellow-100:#eaa100;--c-yellow-110:#dd9800;--c-yellow-120:#cc8d00;--c-yellow-130:#be8300;--c-yellow-140:#b17a00;--c-yellow-150:#9c6c00;--c-yellow-160:#8a6000;--c-yellow-170:#755100;--c-yellow-180:#5f4100;--c-yellow-190:#452f00;--c-yellow-200:#231800;--c-yellow-210:#ffc40950;--c-yellow-220:#ffce3140;--c-aqua-0:#f0fff9;--c-aqua-10:#e6fff6;--c-aqua-20:#ceffed;--c-aqua-30:#b7fce3;--c-aqua-40:#93f9d5;--c-aqua-50:#79f5c9;--c-aqua-60:#59f0ba;--c-aqua-70:#38e9aa;--c-aqua-80:#1ae19a;--c-aqua-90:#00d287;--c-aqua-100:#00ba78;--c-aqua-110:#00aa6d;--c-aqua-120:#009b63;--c-aqua-130:#00915c;--c-aqua-140:#008152;--c-aqua-150:#016e46;--c-aqua-160:#015d3c;--c-aqua-170:#014f32;--c-aqua-180:#013e28;--c-aqua-190:#012e1e;--c-aqua-200:#011e13;--c-teal-0:#eefeff;--c-teal-10:#dffdff;--c-teal-20:#d0fdff;--c-teal-30:#bbfcff;--c-teal-40:#a2fcff;--c-teal-50:#8bfbff;--c-teal-60:#73f6fb;--c-teal-60-a:#73f6fb60;--c-teal-70:#55ecf2;--c-teal-80:#35e2e9;--c-teal-90:#1bd2d9;--c-teal-100:#00b9c0;--c-teal-110:#01adb4;--c-teal-120:#019fa5;--c-teal-130:#018f94;--c-teal-210:#3dc1d340;--c-teal-220:#3dc1d325;--c-teal-140:#017e83;--c-teal-150:#016d71;--c-teal-160:#015d61;--c-teal-170:#014d4f;--c-teal-180:#013c3e;--c-teal-190:#012c2e;--c-teal-200:#011c1d;--c-cyan-0:#f3faff;--c-cyan-10:#e8f5ff;--c-cyan-20:#d3ecff;--c-cyan-30:#bfe4ff;--c-cyan-40:#a7daff;--c-cyan-50:#8dcfff;--c-cyan-60:#77c6ff;--c-cyan-70:#62bdff;--c-cyan-80:#46b1ff;--c-cyan-90:#24a3ff;--c-cyan-100:#0091fa;--c-cyan-110:#0189ec;--c-cyan-120:#017ed8;--c-cyan-130:#0170c0;--c-cyan-140:#0163aa;--c-cyan-150:#015592;--c-cyan-160:#01487b;--c-cyan-170:#013a64;--c-cyan-180:#012d4d;--c-cyan-190:#011e33;--c-cyan-200:#01121e;--sans-serif:-apple-system,BlinkMacSystemFont,san-francisco,Avenir Next,Segoe UI,Roboto,Noto Sans,Helvetica Neue;--serif:Iowan Old Style,Apple Garamond,Baskerville,Times New Roman;--monospaced:Menlo;--border:#03a9f4;--g1:#0003;--g2:#8f1a7f33;--g3:#1f1f1f33;--ifm-color-primary:#8f1a7f;--ifm-color-primary-dark:#6f1a5f;--ifm-color-primary-text:#6f1a5f;--ifm-color-primary-darker:#5f1a4f;--ifm-color-primary-darkest:#4f1a3f;--ifm-color-primary-light:#9f1a8f;--ifm-color-primary-lighter:#af1a9f;--ifm-color-primary-lightest:#bf1aaf;--ifm-code-font-size:95%;--ifm-border-color:#0000000d;--ifm-background:#00000003;--ifm-announcementBar-height:40px;--ifm-primary-hue-saturation:308 78%;--ifm-primary-hue-saturation-light:308 78%;--accent:113,26,95;--accent-background-card-gradient:linear-gradient(45deg,rgb(var(--accent)),#fda7df 10%,var(--ifm-f-white) 40%);--ifm-f-white:#fff;--ifm-f-re-white:#181818;--ifm-f-white-soft:#f8f8f8;--ifm-f-white-mute:#f2f2f2;--ifm-f-bg-soft:#f6f6f7;--farm--border:rgba(86,86,86,.125);--docsearch-searchbox-background:#8f1a7fb3;--max-layout-width:1680px;--ifm-navbar-link-hover-color:initial;--ifm-navbar-padding-vertical:0;--ifm-navbar-item-padding-vertical:0;--ifm-font-family-base:-apple-system,BlinkMacSystemFont,Inter,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI emoji";--ifm-font-family-monospace:"SFMono-Regular","Roboto Mono",Consolas,"Liberation Mono",Menlo,Courier,monospace;--ifm-menu-link-sublist-icon:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSI2IiBmaWxsPSJub25lIj48cGF0aCBzdHJva2U9IiMwMzA2MEIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjUiIGQ9Ik05IDUgNSAxIDEgNSIvPjwvc3ZnPg==");--z-sidebar:2000;--z-backdrop:1100;--ifm-menu-color-background:#ff9ff310;--docusaurus-highlighted-code-line-bg:#ff9ff310;--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base);--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--dm-color-brand:#3451b2;--dm-color-bg-alt:#f6f6f7;--dm-color-hint:#3c3c43c7;--dm-button-font-size:13px;--dm-button-height:40px;--dm-c-white:#fff;--dm-text-color:#374151;--dm-modal-bg-color:var(--dm-c-white);--dm-divider-color:#f3f4f6;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.container,.w-full{width:100%}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.absolute{position:absolute}.chat-container[data-v-3926b6c7],.relative{position:relative}.inset-0{inset:0}.z-10{z-index:10}.m-auto{margin:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-10{margin-bottom:2.5rem;margin-top:2.5rem}.my-14{margin-bottom:3.5rem;margin-top:3.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-8{margin-bottom:2rem;margin-top:2rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.mt-10{margin-top:2.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.loader_KTq1,.mt-8{margin-top:2rem}.inline,.tags_y0VJ{display:inline}.grid{display:grid}.size-3{height:.75rem;width:.75rem}.size-4{height:1rem;width:1rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.documate-button .icon[data-v-956ba6e9],.h-4{height:1rem}.h-52{height:13rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.min-h-\[2rem\]{min-height:2rem}.min-h-\[inherit\]{min-height:inherit}.w-16{width:4rem}.w-20{width:5rem}.w-36{width:9rem}.w-40{width:10rem}.w-6{width:1.5rem}.w-9\/12{width:75%}.w-\[1px\]{width:1px}.max-w-7xl{max-width:80rem}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}@keyframes a{0%,90%,to{background-position:calc(-100% - var(--shimmer-width)) 0}30%,60%{background-position:calc(100% + var(--shimmer-width)) 0}}.animate-shimmer{animation:8s infinite a}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center,.mdxPageWrapper_Xr2N{justify-content:center}.justify-between{justify-content:space-between}.gap-10{gap:2.5rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-5{column-gap:1.25rem}.gap-y-12{row-gap:3rem}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.self-start{align-self:flex-start}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[var\(--border-radius\)\]{border-radius:var(--border-radius)}.rounded-\[var\(--card-content-radius\)\]{border-radius:var(--card-content-radius)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-black\/5{border-color:#0000000d}.bg-fuchsia-600{background-color:rgb(192 38 211/var(--tw-bg-opacity))}.bg-gray-100{background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-500{background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-neutral-100{background-color:rgb(245 245 245/var(--tw-bg-opacity))}.bg-white\/40{background-color:#fff6}.bg-zinc-950{background-color:rgb(9 9 11/var(--tw-bg-opacity))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-\[\#ffaa40\]{--tw-gradient-from:#ffaa40 var(--tw-gradient-from-position)}.from-\[\#ffaa40\]\/50{--tw-gradient-from:#ffaa4080 var(--tw-gradient-from-position)}.from-transparent{--tw-gradient-from:#0000 var(--tw-gradient-from-position);--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.via-\[\#9c40ff\],.via-\[\#9c40ff\]\/50{--tw-gradient-to:#9c40ff00 var(--tw-gradient-to-position)}.via-\[\#9c40ff\]{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-\[\#9c40ff\]\/50{--tw-gradient-stops:var(--tw-gradient-from),#9c40ff80 var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-black\/80{--tw-gradient-to:#0000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#000c var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-50\%{--tw-gradient-via-position:50%}.to-\[\#ffaa40\]{--tw-gradient-to:#ffaa40 var(--tw-gradient-to-position)}.to-\[\#ffaa40\]\/50{--tw-gradient-to:#ffaa4080 var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:#0000 var(--tw-gradient-to-position)}.bg-\[length\:var\(--bg-size\)_100\%\]{background-size:var(--bg-size) 100%}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.p-2{padding:.5rem}.p-6{padding:1.5rem}.p-\[1px\]{padding:1px}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.text-left{text-align:left}.data_ODnV,.kbd-text[data-v-3926b6c7],.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.tracking-wide{letter-spacing:.025em}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-neutral-600\/50{color:#52525280}.text-transparent{color:#0000}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow-\[inset_0_-8px_10px_\#8fdfff1f\]{--tw-shadow:inset 0 -8px 10px #8fdfff1f;--tw-shadow-colored:inset 0 -8px 10px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter}.transition-all{transition-property:all}.transition-shadow{transition-property:box-shadow}.transition-transform{transition-property:transform}.duration-200{transition-duration:.2s}.duration-300,.hover\:duration-300:hover{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--bg-size\:300\%\]{--bg-size:300%}.\[background-position\:0_0\]{background-position:0 0}.\[background-size\:var\(--shimmer-width\)_100\%\]{background-size:var(--shimmer-width) 100%}.\[border-radius\:inherit\]{border-radius:inherit}.\!\[mask-composite\:subtract\]{-webkit-mask-composite:source-out!important;mask-composite:subtract!important}.\[mask\:linear-gradient\(\#fff_0_0\)_content-box\2c linear-gradient\(\#fff_0_0\)\]{-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0)}[data-theme=dark]{--ifm-f-bg-soft:#252529;--ifm-background-color:#000!important;--ifm-color-primary:#fff;--ifm-color-primary-text:#fff;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--ifm-menu-color-background:#ff9ff340;--ifm-background:#0000004d;--ifm-f-white:#c74040;--ifm-f-re-white:#fff;--ifm-f-white-soft:#222;--ifm-f-white-mute:#282828;--farm--border:#fafafa20;--docusaurus-highlighted-code-line-bg:#8f1a7fb3;--docsearch-primary-color:var(--ifm-color-primary-dark)!important;--docsearch-searchbox-background:#3a3a3a!important}.navbar__title{color:#6f1a5f;font-size:1.5em}.navbar__title:hover{color:#bf1aaf}.header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat;content:"";display:flex;height:20px;width:20px}[data-theme=dark] .header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.bg{background-color:var(--ifm-f-white-soft)}.bg-re{background-color:var(--ifm-f-re-white)}.color{color:var(--ifm-f-white)}.token.color{color:#c44cac}.color-re{color:var(--ifm-f-re-white)}.theme-back-to-top-button{height:50px!important;width:50px!important}[class^=backToTopButton_]:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:3rem 3rem!important;-webkit-mask-size:3rem 3rem!important}.clean-btn:after{-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask:var(--ifm-menu-link-sublist-icon) 50%/1.5rem 1.5rem no-repeat!important;mask-size:1.5rem 1.5rem!important;-webkit-mask-size:1.5rem 1.5rem!important}div[class^=announcementBar_]{--site-announcement-bar-stripe-color1:hsl(var(--ifm-primary-hue-saturation) 85%);--site-announcement-bar-stripe-color2:hsl(var(--ifm-primary-hue-saturation) 95%);background:linear-gradient(45deg,#711a5f,#c44cac 30%,#9f1a8f 60%,#fda7df 80%);color:var(--c-white);font-weight:700;height:var(--ifm-announcementBar-height)}footer[class=footer]{background-color:var(--ifm-f-white-soft)!important}.footer__link-item{gap:6px;line-height:3}.DocSearch-Button-Container,.footer__link-item,.navbar__link{align-items:center;display:flex}.code-block-highlight-line{background-color:var(--docusaurus-highlighted-code-line-bg);border-left:5px solid #c44cac;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.DocSearch-Button{border-radius:8px!important;width:250px}.theme-admonition-warning{color:var(--c-yellow-120)}.theme-admonition-danger{color:var(--c-red-60)}.theme-doc-version-badge{margin:10px 0}.navbar--fixed-top{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background:#0000;box-shadow:0 4px 10px #00000014}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}figure{margin:12px}.after\:absolute:after,.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:left-0:before{content:var(--tw-content);left:0}.before\:right-0:before{content:var(--tw-content);right:0}.before\:top-\[-var\(--border-size\)\]:before{content:var(--tw-content);top:-var(--border-size)}.after\:-z-10:after,.before\:z-\[-10\]:before{content:var(--tw-content);z-index:-10}.after\:block:after,.before\:block:before{content:var(--tw-content);display:block}.after\:h-\[var\(--pseudo-element-height\)\]:after,.before\:h-\[var\(--pseudo-element-height\)\]:before{content:var(--tw-content);height:var(--pseudo-element-height)}.before\:w-full:before{content:var(--tw-content);width:100%}.after\:animate-backgroundPositionSpin:after,.before\:animate-backgroundPositionSpin:before{animation:3s infinite alternate b;content:var(--tw-content)}.before\:bg-\[var\(--pseudo-element-background-image\)\]:before{background-color:var(--pseudo-element-background-image);content:var(--tw-content)}.before\:bg-\[length\:200\%_100\%\]:before{background-size:200% 100%;content:var(--tw-content)}.after\:content-\[\'\'\]:after,.before\:content-\[\'\'\]:before{--tw-content:"";content:var(--tw-content)}.after\:-left-\[var\(--border-size\)\]:after{content:var(--tw-content);left:calc(var(--border-size)*-1)}.after\:-top-\[var\(--border-size\)\]:after{content:var(--tw-content);top:calc(var(--border-size)*-1)}.after\:w-\[var\(--pseudo-element-width\)\]:after{content:var(--tw-content);width:var(--pseudo-element-width)}@keyframes b{0%{background-position:top;content:var(--tw-content)}to{background-position:bottom;content:var(--tw-content)}}.after\:rounded-\[var\(--border-radius\)\]:after{border-radius:var(--border-radius);content:var(--tw-content)}.after\:bg-\[linear-gradient\(0deg\2c var\(--neon-first-color\)\2c var\(--neon-second-color\)\2c var\(--neon-third-color\)\)\]:after{background-image:linear-gradient(0deg,var(--neon-first-color),var(--neon-second-color),var(--neon-third-color));content:var(--tw-content)}.after\:bg-\[length\:100\%_200\%\]:after{background-size:100% 200%;content:var(--tw-content)}.after\:opacity-80:after{content:var(--tw-content);opacity:.8}.after\:blur-\[var\(--after-blur\)\]:after{content:var(--tw-content);--tw-blur:blur(var(--after-blur))}.hover\:bg-neutral-200:hover{--tw-bg-opacity:1;background-color:rgb(229 229 229/var(--tw-bg-opacity))}.hover\:text-neutral-600:hover{--tw-text-opacity:1;color:rgb(82 82 82/var(--tw-text-opacity))}.focus\:text-opacity-80:focus,.hover\:text-opacity-80:hover{--tw-text-opacity:0.8}.hover\:shadow-\[inset_0_-5px_10px_\#8fdfff3f\]:hover{--tw-shadow:inset 0 -5px 10px #8fdfff3f;--tw-shadow-colored:inset 0 -5px 10px var(--tw-shadow-color)}.group:hover .group-hover\:translate-x-0\.5{--tw-translate-x:0.125rem}.container__nVC{border-radius:6px;contain:content}}.tab-list_aJ1t{display:flex;min-width:100%;overflow-x:scroll;padding:4px 0 8px 8px}.tab_J4Y8{border-bottom:2px solid #0000;margin-bottom:-1px;margin-right:10px;padding:6px 12px;transition:.2s ease-in-out;user-select:none}.tab_J4Y8:last-child{margin-right:0}.selected_erAK{border-color:currentColor}.no-scrollbar_vtMC::-webkit-scrollbar{display:none}.no-scrollbar_vtMC{-ms-overflow-style:none;scrollbar-width:none}.backToTopButton_jRRJ{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_jRRJ:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_AHoy{opacity:1;transform:scale(1);visibility:visible}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;color:var(--docsearch-muted-color);display:flex;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch-Button-Key--pressed{box-shadow:var(--docsearch-key-pressed-shadow);transform:translate3d(0,1px,0)}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a,.sidebarItemLink_KhnB:hover{text-decoration:none}.DocSearch-Hit[aria-selected=true] mark,.content_hAup a{text-decoration:underline}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset,p[data-v-3926b6c7],ul[data-v-3926b6c7]{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards c;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.sidebar_Ap_S,.tableOfContents_b1mW{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem)}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}#__docusaurus-base-url-issue-banner-container,.button-placeholder[data-v-3926b6c7],.docSidebarContainer_wnoZ,.loading.hide[data-v-3926b6c7],.navbarSearchContainer_ws2C:empty,.sidebarLogo_XkDA,.themedComponent_qoxx,[data-theme=dark] .lightToggleIcon_mtGR,[data-theme=light] .darkToggleIcon_a9bq,html[data-announcement-bar-initially-dismissed=true] .announcementBar_NAgQ,svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon,.tocCollapsibleContent_UQzg a{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands li,.DocSearch-Commands-Key,.buttons_AeoN{align-items:center;display:flex}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@keyframes c{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container,.skipToContent_SvOr{z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_SvOr{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem}.skipToContent_SvOr:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_U3lQ{line-height:0;padding:0}.content_hAup{font-size:85%;padding:5px 0;text-align:center}.content_hAup a{color:inherit}.announcementBar_NAgQ{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_ZgHP{flex:0 0 10px}.announcementBarClose_iOKh{align-self:stretch;flex:0 0 30px}.toggle_eG47{height:2rem;width:2rem}.toggleButton_SA1E{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_SA1E:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_bPAB{cursor:not-allowed}.darkNavbarColorModeToggle_UyoV:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_kvRy,[data-theme=light] .themedComponent--light_lACA,html:not([data-theme]) .themedComponent--light_lACA{display:initial}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_igfI{display:none;margin:0}.iconExternalLink_rCHH{margin-left:.3rem}.docMainContainer_HtRu,.docRoot_DxwR{display:flex;width:100%}.docsWrapper__6U0{display:flex;flex:1 0 auto}.iconLanguage_muqp{margin-right:5px;vertical-align:text-bottom}.dark{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-divider-color:#2e2e32}.sp_EK1s .sp-link_GRPb.link_ib43:focus,.sp_EK1s .sp-link_GRPb.link_ib43:hover,body:not(.navigation-with-keyboard) :not(input):focus,input[data-v-3926b6c7],input[data-v-3926b6c7]:focus{outline:0}.enter[data-v-3926b6c7]{transition:opacity .2s ease-out}.enter-from[data-v-3926b6c7],.leave-to[data-v-3926b6c7]{opacity:0}.leave[data-v-3926b6c7]{transition:opacity .1s ease-in}.transition-child-ref[data-v-3926b6c7]{bottom:0;left:0;position:fixed;right:0;top:0;transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dialog[data-v-3926b6c7]{background-color:var(--dm-mask-bg-color);bottom:0;left:0;overflow-y:auto;position:fixed;right:0;top:0;z-index:999999}.dialog-container[data-v-3926b6c7]{padding:1rem}.dialog-panel[data-v-3926b6c7]{background-color:var(--dm-modal-bg-color);border-radius:.75rem;box-shadow:0 25px 50px -12px #00000040;margin:0 auto;max-width:36rem;overflow:hidden;transition-duration:.3s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.magnifying-glass-icon[data-v-3926b6c7]{color:var(--dm-text-color);height:1.25rem;left:1rem;pointer-events:none;position:absolute;top:.875rem;width:1.25rem}.chat-input[data-v-3926b6c7]{background-color:initial;border-width:0;border-bottom:1px solid var(--dm-divider-color);box-sizing:border-box;color:var(--dm-text-color);height:3rem;padding-left:2.75rem;padding-right:1rem;width:100%}.chat-input[data-v-3926b6c7]::placeholder{font-size:1rem}.combobox-options[data-v-3926b6c7]{list-style:none;max-height:20rem;min-height:5rem;overflow-y:auto;padding:1rem;scroll-padding-bottom:.5rem;scroll-padding-top:2.5rem}.combobox-option[data-v-3926b6c7]{cursor:pointer;display:flex;padding:.5rem 1rem;-webkit-user-select:none;user-select:none}.combobox-options-container[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;margin-left:-1rem;margin-right:-1rem;margin-top:.5rem}.active[data-v-3926b6c7]{background-color:var(--dm-highlight-color);color:var(--dm-c-white)}.combobox-options-name[data-v-3926b6c7]{flex:1 1 auto;margin-left:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.loading[data-v-3926b6c7]{align-items:center;display:flex;justify-content:left;padding:1rem 1rem 1rem 2.6rem}.loading-spin[data-v-3926b6c7]{animation:1s linear infinite d;height:1.5rem;margin-right:.5rem;width:1.5rem}.option-icon[data-v-3926b6c7]{flex:none;height:1.5rem;width:1.5rem}.question-anwser-section[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.875rem;list-style:none;max-height:20rem;scroll-padding-bottom:.5rem;scroll-padding-top:.5rem}.question-anwser-item[data-v-3926b6c7]{padding-bottom:.875rem;padding-top:.875rem}.question-role-user[data-v-3926b6c7]{display:flex;gap:1.2rem}.question-role-icon[data-v-3926b6c7]{display:inline-block;flex:none;height:1.5rem;width:1.5rem}.documate-logo[data-v-3926b6c7]{height:1.4rem;width:1.4rem}.result-not-found[data-v-3926b6c7]{padding:3.5rem 1.5rem;text-align:center}.result-not-found-text[data-v-3926b6c7]{color:var(--dm-text-color);font-size:.85rem;margin-top:.5rem}.anwser-content[data-v-3926b6c7]{display:flex;gap:1.5rem}.markdown-body[data-v-3926b6c7]{border-width:0;color:var(--dm-text-color);font-size:.875rem;line-height:1.25rem;list-style:auto;overflow-wrap:break-word}.footer[data-v-3926b6c7]{align-content:center;align-items:center;border-top:1px solid var(--dm-divider-color);color:var(--dm-text-color);display:flex;flex-wrap:wrap;font-size:.75rem;justify-content:space-between;line-height:1rem;padding:.625rem 1rem}.kbd-wrap[data-v-3926b6c7]{align-content:center;display:flex;justify-content:center}.kbd-text[data-v-3926b6c7],.kbd[data-v-3926b6c7]{align-items:center;display:flex;justify-content:center}.kbd[data-v-3926b6c7]{border-radius:.25rem;border-width:1px;font-weight:600;height:1.25rem;margin-left:.25rem;margin-right:.25rem;width:1.25rem}.esc[data-v-3926b6c7]{width:2rem}.powered-by[data-v-3926b6c7]{align-items:center;color:var(--dm-text-color);display:flex;gap:.25rem;justify-content:center;text-decoration:none}@keyframes d{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.dark .hljs{background:#0d1117;color:#c9d1d9}.dark .hljs-doctag,.dark .hljs-keyword,.dark .hljs-meta .hljs-keyword,.dark .hljs-template-tag,.dark .hljs-template-variable,.dark .hljs-type,.dark .hljs-variable.language_{color:#ff7b72}.dark .hljs-title,.dark .hljs-title.class_,.dark .hljs-title.class_.inherited__,.dark .hljs-title.function_{color:#d2a8ff}.dark .hljs-attr,.dark .hljs-attribute,.dark .hljs-literal,.dark .hljs-meta,.dark .hljs-number,.dark .hljs-operator,.dark .hljs-selector-attr,.dark .hljs-selector-class,.dark .hljs-selector-id,.dark .hljs-variable{color:#79c0ff}.dark .hljs-meta .hljs-string,.dark .hljs-regexp,.dark .hljs-string{color:#a5d6ff}.dark .hljs-built_in,.dark .hljs-symbol{color:#ffa657}.dark .hljs-code,.dark .hljs-comment,.dark .hljs-formula{color:#8b949e}.dark .hljs-name,.dark .hljs-quote,.dark .hljs-selector-pseudo,.dark .hljs-selector-tag{color:#7ee787}.dark .hljs-subst{color:#c9d1d9}.dark .hljs-section{color:#1f6feb;font-weight:700}.dark .hljs-bullet{color:#f2cc60}.dark .hljs-emphasis{color:#c9d1d9;font-style:italic}.dark .hljs-strong{color:#c9d1d9;font-weight:700}.dark .hljs-addition{background-color:#033a16;color:#aff5b4}.dark .hljs-deletion{background-color:#67060c;color:#ffdcd7}.documate-button[data-v-956ba6e9]{align-items:center;cursor:pointer;display:flex;height:var(--dm-button-height);justify-content:flex-start;padding-left:.75rem;padding-right:.75rem;transition:border-color .25s ease-in-out}.navbarHideable_sTax{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_E1Ry{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_xnf4{color:red;white-space:pre-wrap}.errorBoundaryFallback_SyQ8{color:red;padding:.55rem}.anchorWithStickyNavbar_poOM{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_jxQw{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_DIHR{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.searchQueryInput_oi46,.searchVersionInput_th2q{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_oi46:focus,.searchVersionInput_th2q:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_oi46::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_cM4p{font-size:.9rem;font-weight:700}.algoliaLogo_Xo7j{max-width:150px}.algoliaLogoPathFill_GjF2{fill:var(--ifm-font-color-base)}.searchResultItem_FT2J{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_xbdO{font-weight:400;margin-bottom:0}.searchResultItemPath_H63Z{color:var(--ifm-color-content-secondary);font-size:.8rem;--ifm-breadcrumb-separator-size-multiplier:1}.searchResultItemSummary_v8kB{font-style:italic;margin:.5rem 0 0}.loadingSpinner_vBIe{animation:1s linear infinite e;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes e{to{transform:rotate(1turn)}}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}.card-container_mQSC:after,.card_L8bV{background:var(--ifm-f-white-soft);border-radius:10px;box-shadow:0 1px 4px #00000029;width:100%;transition:background-position .35s}.features_t9lD{align-items:center;display:flex;padding:2rem 0;width:100%}.item_fAv5{margin:0 auto;width:100%}.card_L8bV{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;padding:2rem .5rem 0;position:relative;z-index:2}.backgroundImage_M6A8{background:linear-gradient(-45deg,#e67ac6 50%,#47caff 0);border-radius:50%;filter:blur(36px)}.card-container_mQSC{cursor:pointer;justify-content:center;position:relative}.card-container_mQSC:hover:before{animation:16s linear infinite f;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;border-radius:10px;content:"";filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;position:absolute;top:-2px;transition:opacity .3s ease-in-out;width:calc(100% + 4px);z-index:-1000}.card-container_mQSC:after{background-image:radial-gradient(#fff3 8%,#0000 0);background-position:0 0;background-size:5vmin 5vmin;content:"";height:100%;left:0;position:absolute;top:0;z-index:100}.card-container-content_HPWq{position:relative;transition:background-position .35s;z-index:1000}@keyframes f{0%,to{background-position:0 0}50%{background-position:400% 0}}.progress-bar-container_Btve{border:1px solid var(--farm--border);border-radius:4px;box-sizing:initial;height:25px;padding:4px;width:50vw}.progress-bar-inner-container_RjNy{background:#9f1a8f;border-radius:2px;height:25px}.progress-bar_MQ9H{background:linear-gradient(90deg,#c026d3,#d2269e);border-radius:2px;height:100%}.font-mono_qmiE{font-family:Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace}}.main_Gz2F{border:2px solid #272727;border-radius:5px;cursor:pointer;height:50px;overflow:hidden;position:relative;width:200px}.container_GXFn,.layer,canvas{height:100%}.fill_bMTX{background:#ff69b4}.content__pcr,.fill_bMTX{height:100%;left:0;position:absolute;top:0;width:100%}.content__pcr{color:#272727}.container_GXFn,.content__pcr{align-items:center;display:flex;justify-content:center}.tabs_FETH{align-items:center;display:flex;flex-direction:column;justify-content:center;width:100%}canvas{margin:0;padding:0;width:100%}.layer{bottom:0;left:0;width:100%}.layer,span.header{pointer-events:none;position:absolute}span.header{display:inline-block;font-size:9em;font-weight:700;left:50px;line-height:.9em;top:350px;transform:translate3d(0,-50%,0);width:500px}.heroBanner_qdFl{overflow:hidden;padding:3rem 0;position:relative;text-align:center}.banner_IlVB,.banner_d9gt{background:linear-gradient(45deg,#711a5f,#fda7df 70%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:#0000;color:#0000}.farmButton2_X03M,.farmButton_siNL{color:#fff;height:50px;outline:0;z-index:0;cursor:pointer}.btn_bvfa{border-radius:8px;border-width:2px;font-family:Open Sans;font-size:1rem;font-style:normal;font-weight:600;line-height:1.5rem;min-width:130px;padding:12px 20px}.farmButton_siNL{background:#111;border:none;border-radius:10px;position:relative}.farmButton_siNL:before{animation:120s linear infinite g;background:linear-gradient(45deg,#7a00ff,#9f1a8f,#7a00ff,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .5s ease-in-out;width:calc(100% + 4px)}.farmButton2_X03M:after,.farmButton2_X03M:before,.farmButton_siNL:after,.farmButton_siNL:before{border-radius:10px;content:"";position:absolute;z-index:-1}.farmButton2_X03M:after,.farmButton_siNL:after{background:#111;height:100%;left:0;top:0;width:100%}.fKVWgc_SGll{inset:0;-webkit-mask-image:linear-gradient(#000,#0000);mask-image:linear-gradient(#000,#0000);position:absolute}.farmButton2_X03M{background:#171717;border:none;border-radius:10px;position:relative}.farmButton2_X03M:before{animation:100s linear infinite g;background:linear-gradient(45deg,#ffaa40,#9f1a8f,#ffaa40,#ff00c8,#9f1a8f,#7a00ff,#ff00c8);background-size:400%;filter:blur(5px);height:calc(100% + 4px);left:-2px;opacity:1;top:-2px;transition:opacity .2s ease-in-out;width:calc(100% + 4px)}@keyframes g{0%,to{background-position:0 0}30%{background-position:400% 0}}.gradientText_nNG0{background:linear-gradient(to bottom right,#000,gray 40%,#fff);-webkit-background-clip:text;color:#0000}.sidebar_Ap_S{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.card-main_mTfv,.teamMembersItem_XVAE{height:100%;overflow:hidden;width:100%}.sidebarItemTitle_Yqc5{font-size:var(--ifm-h3-font-size);font-weight:var(--ifm-font-weight-bold)}.container_qnDr,.sidebarItemList_Blx1{font-size:.9rem}.sidebarItem_EDKM{margin-top:.7rem}.sidebarItemLink_KhnB{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_BKqy{color:var(--ifm-color-primary)!important}.authorCol_lAQD{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_Hnn6{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_YwkJ{margin-left:.3rem;margin-right:.3rem}.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(130px,1fr))}.container_hhjZ{display:grid;gap:40px;margin:0 auto;width:100%}.card-main_mTfv{align-items:center;display:flex;justify-content:center}.card_sVd9{border-radius:8px;transition:box-shadow .5s;will-change:transform}.teamMembersItem_XVAE{border-radius:12px;display:flex;flex-direction:column;gap:2px}.teamMembersItem_XVAE .profile_WQFr{padding:10px}.teamMembersItem_XVAE .avatar_B5t7{cursor:pointer;height:64px;transition:.2s ease-in-out;width:64px}.teamMembersItem_XVAE .name_LD5w{font-size:16px;line-height:24px}.teamMembersItem_XVAE .org_o4tg{font-size:14px;line-height:24px}.teamMembersItem_XVAE .affiliation_rzqG{font-size:14px;line-height:20px;padding-top:4px}.teamMembersItem_XVAE .desc_pfHu{font-size:14px;line-height:20px;padding-top:12px}.teamMembersItem_XVAE .links_A3uT{margin:0 -16px -20px;padding:10px 0 0}.profile_WQFr{align-items:center;display:flex;flex-direction:column;flex-grow:1;gap:20px}.avatar_B5t7{border-radius:50%;flex-shrink:0;margin:0 auto;position:relative}.avatar-img_PAbF{border-radius:50%;bottom:0;left:0;object-fit:cover;position:absolute;right:0;top:0}.name_LD5w{font-weight:600;margin:0}.affiliation_rzqG{font-weight:500;margin:0}.org_o4tg.link_ib43{transition:color .25s}.desc_pfHu{margin:0 auto}.desc_pfHu :deep(a){font-weight:500;text-decoration-style:dotted;transition:color .25s}.links_A3uT{height:56px}.sp-link_GRPb{align-items:center;background-color:var(--ifm-f-white);font-size:14px;font-weight:500;padding:16px;text-align:center;transition:color .25s,background-color .25s}.buttonGroup_ZDer button,.codeBlockContainer_sxZ3{background:var(--prism-background-color);color:var(--prism-color)}.sp-icon_KrGn{height:16px;margin-right:8px;width:16px;fill:currentColor}.codeBlockContainer_sxZ3{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_PcXS{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_nb7L{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_ebfI{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_nb7L+.codeBlockContent_PcXS .codeBlock_ebfI{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_EHvg{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_eKzc{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup_ZDer{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup_ZDer button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup_ZDer button:focus-visible,.buttonGroup_ZDer button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup_ZDer button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_XYFh{counter-increment:a;display:table-row}.codeLineNumber_tjKH{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_tjKH:before{content:counter(a);opacity:.4}.codeLineContent_lN4y{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_hJ2C{opacity:1!important}.copyButtonIcons_Ct8L{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_GZTQ,.copyButtonSuccessIcon_T5sy{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_T5sy{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_hJ2C .copyButtonIcon_GZTQ{opacity:0;transform:scale(.33)}.copyButtonCopied_hJ2C .copyButtonSuccessIcon_T5sy{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Ci1R{height:1.2rem;width:1.2rem}.tag_JExC{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_JExC:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_MOku{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_FS3W{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_FS3W:after,.tagWithCount_FS3W:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_FS3W:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_FS3W:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_FS3W span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_CtbC{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit__IaR{margin-right:.3em;vertical-align:sub}.details_rMme{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_rMme>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_rMme>summary::-webkit-details-marker{display:none}.details_rMme>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_ytpx{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.lastUpdated_OWKO{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_Sv08{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_Sv08:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_dtI0:after,.tocCollapsibleExpanded_Sf07{transform:none}.tocCollapsible_zMfc{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_UQzg>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_UQzg ul li{margin:.4rem .8rem}.details_KMmw{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_bW6b{list-style:none}.img_JMIO{height:auto}.tableOfContents_b1mW{overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.admonition_o2ui{margin-bottom:1em}.admonitionHeading_N477{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);text-transform:uppercase}.admonitionHeading_N477:not(:last-child){margin-bottom:.3rem}.admonitionIcon_F2Ur{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_F2Ur svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.breadcrumbHomeIcon_Jne1{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_mp_f{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:375px){.teamMembers_mZTa .container_hhjZ{grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}}@media (min-width:640px){.container{max-width:640px}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:block{display:block}.sm\:w-40{width:10rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-6{padding-bottom:1.5rem;padding-top:1.5rem}.sm\:pr-4{padding-right:1rem}.sm\:pt-12{padding-top:3rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}.sm\:text-base{font-size:1rem;line-height:1.5rem}.dialog-container[data-v-3926b6c7]{padding:1.5rem}.chat-input[data-v-3926b6c7]{font-size:.875rem;line-height:1.25rem}.result-not-found[data-v-3926b6c7]{padding-left:3.5rem;padding-right:3.5rem}.kbd[data-v-3926b6c7]{margin-left:.5rem;margin-right:.5rem}}@media (min-width:768px){.container{max-width:768px}.md\:order-1{order:1}.md\:order-2{order:2}.md\:col-span-1{grid-column:span 1/span 1}.md\:mt-0{margin-top:0}.button-placeholder[data-v-3926b6c7],.md\:block{display:block}.md\:w-auto{width:auto}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:gap-x-12{column-gap:3rem}.dialog-container[data-v-3926b6c7]{padding:5rem}.documate-button[data-v-956ba6e9]{background:var(--dm-color-bg-alt);border:1px solid #0000;border-radius:.5rem;color:var(--dm-color-hint);font-size:var(--dm-button-font-size);margin-left:2rem}.documate-button .icon[data-v-956ba6e9]{height:var(--dm-button-font-size);margin-right:.2rem}.documate-button[data-v-956ba6e9]:hover{border-color:var(--dm-color-brand)}}@media (min-width:997px){.collapseSidebarButton_igfI,.expandButton_vGLF{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_iOKh,.announcementBarPlaceholder_ZgHP{flex-basis:50px}.collapseSidebarButton_igfI{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_pubN{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_QmVd,[dir=rtl] .collapseSidebarButtonIcon_pubN{transform:rotate(0)}.collapseSidebarButton_igfI:focus,.collapseSidebarButton_igfI:hover,.expandButton_vGLF:focus,.expandButton_vGLF:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_b_C4{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SxoK{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SxoK{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_gAO5{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_Ivoc{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_WgKC{padding-top:0}.sidebarHidden_pHNJ{opacity:0;visibility:hidden}.sidebarLogo_XkDA{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_XkDA img{height:2rem;margin-right:.5rem}.expandButton_vGLF{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_QmVd{transform:rotate(180deg)}.docSidebarContainer_wnoZ{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_t3U5{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Epar{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_HtRu{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_qW8z{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_snhy{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.navbarSearchContainer_ws2C{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_OWKO{text-align:right}.tocMobile_KbWK{display:none}.docItemCol_qVdH{max-width:75%!important}}@media (min-width:1024px){.container{max-width:1024px}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:row-start-2{grid-row-start:2}.lg\:h-auto{height:auto}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:justify-end{justify-content:flex-end}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-8{padding-bottom:2rem;padding-top:2rem}.lg\:pt-20{padding-top:5rem}.lg\:text-6xl{font-size:3.75rem;line-height:1}.lg\:text-base{font-size:1rem;line-height:1.5rem}.lg\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (min-width:1536px){.container{max-width:1536px}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_QPtE,.footer__link-separator,.navbar__item,.sidebar_Ap_S,.tableOfContents_b1mW{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_ws2C{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_Ji2I{padding:0 .3rem}}@media only screen and (max-width:996px){.searchQueryColumn_D6kq,.searchResultsColumn_cM4p{max-width:60%!important}.searchLogoColumn_f4et,.searchVersionColumn_hUs4{max-width:40%!important}.searchLogoColumn_f4et{padding-left:0!important}}@media screen and (max-width:996px){.heroBanner_qdFl{padding:2rem}}@media (max-width:768px){div[class^=announcementBar_]{height:calc(var(--ifm-announcementBar-height) + 12px)}.navbar__items .documate-button,.navbar__link{display:none!important}.dialog-panel[data-v-3926b6c7]{margin-top:2rem}.powered-by[data-v-3926b6c7]{margin-top:.2rem}.progress-bar-container_Btve,.progress-bar-inner-container_RjNy{height:30px}.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_BZZK{font-size:2rem}}@media screen and (max-width:576px){.searchQueryColumn_D6kq{max-width:100%!important}.searchVersionColumn_hUs4{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@media (max-width:454px){.footer[data-v-3926b6c7]{justify-content:center}}@media (hover:hover){.backToTopButton_jRRJ:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-color-scheme:dark){.dark\:border-white\/5{border-color:#ffffff0d}.dark\:bg-\[rgb\(2\2c 2\2c 2\)\]{--tw-bg-opacity:1;background-color:rgb(2 2 2/var(--tw-bg-opacity))}.dark\:bg-black\/40{background-color:#0006}.dark\:bg-neutral-900{--tw-bg-opacity:1;background-color:rgb(23 23 23/var(--tw-bg-opacity))}.dark\:bg-transparent{background-color:initial}.dark\:via-white\/80{--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),#fffc var(--tw-gradient-via-position),var(--tw-gradient-to)}.dark\:text-neutral-400\/50{color:#a3a3a380}.dark\:after\:bg-transparent:after,.dark\:before\:bg-transparent:before{background-color:initial;content:var(--tw-content)}.dark\:hover\:bg-neutral-800:hover{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity))}.hover\:dark\:text-neutral-400:hover{--tw-text-opacity:1;color:rgb(163 163 163/var(--tw-text-opacity))}:root{--dm-color-brand:#a8b1ff;--dm-color-bg-alt:#161618;--dm-color-hint:#ebebf599;--dm-text-color:#e5e7e8;--dm-modal-bg-color:#202127;--dm-mask-bg-color:#656c85cc;--dm-divider-color:#2e2e32;--dm-highlight-color:var(--dm-color-brand)}.hljs{background:#0d1117;color:#c9d1d9}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{background-color:#033a16;color:#aff5b4}.hljs-deletion{background-color:#67060c;color:#ffdcd7}}@media (prefers-color-scheme:light){.hljs{background:#fff;color:#24292e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{background-color:#f0fff4;color:#22863a}.hljs-deletion{background-color:#ffeef0;color:#b31d28}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_NAgQ,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_KbWK{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_EHvg{white-space:pre-wrap}} \ No newline at end of file diff --git a/zh/assets/js/004cbcd1.d177fd4a.js b/zh/assets/js/004cbcd1.d177fd4a.js deleted file mode 100644 index a7e4e523b..000000000 --- a/zh/assets/js/004cbcd1.d177fd4a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[1528],{9302:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>a,frontMatter:()=>r,metadata:()=>l,toc:()=>t});var i=s(6070),c=s(5710);const r={},d="\u5c40\u90e8\u6253\u5305",l={id:"advanced/partial-bundling",title:"\u5c40\u90e8\u6253\u5305",description:"\u5c40\u90e8\u6253\u5305\uff08Partial Bundling\uff09\u662f Farm \u7528\u6765\u6253\u5305\u6a21\u5757\u7684\u7b56\u7565\uff0c\u7c7b\u4f3c\u4e8e\u5176\u4ed6\u6253\u5305\u5de5\u5177\uff0c\u4f46 Farm \u7684 \u5c40\u90e8\u6253\u5305 \u76ee\u6807\u4e0d\u540c\u3002",source:"@site/i18n/zh/docusaurus-plugin-content-docs/current/advanced/partial-bundling.md",sourceDirName:"advanced",slug:"/advanced/partial-bundling",permalink:"/zh/docs/advanced/partial-bundling",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/advanced/partial-bundling.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"\u670d\u52a1\u7aef\u6e32\u67d3 (SSR)",permalink:"/zh/docs/advanced/ssr"},next:{title:"Tree Shake",permalink:"/zh/docs/advanced/tree-shake"}},o={},t=[{value:"\u52a8\u673a",id:"\u52a8\u673a",level:2},{value:"\u5c40\u90e8\u6253\u5305\u89c4\u5219",id:"\u5c40\u90e8\u6253\u5305\u89c4\u5219",level:2},{value:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305",id:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305",level:2},{value:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5",id:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5",level:3},{value:"\u5c40\u90e8\u6253\u5305\u9009\u9879",id:"\u5c40\u90e8\u6253\u5305\u9009\u9879",level:3},{value:"\u6a21\u5757\u5206\u7ec4",id:"\u6a21\u5757\u5206\u7ec4",level:3},{value:"\u4f7f\u7528 enforceResources",id:"\u4f7f\u7528-enforceresources",level:3},{value:"\u914d\u7f6e immutable modules",id:"\u914d\u7f6e-immutable-modules",level:3},{value:"\u793a\u4f8b",id:"\u793a\u4f8b",level:2},{value:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4",id:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4",level:3},{value:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f",id:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f",level:3},{value:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77",id:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77",level:3}];function h(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,c.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"\u5c40\u90e8\u6253\u5305",children:"\u5c40\u90e8\u6253\u5305"}),"\n",(0,i.jsxs)(n.p,{children:["\u5c40\u90e8\u6253\u5305\uff08",(0,i.jsx)(n.code,{children:"Partial Bundling"}),"\uff09\u662f Farm \u7528\u6765\u6253\u5305\u6a21\u5757\u7684\u7b56\u7565\uff0c\u7c7b\u4f3c\u4e8e\u5176\u4ed6\u6253\u5305\u5de5\u5177\uff0c\u4f46 Farm \u7684 ",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"})," \u76ee\u6807\u4e0d\u540c\u3002"]}),"\n",(0,i.jsxs)(n.p,{children:["\u4e0e\u5176\u5b83\u6253\u5305\u5de5\u5177\u4e0d\u540c\uff0cFarm\u4e0d\u4f1a\u5c1d\u8bd5\u5c06\u6240\u6709\u5185\u5bb9\u6253\u5305\u5728\u4e00\u8d77\uff0c\u800c\u662f\u4f7f\u7528\u50cf ",(0,i.jsx)(n.code,{children:"splitChunks"})," \u4e4b\u7c7b\u7684\u4f18\u5316\u7b56\u7565\u5c06\u5176\u62c6\u5206\u51fa\u6765\uff0c\u76f8\u53cd\uff0cFarm\u4f1a\u5c06\u9879\u76ee\u76f4\u63a5\u6346\u6253\u5305\u6210\u591a\u4e2a\u8f93\u51fa\u6587\u4ef6\u3002\u4f8b\u5982\uff0c\u5982\u679c\u9700\u8981\u6570\u767e\u4e2a\u6a21\u5757\u6765\u542f\u52a8\u4e00\u4e2ahtml\u9875\u9762\uff0cFarm\u5c06\u5c1d\u8bd5\u5c06\u5b83\u4eec\u76f4\u63a5\u6253\u5305\u621020\u523030\u4e2a\u8f93\u51fa\u6587\u4ef6\u3002Farm\u5c06\u8fd9\u79cd\u884c\u4e3a\u79f0\u4e3a",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u3002"]}),"\n",(0,i.jsx)(n.p,{children:"Farm\u5c40\u90e8\u6253\u5305\u7684\u76ee\u6807\u662f:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u51cf\u5c11\u8bf7\u6c42\u6570\u91cf\u548c\u8bf7\u6c42\u5c42\u6b21"}),": \u5c06\u6570\u767e\u4e0a\u5343\u4e2a\u6a21\u5757\u8bf7\u6c42\u51cf\u5c11\u523020-30\u4e2a\u8bf7\u6c42\uff0c\u907f\u514d\u7531\u4e8e\u4f9d\u8d56\u5c42\u6b21\u7ed3\u6784\u800c\u9010\u4e2a\u52a0\u8f7d\u6a21\u5757\uff0c\u4ece\u800c\u52a0\u5feb\u8d44\u6e90\u7684\u52a0\u8f7d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u63d0\u9ad8\u7f13\u5b58\u547d\u4e2d\u7387"}),": \u5f53\u6a21\u5757\u53d1\u751f\u66f4\u6539\u65f6\uff0c\u786e\u4fdd\u53ea\u6709\u5c11\u6570\u8f93\u51fa\u6587\u4ef6\u53d7\u5230\u5f71\u54cd\uff0c\u56e0\u6b64\u53ef\u4ee5\u4e3a\u9879\u76ee\u63d0\u9ad8\u7f13\u5b58\u547d\u4e2d\u7387\u3002"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u5bf9\u4e8e\u4f20\u7edf\u6253\u5305\u5de5\u5177\uff0c\u6211\u4eec\u53ef\u80fd\u5f88\u96be\u901a\u8fc7\u590d\u6742\u7684 ",(0,i.jsx)(n.code,{children:"splitChunks"})," \u6216 ",(0,i.jsx)(n.code,{children:"manualChunks"})," \u914d\u7f6e\u6765\u5b9e\u73b0\u4e0a\u8ff0\u76ee\u6807\uff0c\u4f46\u662f Farm \u539f\u751f\u652f\u6301",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u3002"]}),"\n",(0,i.jsxs)(n.p,{children:["\u8bf7\u6ce8\u610f\uff0c\u9ed8\u8ba4\u7684\u6253\u5305\u7b56\u7565\u662f\u4e3a\u6d4f\u89c8\u5668\u8bbe\u8ba1\u7684\uff0c\u4f46\u5b83\u4e5f\u9002\u7528\u4e8e Node.js\u3002 \u5982\u679c\u60f3\u8981\u66f4\u6539 Node.js \u7684\u6253\u5305\u7b56\u7565\uff0c\u8bf7\u5c1d\u8bd5",(0,i.jsx)(n.a,{href:"#configuring-partial-bundling",children:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305"}),"\u3002"]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["\u8bf7\u53c2\u8003 ",(0,i.jsx)(n.a,{href:"https://github.com/farm-fe/rfcs/blob/main/rfcs/003-partial-bundling/rfc.md",children:"RFC-003 Partial Bundling"})," \u5c40\u90e8\u6253\u5305\u4ee5\u83b7\u53d6\u66f4\u591a\u6280\u672f\u7ec6\u8282\u3002"]})}),"\n",(0,i.jsx)(n.h2,{id:"\u52a8\u673a",children:"\u52a8\u673a"}),"\n",(0,i.jsx)(n.p,{children:"\u76ee\u524d\uff0cWeb\u6784\u5efa\u5de5\u5177\u5904\u7406\u6a21\u5757\u7684\u4e3b\u8981\u65b9\u6cd5\u6709\u4e24\u79cd\uff1a\u5b8c\u5168\u6253\u5305\u6216\u539f\u751fESM\u3002\u4f46\u5b83\u4eec\u90fd\u6709\u7f3a\u70b9\uff1a"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u5bf9\u4e8e\u5b8c\u5168\u6253\u5305\uff0c\u6253\u5305\u5de5\u5177\u65e8\u5728\u5c06\u6240\u6709\u5185\u5bb9\u6253\u5305\u5728\u4e00\u8d77\uff0c\u7136\u540e\u62c6\u5206\u51fa\u6765\u8fdb\u884c\u4f18\u5316\uff0c\u4f46\u62c6\u5206\u901a\u5e38\u96be\u4ee5\u914d\u7f6e\uff0c\u624b\u52a8\u5e73\u8861\u8d44\u6e90\u52a0\u8f7d\u6027\u80fd\u548c\u7f13\u5b58\u547d\u4e2d\u7387\u5f88\u96be\u3002"}),"\n",(0,i.jsx)(n.li,{children:"\u5bf9\u4e8e\u539f\u751fESM\uff0c\u6bcf\u4e2a\u6a21\u5757\u90fd\u53ef\u4ee5\u5355\u72ec\u7f16\u8bd1\u548c\u7f13\u5b58\uff0c\u4f46\u5f53\u6709\u6570\u767e\u4e2a\u6a21\u5757\u8bf7\u6c42\u65f6\uff0c\u4f1a\u4e25\u91cd\u5f71\u54cd\u52a0\u8f7d\u6027\u80fd\u3002"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u56e0\u6b64\uff0c\u6211\u4e00\u76f4\u5728\u601d\u8003\u662f\u5426\u6709\u4e00\u79cd\u7b56\u7565\u53ef\u4ee5\u907f\u514d\u8fd9\u4e24\u79cd\u6781\u7aef\u60c5\u51b5 - \u4e5f\u8bb8\u6211\u4eec\u53ef\u4ee5\u8fdb\u884c\u5c40\u90e8\u6253\u5305\uff1f\u6211\u4eec\u53ef\u4ee5\u76f4\u63a5\u5c06\u9879\u76ee\u6253\u5305\u6210\u51e0\u4e2a\u6709\u9650\u3001\u5927\u5c0f\u5e73\u8861\u7684\u8d44\u6e90\uff0c\u5e76\u4e14\u81ea\u52a8\u8fdb\u884c\u3002\u6211\u5c06\u8fd9\u79cd\u601d\u8003\u547d\u540d\u4e3a",(0,i.jsx)(n.code,{children:"\u6a21\u5757\u5408\u5e76"})," \uff08 ",(0,i.jsx)(n.code,{children:"Module Merging"})," \uff09- \u5728\u5168\u91cf\u6253\u5305\u548c\u975e\u6253\u5305\u4e4b\u95f4\u627e\u5230\u5e73\u8861\uff0c\u53ea\u6253\u5305\u51e0\u4e2a\u76f8\u5173\u7684\u6a21\u5757\u4ee5\u63d0\u9ad8\u52a0\u8f7d\u6027\u80fd\uff0c\u540c\u65f6\u4e0d\u5931\u53bb\u7f13\u5b58\u9897\u7c92\u5ea6\u3002"]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u540e\u6765\uff0c\u6211\u5c06",(0,i.jsx)(n.code,{children:"\u6a21\u5757\u5408\u5e76"}),"\u66f4\u540d\u4e3a",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\uff0c\u56e0\u4e3a\u6211\u8ba4\u4e3a",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u66f4\u80fd\u51c6\u786e\u5730\u8868\u8fbe\u6211\u7684\u60f3\u6cd5\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"\u5c40\u90e8\u6253\u5305\u89c4\u5219",children:"\u5c40\u90e8\u6253\u5305\u89c4\u5219"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u5728\u8fd9\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u901a\u8fc7\u793a\u4f8b\u4ecb\u7ecd",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u7684\u57fa\u672c\u89c4\u5219\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"\u9996\u5148\uff0c\u6211\u4eec\u6765\u770b\u4e00\u4e2a\u57fa\u672c\u7684React\u9879\u76ee\u793a\u4f8b\u3002\u5bf9\u4e8e\u4e00\u4e2a\u57fa\u672c\u7684React\u9879\u76ee\uff0c\u6211\u4eec\u53ea\u5728\u5165\u53e3\u6587\u4ef6\u4e2d\u5bfc\u5165react\u548creact-dom\uff1a"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",metastring:'title="index.tsx"',children:"import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport './index.scss';\n\nconst container = document.querySelector('#root');\nconst root = createRoot(container);\n\nroot.render(\n <>\n
    Index page
    \n \n);\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u6253\u5305\u7ed3\u679c\u5c06\u5982\u4e0b\u6240\u793a\uff1a"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-text",children:"./dist/\n\u251c\u2500\u2500 index_9c07.49b83356.js # contains react-dom\n\u251c\u2500\u2500 index_a35f.0ac21082.js # contains ./index.tsx\n\u251c\u2500\u2500 index_b7e0.7ab9ca2d.js # contains react and its dependencies\n\u251c\u2500\u2500 index_ce26.7f833381.css $ contains ./index.scss\n\u2514\u2500\u2500 index.html # contains ./index.html\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cFarm\u4f1a\u5c06\u4f60\u7684\u9879\u76ee\u6253\u5305\u62105\u4e2a\u6587\u4ef6\uff1a"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["2\u4e2ajs\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"node_modules"})," \uff0c\u5305\u542b ",(0,i.jsx)(n.code,{children:"react"})," \u3001 ",(0,i.jsx)(n.code,{children:"react-dom"})," \u5176\u4f9d\u8d56\u9879\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:["1\u4e2ajs\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"./index.tsx"})]}),"\n",(0,i.jsxs)(n.li,{children:["1\u4e2acss\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"./index.scss"}),";"]}),"\n",(0,i.jsxs)(n.li,{children:["1\u4e2ahtml\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"./index.html"}),";"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Farm\u4f7f\u7528\u4ee5\u4e0b\u89c4\u5219\u6765\u83b7\u5f97\u4e0a\u8ff0\u7ed3\u679c\uff1a"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u5e94\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d"}),": \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cFarm \u5c06 ",(0,i.jsx)(n.code,{children:"node_modules"})," \u4e0b\u7684\u6240\u6709\u6a21\u5757\u89c6\u4e3a\u4e0d\u53ef\u53d8\u7684\uff0c\u5426\u5219\u5b83\u4eec\u662f\u53ef\u53d8\u7684\u3002\u56e0\u6b64 ",(0,i.jsx)(n.code,{children:"./index.tsx"})," \u4f4d\u4e8e\u5355\u72ec\u7684\u6587\u4ef6\u4e2d\uff0c\u56e0\u4e3a\u5b83\u662f\u4e00\u4e2a\u53ef\u53d8\u6a21\u5757\uff0c\u56e0\u6b64\u5b83\u6c38\u8fdc\u4e0d\u4f1a\u4e0e ",(0,i.jsx)(n.code,{children:"react"})," \u548c ",(0,i.jsx)(n.code,{children:"react-dom"})," \u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u4e0d\u540c\u7c7b\u578b\u7684\u6a21\u5757\u5e94\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d"}),": \u56e0\u6b64 ",(0,i.jsx)(n.code,{children:"./index.scss"})," \u4f4d\u4e8e\u5355\u72ec\u7684\u6587\u4ef6\u4e2d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u540c\u4e00\u5305\u4e2d\u7684\u6a21\u5757\u5e94\u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d"}),": \u56e0\u6b64\uff0c\u6240\u6709 ",(0,i.jsx)(n.code,{children:"react"})," \u6a21\u5757\u59cb\u7ec8\u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\uff0c ",(0,i.jsx)(n.code,{children:"react-dom"})," \u4e5f\u662f\u5982\u6b64\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u8d44\u6e90\u52a0\u8f7d\u7684\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u5e94\u9ed8\u8ba4\u572820-30\u4e4b\u95f4"}),": \u56e0\u6b64\u67093\u4e2ajs\u8f93\u51fa\u6587\u4ef6\uff0c\u800c\u4e0d\u662f1\u4e2ajs\u8f93\u51fa\u6587\u4ef6\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u8f93\u51fa\u6587\u4ef6\u5e94\u5177\u6709\u76f8\u4f3c\u7684\u5927\u5c0f\uff0c\u6700\u5c0f\u8d44\u6e90\u5927\u5c0f\u5e94\u9ed8\u8ba4\u5927\u4e8e20KB"}),": \u56e0\u4e3a ",(0,i.jsx)(n.code,{children:"react-dom"})," \u662f\u6700\u5927\u7684\uff0c\u8d85\u8fc7100KB\uff0c\u6240\u4ee5\u5b83\u4f4d\u4e8e\u5355\u72ec\u7684\u6587\u4ef6\u4e2d\uff0c\u800c ",(0,i.jsx)(n.code,{children:"react"})," \u53ca\u5176\u4f9d\u8d56\u9879\u5c0f\u4e8e20KB\uff0c\u56e0\u6b64\u88ab\u5408\u5e76\u5230\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u719f\u6089\u4e86",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u7684\u57fa\u672c\u89c4\u5219\uff0c\u5982\u679c\u9047\u5230\u5c40\u90e8\u6253\u5305\u95ee\u9898\uff0c\u8bf7\u4f7f\u7528\u4e0a\u8ff0\u89c4\u5219\u8c03\u8bd5\u60a8\u7684\u9879\u76ee\u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u5982\u4f55\u914d\u7f6e\u5c40\u90e8\u6253\u5305\u3002"]}),"\n",(0,i.jsx)(n.h2,{id:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305",children:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305"}),"\n",(0,i.jsx)(n.h3,{id:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5",children:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5"}),"\n",(0,i.jsx)(n.p,{children:"\u6709\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u63a7\u5236\u6253\u5305\uff1a"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"groups"})}),": \u544a\u8bc9Farm\u60a8\u5e0c\u671b\u5c06\u8fd9\u4e9b\u6a21\u5757\u5c3d\u53ef\u80fd\u5730\u6253\u5305\u5728\u4e00\u8d77\uff0c\u4f46\u7531\u4e8eFarm\u7684\u4f18\u5316\u7b56\u7565\uff0c\u8fd9\u5e76\u4e0d\u662f\u5f3a\u5236\u6267\u884c\u7684\u3002\u8bf7\u53c2\u9605",(0,i.jsx)(n.a,{href:"#%E6%A8%A1%E5%9D%97%E5%88%86%E7%BB%84",children:"\u6a21\u5757\u5206\u7ec4"}),"\u4ee5\u4e86\u89e3\u6b64\u65b9\u6cd5\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceResources"})}),": \u544a\u8bc9Farm\u60a8\u5e0c\u671b\u8fd9\u4e9b\u6a21\u5757\u59cb\u7ec8\u6253\u5305\u5728\u4e00\u8d77\uff0c\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u4f18\u5316\u7b56\u7565\u7ea6\u675f\u3002\u8bf7\u53c2\u9605\u4f7f\u7528 ",(0,i.jsx)(n.a,{href:"#%E4%BD%BF%E7%94%A8-enforceresources",children:(0,i.jsx)(n.code,{children:"enforceResources"})})," \u4ee5\u4e86\u89e3\u6b64\u65b9\u6cd5\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"\u5c40\u90e8\u6253\u5305\u9009\u9879",children:"\u5c40\u90e8\u6253\u5305\u9009\u9879"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u652f\u6301\u8bb8\u591a\u9009\u9879\uff0c\u4f7f\u7528\u6237\u53ef\u4ee5\u81ea\u5b9a\u4e49\u5176\u884c\u4e3a\u3002\u6240\u6709\u9009\u9879\u5982\u4e0b\uff1a"]}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"targetConcurrentRequests"})}),": Farm\u5c1d\u8bd5\u4e3a\u521d\u59cb\u8d44\u6e90\u52a0\u8f7d\u6216\u52a8\u6001\u8d44\u6e90\u52a0\u8f7d\u751f\u6210\u5c3d\u53ef\u80fd\u63a5\u8fd1\u6b64\u914d\u7f6e\u503c\u7684\u8d44\u6e90\u6570\u91cf\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"targetMinSize"})}),": \u751f\u6210\u8d44\u6e90\u7684\u6700\u5c0f\u5927\u5c0f\uff0c\u5728\u538b\u7f29\u548cgzip\u4e4b\u524d\u3002\u8bf7\u6ce8\u610f\uff0c\u5982\u679c ",(0,i.jsx)(n.code,{children:"ModuleBucket\u7684\u5927\u5c0f"})," \u5c0f\u4e8e ",(0,i.jsx)(n.code,{children:"targetMinSize"}),"\uff0c ",(0,i.jsx)(n.code,{children:"ModuleBucket"})," \u5c06\u4f18\u5148\u8003\u8651\uff0c\u8fd9\u65f6\u5019\u5927\u5c0f\u9650\u5236\u4e0d\u4e00\u5b9a\u4f1a\u88ab\u5f3a\u5236\u4fdd\u8bc1\u3002\u53ef\u4ee5\u4f7f\u7528\u914d\u7f6e ",(0,i.jsx)(n.code,{children:"enforceTargetMinSize"})," \u6765\u5f3a\u5236\u4fdd\u8bc1\u5927\u5c0f\uff0c\u4f46\u662f\u8fd9\u6837\u53ef\u80fd\u4f1a\u5bfc\u81f4\u4e00\u4e9b\u5171\u4eab\u6a21\u5757\u7684\u4f18\u5316\u7b56\u7565\u5931\u6548\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"targetMaxSize"})}),": \u7c7b\u4f3c ",(0,i.jsx)(n.code,{children:"targetMinSize"}),"\uff0c\u751f\u6210\u8d44\u6e90\u7684\u6700\u5927\u5927\u5c0f\uff0c\u5728\u538b\u7f29\u548cgzip\u4e4b\u524d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"groups"})}),": \u4e00\u7ec4\u5e94\u8be5\u653e\u5728\u4e00\u8d77\u7684\u6a21\u5757\u3002\u8bf7\u6ce8\u610f\uff0c\u6b64\u7ec4\u914d\u7f6e\u53ea\u662f\u544a\u8bc9\u7f16\u8bd1\u5668\u8fd9\u4e9b\u6a21\u5757\u5e94\u8be5\u653e\u5728\u4e00\u8d77\uff0c\u5b83\u53ef\u80fd\u4f1a\u4ea7\u751f\u591a\u4e2a\u8d44\u6e90\uff0c\u5982\u679c\u60a8\u60f3\u5f3a\u5236\u5c06\u6a21\u5757\u653e\u5728\u540c\u4e00\u8d44\u6e90\u4e2d\uff0c\u5e94\u8be5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"}),"\u3002","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"name"}),": \u8fd9\u7ec4\u8d44\u6e90\u7684\u540d\u79f0."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"test"}),": \u5339\u914d\u5c5e\u4e8e\u8be5\u7ec4\u7684\u6a21\u5757\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u6570\u7ec4\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"groupType"}),": ",(0,i.jsx)(n.code,{children:"mutable"})," \u6216 ",(0,i.jsx)(n.code,{children:"immutable"})," \uff0c\u6b64\u7ec4\u4ec5\u7528\u4e8e\u6307\u5b9a\u6a21\u5757\u7684\u7c7b\u578b\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"resourceType"}),": ",(0,i.jsx)(n.code,{children:"all"}),"\u3001 ",(0,i.jsx)(n.code,{children:"initial"})," \u6216 ",(0,i.jsx)(n.code,{children:"async"}),"\uff0c\u6b64\u7ec4\u4ec5\u7528\u4e8e\u6307\u5b9a\u8d44\u6e90\u7684\u7c7b\u578b\u3002"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceResources"})}),": \u5339\u914d\u5e94\u8be5\u59cb\u7ec8\u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u8d44\u6e90\u4e2d\u7684\u6a21\u5757\u7684\u6570\u7ec4\uff0c\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u7ea6\u675f\u3002","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"name"}),": \u8d44\u6e90\u7684\u540d\u79f0."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"test"}),": \u5339\u914d\u5c5e\u4e8e\u8be5\u8d44\u6e90\u7684\u6a21\u5757\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u6570\u7ec4\u3002"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceTargetConcurrentRequests"})}),": \u5f3a\u5236\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u5bf9\u4e8e\u6bcf\u4e2a\u8d44\u6e90\u52a0\u8f7d\uff0c\u5f53\u4e3atrue\u65f6\uff0c\u8f83\u5c0f\u7684\u8d44\u6e90\u5c06\u88ab\u5408\u5e76\u5230\u8f83\u5927\u7684\u8d44\u6e90\u4e2d\u4ee5\u6ee1\u8db3\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4css\u8d44\u6e90\u51fa\u73b0\u95ee\u9898\uff0c\u8bf7\u8c28\u614e\u4f7f\u7528\u6b64\u9009\u9879\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceTargetMinSize"})}),": \u5f3a\u5236\u8bbe\u7f6e\u5bf9\u4e8e\u6bcf\u4e2a\u8d44\u6e90\u7684\u76ee\u6807\u6700\u5c0f\u5927\u5c0f\uff0c\u5f53\u4e3atrue\u65f6\uff0c\u8f83\u5c0f\u7684\u8d44\u6e90\u5c06\u88ab\u5408\u5e76\u5230\u8f83\u5927\u7684\u8d44\u6e90\u4e2d\u4ee5\u6ee1\u8db3\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4css\u8d44\u6e90\u51fa\u73b0\u95ee\u9898\uff0c\u8bf7\u8c28\u614e\u4f7f\u7528\u6b64\u9009\u9879\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"immutableModules"})}),": \u5339\u914d\u4e0d\u53ef\u53d8\u6a21\u5757\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u6570\u7ec4\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"immutableModulesWeight"})}),": \u9ed8\u8ba4\u4e3a0.8\uff0c\u4e0d\u53ef\u53d8\u6a21\u5757\u5c06\u5177\u670980%\u7684\u8bf7\u6c42\u6570\u91cf\u3002\u4f8b\u5982\uff0c\u5982\u679c ",(0,i.jsx)(n.code,{children:"targetConcurrentRequest"})," \u4e3a25\uff0c\u5219\u4e0d\u53ef\u53d8\u8d44\u6e90\u5c06\u9ed8\u8ba4\u4e3a ",(0,i.jsx)(n.code,{children:"25 * 80% = 20"})," \u3002\u6b64\u9009\u9879\u662f\u4e3a\u4e86\u786e\u4fdd\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u662f\u9694\u79bb\u7684\uff0c\u5982\u679c\u60a8\u66f4\u6539\u4e86\u4e1a\u52a1\u4ee3\u7801\uff0cnode_modules\u4e0b\u7684\u4ee3\u7801\u5c06\u4e0d\u4f1a\u53d7\u5230\u5f71\u54cd\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["\u901a\u5e38\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"targetConcurrentRequests"})," \u3001 ",(0,i.jsx)(n.code,{children:"targetMinSize"})," \u548c ",(0,i.jsx)(n.code,{children:"targetMaxSize"})," \u6765\u63a7\u5236\u5c40\u90e8\u6253\u5305\u7684\u9ed8\u8ba4\u884c\u4e3a\u3002Farm\u8bbe\u7f6e\u7684\u9ed8\u8ba4\u503c\u57fa\u4e8e\u6700\u4f73\u5b9e\u8df5\uff0c\u56e0\u6b64\u8bf7\u786e\u8ba4\u662f\u5426\u5fc5\u987b\u4fee\u6539\u9ed8\u8ba4\u503c\u3002"]})}),"\n",(0,i.jsx)(n.h3,{id:"\u6a21\u5757\u5206\u7ec4",children:"\u6a21\u5757\u5206\u7ec4"}),"\n",(0,i.jsxs)(n.p,{children:["\u60a8\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"groups"})," \u5c06\u6a21\u5757\u5206\u7ec4\u5728\u4e00\u8d77\u3002\u5bf9\u4e8e\u4e0a\u8ff0\u57fa\u672cReact\u9879\u76ee\u793a\u4f8b\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u914d\u7f6e\u5c06 ",(0,i.jsx)(n.code,{children:"node_modules"})," \u4e0b\u7684\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts" {4-9}',children:"export default defineConfig({\n compilation: {\n partialBundling: {\n groups: [\n {\n name: 'vendor-react',\n test: ['node_modules/'],\n }\n ]\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u6211\u4eec\u6dfb\u52a0\u4e86\u4e00\u4e2a ",(0,i.jsx)(n.code,{children:"group item"})," \uff0c\u5176\u4e2d\u5305\u542b ",(0,i.jsx)(n.code,{children:"name"})," \u548c ",(0,i.jsx)(n.code,{children:"test"})," \uff0c\u4ee5\u5c06 ",(0,i.jsx)(n.code,{children:"react"})," \u548c ",(0,i.jsx)(n.code,{children:"react-dom"})," \u5206\u7ec4\u5728\u4e00\u8d77\u3002\u6253\u5305\u7ed3\u679c\u5982\u4e0b\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"./dist/\n\u251c\u2500\u2500 index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules\n\u251c\u2500\u2500 index_a35f.0ac21082.js # contains `./index.tsx`\n\u251c\u2500\u2500 index_ce26.7f833381.css # contains `./index.scss`\n\u2514\u2500\u2500 index.html # contains `./index.html`\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u73b0\u5728\uff0c ",(0,i.jsx)(n.code,{children:"node_modules"})," \u4e0b\u7684\u6240\u6709\u6a21\u5757\u90fd\u6253\u5305\u5230 ",(0,i.jsx)(n.code,{children:"index_499e.72cf733c.js"})," \u4e2d\u3002\u8bf7\u6ce8\u610f\uff0cgroups\u5e76\u4e0d\u5f3a\u5236\u6240\u6709\u5339\u914d\u8be5\u7ec4\u7684\u6a21\u5757\u90fd\u6253\u5305\u5728\u4e00\u8d77\uff0c\u4e00\u4e2a ",(0,i.jsx)(n.code,{children:"group"}),"\u53ef\u4ee5\u4ea7\u751f\u591a\u4e2a ",(0,i.jsx)(n.code,{children:"output file"})," \uff0c\u56e0\u4e3a\uff1a"]}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002\u5f53\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u90fd\u5339\u914d\u5230\u8fd9\u4e2a ",(0,i.jsx)(n.code,{children:"group"})," \u65f6\uff0c\u5b83\u4eec\u5c06\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u4e2d\u3002"]}),"\n",(0,i.jsx)(n.li,{children:"\u5bf9\u4e8e\u591a\u9875\u9762\u5e94\u7528\u6216\u52a8\u6001\u5bfc\u5165\u7684\u5165\u53e3\uff0c\u53ef\u80fd\u5b58\u5728\u5171\u4eab\u6a21\u5757\uff0c\u8fd9\u4e9b\u6a21\u5757\u5e94\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u5982\u679c\u60a8\u9700\u8981\u5f3a\u5236\u5c06\u6a21\u5757\u653e\u5728\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})]}),"\n",(0,i.jsxs)(n.h3,{id:"\u4f7f\u7528-enforceresources",children:["\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})]}),"\n",(0,i.jsxs)(n.p,{children:["\u8981\u5c06\u6240\u6709\u6a21\u5757\u5206\u7ec4\u5728\u4e00\u8d77\u5e76\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u6761\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})," \uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n enforceResources: [\n {\n name: 'index',\n test: ['.+'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u6253\u5305\u7ed3\u679c:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"./dist/\n\u251c\u2500\u2500 index.7f833381.css # all css modules are bundled together\n\u251c\u2500\u2500 index.ba5550d9.js # all script modules are bundled together\n\u2514\u2500\u2500 index.html\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"enforceResources"})," \u5c06\u5ffd\u7565Farm\u7684\u6240\u6709\u5185\u90e8\u4f18\u5316\uff0c\u4f7f\u7528\u65f6\u8bf7\u5c0f\u5fc3\u3002"]})}),"\n",(0,i.jsxs)(n.h3,{id:"\u914d\u7f6e-immutable-modules",children:["\u914d\u7f6e ",(0,i.jsx)(n.code,{children:"immutable modules"})]}),"\n",(0,i.jsxs)(n.p,{children:["\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"immutableModules"})," \u914d\u7f6e\u4e0d\u53ef\u53d8\u6a21\u5757\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cFarm\u5c06\u5176\u8bbe\u7f6e\u4e3a ",(0,i.jsx)(n.code,{children:"node_modules/"})," \u3002"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default defineConfig({\n compilation: {\n partialBundling: {\n immutableModules: ['node_modules/', '/global-constants']\n },\n },\n});\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u4e0d\u53ef\u53d8\u6a21\u5757\u4f1a\u5f71\u54cd\u6253\u5305\u548c\u4f20\u5165\u7684\u6301\u4e45\u5316\u7f13\u5b58\uff0c\u5982\u679c\u60a8\u60f3\u4fee\u6539\u5b83\uff0c\u8bf7\u5c0f\u5fc3\u3002"}),"\n",(0,i.jsx)(n.h2,{id:"\u793a\u4f8b",children:"\u793a\u4f8b"}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsx)(n.p,{children:"\u901a\u5e38\u60a8\u4e0d\u9700\u8981\u624b\u52a8\u914d\u7f6e\u6253\u5305\uff0c\u5982\u679c\u60a8\u60f3\u624b\u52a8\u914d\u7f6e\u6253\u5305\uff0c\u8bf7\u786e\u4fdd\u60a8\u786e\u5b9e\u9700\u8981\u5b83\u3002\u8fd9\u4e9b\u793a\u4f8b\u4ec5\u7528\u4e8e\u5e2e\u52a9\u60a8\u8f7b\u677e\u5b66\u4e60\u5982\u4f55\u914d\u7f6e\u6253\u5305\u7b56\u7565\u3002"})}),"\n",(0,i.jsx)(n.h3,{id:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4",children:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4"}),"\n",(0,i.jsxs)(n.p,{children:["\u5c06 ",(0,i.jsx)(n.code,{children:"src/components"})," \u4e0b\u7684 ",(0,i.jsx)(n.code,{children:"modules"})," \u5206\u7ec4\uff0c\u5e76",(0,i.jsx)(n.strong,{children:"\u5c3d\u53ef\u80fd"}),"\u5c06\u5b83\u4eec\u8f93\u51fa\u5230\u540c\u4e00\u8d44\u6e90\u4e2d\u3002"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n groups: [\n {\n name: 'components',\n test: ['./src/components'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsx)(n.h3,{id:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f",children:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n targetConcurrentRequests: 15,\n targetMinSize: 200 * 1024 // 200 KB\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0cFarm\u5c06\u5c1d\u8bd5",(0,i.jsx)(n.strong,{children:"\u5c3d\u53ef\u80fd"}),"\u5730\u5c06\u60a8\u7684\u9879\u76ee\u6253\u5305\u5230 ",(0,i.jsx)(n.code,{children:"15"})," \u4e2a\u6587\u4ef6\u4e2d\uff0c\u6bcf\u4e2a\u6587\u4ef6\u7684\u6700\u5c0f\u5927\u5c0f",(0,i.jsx)(n.strong,{children:"\u5c3d\u53ef\u80fd"}),"\u5927\u4e8e ",(0,i.jsx)(n.code,{children:"200KB"})," \u3002"]}),"\n",(0,i.jsx)(n.h3,{id:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77",children:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n enforceResources: [\n {\n name: 'index',\n test: ['.+'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c\u6211\u4eec\u5f3a\u5236\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\uff0c\u5e76\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u7ea6\u675f\uff08\u4f8b\u5982\uff0c\u8bf7\u6c42\u6570\u91cf\u3001\u6587\u4ef6\u5927\u5c0f\uff09\u3002\u60a8\u4e5f\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})," \u5f3a\u5236\u5c06\u67d0\u4e9b\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n enforceResources: [\n {\n name: 'index',\n test: ['\\\\./src/components/.+'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u6211\u4eec\u5f3a\u5236\u5c06 ",(0,i.jsx)(n.code,{children:"src/components"})," \u76ee\u5f55\u4e0b\u7684\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\u3002"]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"enforceResources"})," \u4f1a\u7834\u574f\u6253\u5305\u7684\u5185\u90e8\u4f18\u5316\uff0c\u4f7f\u7528\u65f6\u8bf7\u5c0f\u5fc3\u3002"]})})]})}function a(e={}){const{wrapper:n}={...(0,c.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},5710:(e,n,s)=>{s.d(n,{R:()=>d,x:()=>l});var i=s(758);const c={},r=i.createContext(c);function d(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:d(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/zh/assets/js/004cbcd1.efb43db5.js b/zh/assets/js/004cbcd1.efb43db5.js new file mode 100644 index 000000000..363716e94 --- /dev/null +++ b/zh/assets/js/004cbcd1.efb43db5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[1528],{269:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>a,frontMatter:()=>r,metadata:()=>l,toc:()=>t});var i=s(6070),c=s(5710);const r={},d="\u5c40\u90e8\u6253\u5305",l={id:"advanced/partial-bundling",title:"\u5c40\u90e8\u6253\u5305",description:"\u5c40\u90e8\u6253\u5305\uff08Partial Bundling\uff09\u662f Farm \u7528\u6765\u6253\u5305\u6a21\u5757\u7684\u7b56\u7565\uff0c\u7c7b\u4f3c\u4e8e\u5176\u4ed6\u6253\u5305\u5de5\u5177\uff0c\u4f46 Farm \u7684 \u5c40\u90e8\u6253\u5305 \u76ee\u6807\u4e0d\u540c\u3002",source:"@site/i18n/zh/docusaurus-plugin-content-docs/current/advanced/partial-bundling.md",sourceDirName:"advanced",slug:"/advanced/partial-bundling",permalink:"/zh/docs/advanced/partial-bundling",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/advanced/partial-bundling.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"\u670d\u52a1\u7aef\u6e32\u67d3 (SSR)",permalink:"/zh/docs/advanced/ssr"},next:{title:"Tree Shake",permalink:"/zh/docs/advanced/tree-shake"}},o={},t=[{value:"\u52a8\u673a",id:"\u52a8\u673a",level:2},{value:"\u5c40\u90e8\u6253\u5305\u89c4\u5219",id:"\u5c40\u90e8\u6253\u5305\u89c4\u5219",level:2},{value:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305",id:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305",level:2},{value:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5",id:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5",level:3},{value:"\u5c40\u90e8\u6253\u5305\u9009\u9879",id:"\u5c40\u90e8\u6253\u5305\u9009\u9879",level:3},{value:"\u6a21\u5757\u5206\u7ec4",id:"\u6a21\u5757\u5206\u7ec4",level:3},{value:"\u4f7f\u7528 enforceResources",id:"\u4f7f\u7528-enforceresources",level:3},{value:"\u914d\u7f6e immutable modules",id:"\u914d\u7f6e-immutable-modules",level:3},{value:"\u793a\u4f8b",id:"\u793a\u4f8b",level:2},{value:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4",id:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4",level:3},{value:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f",id:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f",level:3},{value:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77",id:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77",level:3}];function h(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,c.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"\u5c40\u90e8\u6253\u5305",children:"\u5c40\u90e8\u6253\u5305"}),"\n",(0,i.jsxs)(n.p,{children:["\u5c40\u90e8\u6253\u5305\uff08",(0,i.jsx)(n.code,{children:"Partial Bundling"}),"\uff09\u662f Farm \u7528\u6765\u6253\u5305\u6a21\u5757\u7684\u7b56\u7565\uff0c\u7c7b\u4f3c\u4e8e\u5176\u4ed6\u6253\u5305\u5de5\u5177\uff0c\u4f46 Farm \u7684 ",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"})," \u76ee\u6807\u4e0d\u540c\u3002"]}),"\n",(0,i.jsxs)(n.p,{children:["\u4e0e\u5176\u5b83\u6253\u5305\u5de5\u5177\u4e0d\u540c\uff0cFarm\u4e0d\u4f1a\u5c1d\u8bd5\u5c06\u6240\u6709\u5185\u5bb9\u6253\u5305\u5728\u4e00\u8d77\uff0c\u800c\u662f\u4f7f\u7528\u50cf ",(0,i.jsx)(n.code,{children:"splitChunks"})," \u4e4b\u7c7b\u7684\u4f18\u5316\u7b56\u7565\u5c06\u5176\u62c6\u5206\u51fa\u6765\uff0c\u76f8\u53cd\uff0cFarm\u4f1a\u5c06\u9879\u76ee\u76f4\u63a5\u6346\u6253\u5305\u6210\u591a\u4e2a\u8f93\u51fa\u6587\u4ef6\u3002\u4f8b\u5982\uff0c\u5982\u679c\u9700\u8981\u6570\u767e\u4e2a\u6a21\u5757\u6765\u542f\u52a8\u4e00\u4e2ahtml\u9875\u9762\uff0cFarm\u5c06\u5c1d\u8bd5\u5c06\u5b83\u4eec\u76f4\u63a5\u6253\u5305\u621020\u523030\u4e2a\u8f93\u51fa\u6587\u4ef6\u3002Farm\u5c06\u8fd9\u79cd\u884c\u4e3a\u79f0\u4e3a",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u3002"]}),"\n",(0,i.jsx)(n.p,{children:"Farm\u5c40\u90e8\u6253\u5305\u7684\u76ee\u6807\u662f:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u51cf\u5c11\u8bf7\u6c42\u6570\u91cf\u548c\u8bf7\u6c42\u5c42\u6b21"}),": \u5c06\u6570\u767e\u4e0a\u5343\u4e2a\u6a21\u5757\u8bf7\u6c42\u51cf\u5c11\u523020-30\u4e2a\u8bf7\u6c42\uff0c\u907f\u514d\u7531\u4e8e\u4f9d\u8d56\u5c42\u6b21\u7ed3\u6784\u800c\u9010\u4e2a\u52a0\u8f7d\u6a21\u5757\uff0c\u4ece\u800c\u52a0\u5feb\u8d44\u6e90\u7684\u52a0\u8f7d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u63d0\u9ad8\u7f13\u5b58\u547d\u4e2d\u7387"}),": \u5f53\u6a21\u5757\u53d1\u751f\u66f4\u6539\u65f6\uff0c\u786e\u4fdd\u53ea\u6709\u5c11\u6570\u8f93\u51fa\u6587\u4ef6\u53d7\u5230\u5f71\u54cd\uff0c\u56e0\u6b64\u53ef\u4ee5\u4e3a\u9879\u76ee\u63d0\u9ad8\u7f13\u5b58\u547d\u4e2d\u7387\u3002"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u5bf9\u4e8e\u4f20\u7edf\u6253\u5305\u5de5\u5177\uff0c\u6211\u4eec\u53ef\u80fd\u5f88\u96be\u901a\u8fc7\u590d\u6742\u7684 ",(0,i.jsx)(n.code,{children:"splitChunks"})," \u6216 ",(0,i.jsx)(n.code,{children:"manualChunks"})," \u914d\u7f6e\u6765\u5b9e\u73b0\u4e0a\u8ff0\u76ee\u6807\uff0c\u4f46\u662f Farm \u539f\u751f\u652f\u6301",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u3002"]}),"\n",(0,i.jsxs)(n.p,{children:["\u8bf7\u6ce8\u610f\uff0c\u9ed8\u8ba4\u7684\u6253\u5305\u7b56\u7565\u662f\u4e3a\u6d4f\u89c8\u5668\u8bbe\u8ba1\u7684\uff0c\u4f46\u5b83\u4e5f\u9002\u7528\u4e8e Node.js\u3002 \u5982\u679c\u60f3\u8981\u66f4\u6539 Node.js \u7684\u6253\u5305\u7b56\u7565\uff0c\u8bf7\u5c1d\u8bd5",(0,i.jsx)(n.a,{href:"#configuring-partial-bundling",children:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305"}),"\u3002"]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["\u8bf7\u53c2\u8003 ",(0,i.jsx)(n.a,{href:"https://github.com/farm-fe/rfcs/blob/main/rfcs/003-partial-bundling/rfc.md",children:"RFC-003 Partial Bundling"})," \u5c40\u90e8\u6253\u5305\u4ee5\u83b7\u53d6\u66f4\u591a\u6280\u672f\u7ec6\u8282\u3002"]})}),"\n",(0,i.jsx)(n.h2,{id:"\u52a8\u673a",children:"\u52a8\u673a"}),"\n",(0,i.jsx)(n.p,{children:"\u76ee\u524d\uff0cWeb\u6784\u5efa\u5de5\u5177\u5904\u7406\u6a21\u5757\u7684\u4e3b\u8981\u65b9\u6cd5\u6709\u4e24\u79cd\uff1a\u5b8c\u5168\u6253\u5305\u6216\u539f\u751fESM\u3002\u4f46\u5b83\u4eec\u90fd\u6709\u7f3a\u70b9\uff1a"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"\u5bf9\u4e8e\u5b8c\u5168\u6253\u5305\uff0c\u6253\u5305\u5de5\u5177\u65e8\u5728\u5c06\u6240\u6709\u5185\u5bb9\u6253\u5305\u5728\u4e00\u8d77\uff0c\u7136\u540e\u62c6\u5206\u51fa\u6765\u8fdb\u884c\u4f18\u5316\uff0c\u4f46\u62c6\u5206\u901a\u5e38\u96be\u4ee5\u914d\u7f6e\uff0c\u624b\u52a8\u5e73\u8861\u8d44\u6e90\u52a0\u8f7d\u6027\u80fd\u548c\u7f13\u5b58\u547d\u4e2d\u7387\u5f88\u96be\u3002"}),"\n",(0,i.jsx)(n.li,{children:"\u5bf9\u4e8e\u539f\u751fESM\uff0c\u6bcf\u4e2a\u6a21\u5757\u90fd\u53ef\u4ee5\u5355\u72ec\u7f16\u8bd1\u548c\u7f13\u5b58\uff0c\u4f46\u5f53\u6709\u6570\u767e\u4e2a\u6a21\u5757\u8bf7\u6c42\u65f6\uff0c\u4f1a\u4e25\u91cd\u5f71\u54cd\u52a0\u8f7d\u6027\u80fd\u3002"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u56e0\u6b64\uff0c\u6211\u4e00\u76f4\u5728\u601d\u8003\u662f\u5426\u6709\u4e00\u79cd\u7b56\u7565\u53ef\u4ee5\u907f\u514d\u8fd9\u4e24\u79cd\u6781\u7aef\u60c5\u51b5 - \u4e5f\u8bb8\u6211\u4eec\u53ef\u4ee5\u8fdb\u884c\u5c40\u90e8\u6253\u5305\uff1f\u6211\u4eec\u53ef\u4ee5\u76f4\u63a5\u5c06\u9879\u76ee\u6253\u5305\u6210\u51e0\u4e2a\u6709\u9650\u3001\u5927\u5c0f\u5e73\u8861\u7684\u8d44\u6e90\uff0c\u5e76\u4e14\u81ea\u52a8\u8fdb\u884c\u3002\u6211\u5c06\u8fd9\u79cd\u601d\u8003\u547d\u540d\u4e3a",(0,i.jsx)(n.code,{children:"\u6a21\u5757\u5408\u5e76"})," \uff08 ",(0,i.jsx)(n.code,{children:"Module Merging"})," \uff09- \u5728\u5168\u91cf\u6253\u5305\u548c\u975e\u6253\u5305\u4e4b\u95f4\u627e\u5230\u5e73\u8861\uff0c\u53ea\u6253\u5305\u51e0\u4e2a\u76f8\u5173\u7684\u6a21\u5757\u4ee5\u63d0\u9ad8\u52a0\u8f7d\u6027\u80fd\uff0c\u540c\u65f6\u4e0d\u5931\u53bb\u7f13\u5b58\u9897\u7c92\u5ea6\u3002"]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u540e\u6765\uff0c\u6211\u5c06",(0,i.jsx)(n.code,{children:"\u6a21\u5757\u5408\u5e76"}),"\u66f4\u540d\u4e3a",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\uff0c\u56e0\u4e3a\u6211\u8ba4\u4e3a",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u66f4\u80fd\u51c6\u786e\u5730\u8868\u8fbe\u6211\u7684\u60f3\u6cd5\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"\u5c40\u90e8\u6253\u5305\u89c4\u5219",children:"\u5c40\u90e8\u6253\u5305\u89c4\u5219"}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["\u5728\u8fd9\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u901a\u8fc7\u793a\u4f8b\u4ecb\u7ecd",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u7684\u57fa\u672c\u89c4\u5219\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"\u9996\u5148\uff0c\u6211\u4eec\u6765\u770b\u4e00\u4e2a\u57fa\u672c\u7684React\u9879\u76ee\u793a\u4f8b\u3002\u5bf9\u4e8e\u4e00\u4e2a\u57fa\u672c\u7684React\u9879\u76ee\uff0c\u6211\u4eec\u53ea\u5728\u5165\u53e3\u6587\u4ef6\u4e2d\u5bfc\u5165react\u548creact-dom\uff1a"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",metastring:'title="index.tsx"',children:"import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport './index.scss';\n\nconst container = document.querySelector('#root');\nconst root = createRoot(container);\n\nroot.render(\n <>\n
    Index page
    \n \n);\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u6253\u5305\u7ed3\u679c\u5c06\u5982\u4e0b\u6240\u793a\uff1a"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-text",children:"./dist/\n\u251c\u2500\u2500 index_9c07.49b83356.js # contains react-dom\n\u251c\u2500\u2500 index_a35f.0ac21082.js # contains ./index.tsx\n\u251c\u2500\u2500 index_b7e0.7ab9ca2d.js # contains react and its dependencies\n\u251c\u2500\u2500 index_ce26.7f833381.css $ contains ./index.scss\n\u2514\u2500\u2500 index.html # contains ./index.html\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cFarm\u4f1a\u5c06\u4f60\u7684\u9879\u76ee\u6253\u5305\u62105\u4e2a\u6587\u4ef6\uff1a"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["2\u4e2ajs\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"node_modules"})," \uff0c\u5305\u542b ",(0,i.jsx)(n.code,{children:"react"})," \u3001 ",(0,i.jsx)(n.code,{children:"react-dom"})," \u5176\u4f9d\u8d56\u9879\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:["1\u4e2ajs\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"./index.tsx"})]}),"\n",(0,i.jsxs)(n.li,{children:["1\u4e2acss\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"./index.scss"}),";"]}),"\n",(0,i.jsxs)(n.li,{children:["1\u4e2ahtml\u6587\u4ef6\u6765\u81ea ",(0,i.jsx)(n.code,{children:"./index.html"}),";"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Farm\u4f7f\u7528\u4ee5\u4e0b\u89c4\u5219\u6765\u83b7\u5f97\u4e0a\u8ff0\u7ed3\u679c\uff1a"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u5e94\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d"}),": \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cFarm \u5c06 ",(0,i.jsx)(n.code,{children:"node_modules"})," \u4e0b\u7684\u6240\u6709\u6a21\u5757\u89c6\u4e3a\u4e0d\u53ef\u53d8\u7684\uff0c\u5426\u5219\u5b83\u4eec\u662f\u53ef\u53d8\u7684\u3002\u56e0\u6b64 ",(0,i.jsx)(n.code,{children:"./index.tsx"})," \u4f4d\u4e8e\u5355\u72ec\u7684\u6587\u4ef6\u4e2d\uff0c\u56e0\u4e3a\u5b83\u662f\u4e00\u4e2a\u53ef\u53d8\u6a21\u5757\uff0c\u56e0\u6b64\u5b83\u6c38\u8fdc\u4e0d\u4f1a\u4e0e ",(0,i.jsx)(n.code,{children:"react"})," \u548c ",(0,i.jsx)(n.code,{children:"react-dom"})," \u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u4e0d\u540c\u7c7b\u578b\u7684\u6a21\u5757\u5e94\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d"}),": \u56e0\u6b64 ",(0,i.jsx)(n.code,{children:"./index.scss"})," \u4f4d\u4e8e\u5355\u72ec\u7684\u6587\u4ef6\u4e2d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u540c\u4e00\u5305\u4e2d\u7684\u6a21\u5757\u5e94\u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d"}),": \u56e0\u6b64\uff0c\u6240\u6709 ",(0,i.jsx)(n.code,{children:"react"})," \u6a21\u5757\u59cb\u7ec8\u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\uff0c ",(0,i.jsx)(n.code,{children:"react-dom"})," \u4e5f\u662f\u5982\u6b64\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u8d44\u6e90\u52a0\u8f7d\u7684\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u5e94\u9ed8\u8ba4\u572820-30\u4e4b\u95f4"}),": \u56e0\u6b64\u67093\u4e2ajs\u8f93\u51fa\u6587\u4ef6\uff0c\u800c\u4e0d\u662f1\u4e2ajs\u8f93\u51fa\u6587\u4ef6\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"\u8f93\u51fa\u6587\u4ef6\u5e94\u5177\u6709\u76f8\u4f3c\u7684\u5927\u5c0f\uff0c\u6700\u5c0f\u8d44\u6e90\u5927\u5c0f\u5e94\u9ed8\u8ba4\u5927\u4e8e20KB"}),": \u56e0\u4e3a ",(0,i.jsx)(n.code,{children:"react-dom"})," \u662f\u6700\u5927\u7684\uff0c\u8d85\u8fc7100KB\uff0c\u6240\u4ee5\u5b83\u4f4d\u4e8e\u5355\u72ec\u7684\u6587\u4ef6\u4e2d\uff0c\u800c ",(0,i.jsx)(n.code,{children:"react"})," \u53ca\u5176\u4f9d\u8d56\u9879\u5c0f\u4e8e20KB\uff0c\u56e0\u6b64\u88ab\u5408\u5e76\u5230\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u719f\u6089\u4e86",(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u7684\u57fa\u672c\u89c4\u5219\uff0c\u5982\u679c\u9047\u5230\u5c40\u90e8\u6253\u5305\u95ee\u9898\uff0c\u8bf7\u4f7f\u7528\u4e0a\u8ff0\u89c4\u5219\u8c03\u8bd5\u60a8\u7684\u9879\u76ee\u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u5982\u4f55\u914d\u7f6e\u5c40\u90e8\u6253\u5305\u3002"]}),"\n",(0,i.jsx)(n.h2,{id:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305",children:"\u914d\u7f6e\u5c40\u90e8\u6253\u5305"}),"\n",(0,i.jsx)(n.h3,{id:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5",children:"\u4e24\u79cd\u914d\u7f6e\u65b9\u6cd5"}),"\n",(0,i.jsx)(n.p,{children:"\u6709\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u63a7\u5236\u6253\u5305\uff1a"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"groups"})}),": \u544a\u8bc9Farm\u60a8\u5e0c\u671b\u5c06\u8fd9\u4e9b\u6a21\u5757\u5c3d\u53ef\u80fd\u5730\u6253\u5305\u5728\u4e00\u8d77\uff0c\u4f46\u7531\u4e8eFarm\u7684\u4f18\u5316\u7b56\u7565\uff0c\u8fd9\u5e76\u4e0d\u662f\u5f3a\u5236\u6267\u884c\u7684\u3002\u8bf7\u53c2\u9605",(0,i.jsx)(n.a,{href:"#%E6%A8%A1%E5%9D%97%E5%88%86%E7%BB%84",children:"\u6a21\u5757\u5206\u7ec4"}),"\u4ee5\u4e86\u89e3\u6b64\u65b9\u6cd5\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceResources"})}),": \u544a\u8bc9Farm\u60a8\u5e0c\u671b\u8fd9\u4e9b\u6a21\u5757\u59cb\u7ec8\u6253\u5305\u5728\u4e00\u8d77\uff0c\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u4f18\u5316\u7b56\u7565\u7ea6\u675f\u3002\u8bf7\u53c2\u9605\u4f7f\u7528 ",(0,i.jsx)(n.a,{href:"#%E4%BD%BF%E7%94%A8-enforceresources",children:(0,i.jsx)(n.code,{children:"enforceResources"})})," \u4ee5\u4e86\u89e3\u6b64\u65b9\u6cd5\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"\u5c40\u90e8\u6253\u5305\u9009\u9879",children:"\u5c40\u90e8\u6253\u5305\u9009\u9879"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"\u5c40\u90e8\u6253\u5305"}),"\u652f\u6301\u8bb8\u591a\u9009\u9879\uff0c\u4f7f\u7528\u6237\u53ef\u4ee5\u81ea\u5b9a\u4e49\u5176\u884c\u4e3a\u3002\u6240\u6709\u9009\u9879\u5982\u4e0b\uff1a"]}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"targetConcurrentRequests"})}),": Farm\u5c1d\u8bd5\u4e3a\u521d\u59cb\u8d44\u6e90\u52a0\u8f7d\u6216\u52a8\u6001\u8d44\u6e90\u52a0\u8f7d\u751f\u6210\u5c3d\u53ef\u80fd\u63a5\u8fd1\u6b64\u914d\u7f6e\u503c\u7684\u8d44\u6e90\u6570\u91cf\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"targetMinSize"})}),": \u751f\u6210\u8d44\u6e90\u7684\u6700\u5c0f\u5927\u5c0f\uff0c\u5728\u538b\u7f29\u548cgzip\u4e4b\u524d\u3002\u8bf7\u6ce8\u610f\uff0c\u5982\u679c ",(0,i.jsx)(n.code,{children:"ModuleBucket\u7684\u5927\u5c0f"})," \u5c0f\u4e8e ",(0,i.jsx)(n.code,{children:"targetMinSize"}),"\uff0c ",(0,i.jsx)(n.code,{children:"ModuleBucket"})," \u5c06\u4f18\u5148\u8003\u8651\uff0c\u8fd9\u65f6\u5019\u5927\u5c0f\u9650\u5236\u4e0d\u4e00\u5b9a\u4f1a\u88ab\u5f3a\u5236\u4fdd\u8bc1\u3002\u53ef\u4ee5\u4f7f\u7528\u914d\u7f6e ",(0,i.jsx)(n.code,{children:"enforceTargetMinSize"})," \u6765\u5f3a\u5236\u4fdd\u8bc1\u5927\u5c0f\uff0c\u4f46\u662f\u8fd9\u6837\u53ef\u80fd\u4f1a\u5bfc\u81f4\u4e00\u4e9b\u5171\u4eab\u6a21\u5757\u7684\u4f18\u5316\u7b56\u7565\u5931\u6548\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"targetMaxSize"})}),": \u7c7b\u4f3c ",(0,i.jsx)(n.code,{children:"targetMinSize"}),"\uff0c\u751f\u6210\u8d44\u6e90\u7684\u6700\u5927\u5927\u5c0f\uff0c\u5728\u538b\u7f29\u548cgzip\u4e4b\u524d\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"groups"})}),": \u4e00\u7ec4\u5e94\u8be5\u653e\u5728\u4e00\u8d77\u7684\u6a21\u5757\u3002\u8bf7\u6ce8\u610f\uff0c\u6b64\u7ec4\u914d\u7f6e\u53ea\u662f\u544a\u8bc9\u7f16\u8bd1\u5668\u8fd9\u4e9b\u6a21\u5757\u5e94\u8be5\u653e\u5728\u4e00\u8d77\uff0c\u5b83\u53ef\u80fd\u4f1a\u4ea7\u751f\u591a\u4e2a\u8d44\u6e90\uff0c\u5982\u679c\u60a8\u60f3\u5f3a\u5236\u5c06\u6a21\u5757\u653e\u5728\u540c\u4e00\u8d44\u6e90\u4e2d\uff0c\u5e94\u8be5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"}),"\u3002","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"name"}),": \u8fd9\u7ec4\u8d44\u6e90\u7684\u540d\u79f0."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"test"}),": \u5339\u914d\u5c5e\u4e8e\u8be5\u7ec4\u7684\u6a21\u5757\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u6570\u7ec4\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"groupType"}),": ",(0,i.jsx)(n.code,{children:"mutable"})," \u6216 ",(0,i.jsx)(n.code,{children:"immutable"})," \uff0c\u6b64\u7ec4\u4ec5\u7528\u4e8e\u6307\u5b9a\u6a21\u5757\u7684\u7c7b\u578b\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"resourceType"}),": ",(0,i.jsx)(n.code,{children:"all"}),"\u3001 ",(0,i.jsx)(n.code,{children:"initial"})," \u6216 ",(0,i.jsx)(n.code,{children:"async"}),"\uff0c\u6b64\u7ec4\u4ec5\u7528\u4e8e\u6307\u5b9a\u8d44\u6e90\u7684\u7c7b\u578b\u3002"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceResources"})}),": \u5339\u914d\u5e94\u8be5\u59cb\u7ec8\u4f4d\u4e8e\u540c\u4e00\u8f93\u51fa\u8d44\u6e90\u4e2d\u7684\u6a21\u5757\u7684\u6570\u7ec4\uff0c\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u7ea6\u675f\u3002","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"name"}),": \u8d44\u6e90\u7684\u540d\u79f0."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"test"}),": \u5339\u914d\u5c5e\u4e8e\u8be5\u8d44\u6e90\u7684\u6a21\u5757\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u6570\u7ec4\u3002"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceTargetConcurrentRequests"})}),": \u5f3a\u5236\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u5bf9\u4e8e\u6bcf\u4e2a\u8d44\u6e90\u52a0\u8f7d\uff0c\u5f53\u4e3atrue\u65f6\uff0c\u8f83\u5c0f\u7684\u8d44\u6e90\u5c06\u88ab\u5408\u5e76\u5230\u8f83\u5927\u7684\u8d44\u6e90\u4e2d\u4ee5\u6ee1\u8db3\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4css\u8d44\u6e90\u51fa\u73b0\u95ee\u9898\uff0c\u8bf7\u8c28\u614e\u4f7f\u7528\u6b64\u9009\u9879\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"enforceTargetMinSize"})}),": \u5f3a\u5236\u8bbe\u7f6e\u5bf9\u4e8e\u6bcf\u4e2a\u8d44\u6e90\u7684\u76ee\u6807\u6700\u5c0f\u5927\u5c0f\uff0c\u5f53\u4e3atrue\u65f6\uff0c\u8f83\u5c0f\u7684\u8d44\u6e90\u5c06\u88ab\u5408\u5e76\u5230\u8f83\u5927\u7684\u8d44\u6e90\u4e2d\u4ee5\u6ee1\u8db3\u76ee\u6807\u5e76\u53d1\u8bf7\u6c42\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4css\u8d44\u6e90\u51fa\u73b0\u95ee\u9898\uff0c\u8bf7\u8c28\u614e\u4f7f\u7528\u6b64\u9009\u9879\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"immutableModules"})}),": \u5339\u914d\u4e0d\u53ef\u53d8\u6a21\u5757\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u6570\u7ec4\u3002"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"immutableModulesWeight"})}),": \u9ed8\u8ba4\u4e3a0.8\uff0c\u4e0d\u53ef\u53d8\u6a21\u5757\u5c06\u5177\u670980%\u7684\u8bf7\u6c42\u6570\u91cf\u3002\u4f8b\u5982\uff0c\u5982\u679c ",(0,i.jsx)(n.code,{children:"targetConcurrentRequest"})," \u4e3a25\uff0c\u5219\u4e0d\u53ef\u53d8\u8d44\u6e90\u5c06\u9ed8\u8ba4\u4e3a ",(0,i.jsx)(n.code,{children:"25 * 80% = 20"})," \u3002\u6b64\u9009\u9879\u662f\u4e3a\u4e86\u786e\u4fdd\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u662f\u9694\u79bb\u7684\uff0c\u5982\u679c\u60a8\u66f4\u6539\u4e86\u4e1a\u52a1\u4ee3\u7801\uff0cnode_modules\u4e0b\u7684\u4ee3\u7801\u5c06\u4e0d\u4f1a\u53d7\u5230\u5f71\u54cd\u3002"]}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["\u901a\u5e38\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"targetConcurrentRequests"})," \u3001 ",(0,i.jsx)(n.code,{children:"targetMinSize"})," \u548c ",(0,i.jsx)(n.code,{children:"targetMaxSize"})," \u6765\u63a7\u5236\u5c40\u90e8\u6253\u5305\u7684\u9ed8\u8ba4\u884c\u4e3a\u3002Farm\u8bbe\u7f6e\u7684\u9ed8\u8ba4\u503c\u57fa\u4e8e\u6700\u4f73\u5b9e\u8df5\uff0c\u56e0\u6b64\u8bf7\u786e\u8ba4\u662f\u5426\u5fc5\u987b\u4fee\u6539\u9ed8\u8ba4\u503c\u3002"]})}),"\n",(0,i.jsx)(n.h3,{id:"\u6a21\u5757\u5206\u7ec4",children:"\u6a21\u5757\u5206\u7ec4"}),"\n",(0,i.jsxs)(n.p,{children:["\u60a8\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"groups"})," \u5c06\u6a21\u5757\u5206\u7ec4\u5728\u4e00\u8d77\u3002\u5bf9\u4e8e\u4e0a\u8ff0\u57fa\u672cReact\u9879\u76ee\u793a\u4f8b\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u914d\u7f6e\u5c06 ",(0,i.jsx)(n.code,{children:"node_modules"})," \u4e0b\u7684\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts" {4-9}',children:"export default defineConfig({\n compilation: {\n partialBundling: {\n groups: [\n {\n name: 'vendor-react',\n test: ['node_modules/'],\n }\n ]\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u6211\u4eec\u6dfb\u52a0\u4e86\u4e00\u4e2a ",(0,i.jsx)(n.code,{children:"group item"})," \uff0c\u5176\u4e2d\u5305\u542b ",(0,i.jsx)(n.code,{children:"name"})," \u548c ",(0,i.jsx)(n.code,{children:"test"})," \uff0c\u4ee5\u5c06 ",(0,i.jsx)(n.code,{children:"react"})," \u548c ",(0,i.jsx)(n.code,{children:"react-dom"})," \u5206\u7ec4\u5728\u4e00\u8d77\u3002\u6253\u5305\u7ed3\u679c\u5982\u4e0b\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"./dist/\n\u251c\u2500\u2500 index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules\n\u251c\u2500\u2500 index_a35f.0ac21082.js # contains `./index.tsx`\n\u251c\u2500\u2500 index_ce26.7f833381.css # contains `./index.scss`\n\u2514\u2500\u2500 index.html # contains `./index.html`\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u73b0\u5728\uff0c ",(0,i.jsx)(n.code,{children:"node_modules"})," \u4e0b\u7684\u6240\u6709\u6a21\u5757\u90fd\u6253\u5305\u5230 ",(0,i.jsx)(n.code,{children:"index_499e.72cf733c.js"})," \u4e2d\u3002\u8bf7\u6ce8\u610f\uff0cgroups\u5e76\u4e0d\u5f3a\u5236\u6240\u6709\u5339\u914d\u8be5\u7ec4\u7684\u6a21\u5757\u90fd\u6253\u5305\u5728\u4e00\u8d77\uff0c\u4e00\u4e2a ",(0,i.jsx)(n.code,{children:"group"}),"\u53ef\u4ee5\u4ea7\u751f\u591a\u4e2a ",(0,i.jsx)(n.code,{children:"output file"})," \uff0c\u56e0\u4e3a\uff1a"]}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002\u5f53\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u6a21\u5757\u90fd\u5339\u914d\u5230\u8fd9\u4e2a ",(0,i.jsx)(n.code,{children:"group"})," \u65f6\uff0c\u5b83\u4eec\u5c06\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u4e2d\u3002"]}),"\n",(0,i.jsx)(n.li,{children:"\u5bf9\u4e8e\u591a\u9875\u9762\u5e94\u7528\u6216\u52a8\u6001\u5bfc\u5165\u7684\u5165\u53e3\uff0c\u53ef\u80fd\u5b58\u5728\u5171\u4eab\u6a21\u5757\uff0c\u8fd9\u4e9b\u6a21\u5757\u5e94\u59cb\u7ec8\u4f4d\u4e8e\u4e0d\u540c\u7684\u8f93\u51fa\u6587\u4ef6\u4e2d\u3002"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["\u5982\u679c\u60a8\u9700\u8981\u5f3a\u5236\u5c06\u6a21\u5757\u653e\u5728\u540c\u4e00\u8f93\u51fa\u6587\u4ef6\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})]}),"\n",(0,i.jsxs)(n.h3,{id:"\u4f7f\u7528-enforceresources",children:["\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})]}),"\n",(0,i.jsxs)(n.p,{children:["\u8981\u5c06\u6240\u6709\u6a21\u5757\u5206\u7ec4\u5728\u4e00\u8d77\u5e76\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u6761\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})," \uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n enforceResources: [\n {\n name: 'index',\n test: ['.+'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u6253\u5305\u7ed3\u679c:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"./dist/\n\u251c\u2500\u2500 index.7f833381.css # all css modules are bundled together\n\u251c\u2500\u2500 index.ba5550d9.js # all script modules are bundled together\n\u2514\u2500\u2500 index.html\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"enforceResources"})," \u5c06\u5ffd\u7565Farm\u7684\u6240\u6709\u5185\u90e8\u4f18\u5316\uff0c\u4f7f\u7528\u65f6\u8bf7\u5c0f\u5fc3\u3002"]})}),"\n",(0,i.jsxs)(n.h3,{id:"\u914d\u7f6e-immutable-modules",children:["\u914d\u7f6e ",(0,i.jsx)(n.code,{children:"immutable modules"})]}),"\n",(0,i.jsxs)(n.p,{children:["\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"immutableModules"})," \u914d\u7f6e\u4e0d\u53ef\u53d8\u6a21\u5757\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cFarm\u5c06\u5176\u8bbe\u7f6e\u4e3a ",(0,i.jsx)(n.code,{children:"node_modules/"})," \u3002"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default defineConfig({\n compilation: {\n partialBundling: {\n immutableModules: ['node_modules/', '/global-constants']\n },\n },\n});\n"})}),"\n",(0,i.jsx)(n.p,{children:"\u4e0d\u53ef\u53d8\u6a21\u5757\u4f1a\u5f71\u54cd\u6253\u5305\u548c\u4f20\u5165\u7684\u6301\u4e45\u5316\u7f13\u5b58\uff0c\u5982\u679c\u60a8\u60f3\u4fee\u6539\u5b83\uff0c\u8bf7\u5c0f\u5fc3\u3002"}),"\n",(0,i.jsx)(n.h2,{id:"\u793a\u4f8b",children:"\u793a\u4f8b"}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsx)(n.p,{children:"\u901a\u5e38\u60a8\u4e0d\u9700\u8981\u624b\u52a8\u914d\u7f6e\u6253\u5305\uff0c\u5982\u679c\u60a8\u60f3\u624b\u52a8\u914d\u7f6e\u6253\u5305\uff0c\u8bf7\u786e\u4fdd\u60a8\u786e\u5b9e\u9700\u8981\u5b83\u3002\u8fd9\u4e9b\u793a\u4f8b\u4ec5\u7528\u4e8e\u5e2e\u52a9\u60a8\u8f7b\u677e\u5b66\u4e60\u5982\u4f55\u914d\u7f6e\u6253\u5305\u7b56\u7565\u3002"})}),"\n",(0,i.jsx)(n.h3,{id:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4",children:"\u5c06\u540c\u4e00\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u5206\u7ec4"}),"\n",(0,i.jsxs)(n.p,{children:["\u5c06 ",(0,i.jsx)(n.code,{children:"src/components"})," \u4e0b\u7684 ",(0,i.jsx)(n.code,{children:"modules"})," \u5206\u7ec4\uff0c\u5e76",(0,i.jsx)(n.strong,{children:"\u5c3d\u53ef\u80fd"}),"\u5c06\u5b83\u4eec\u8f93\u51fa\u5230\u540c\u4e00\u8d44\u6e90\u4e2d\u3002"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n groups: [\n {\n name: 'components',\n test: ['./src/components'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsx)(n.h3,{id:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f",children:"\u914d\u7f6e\u6253\u5305\u7684\u6570\u91cf\u548c\u5927\u5c0f"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n targetConcurrentRequests: 15,\n targetMinSize: 200 * 1024 // 200 KB\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0cFarm\u5c06\u5c1d\u8bd5",(0,i.jsx)(n.strong,{children:"\u5c3d\u53ef\u80fd"}),"\u5730\u5c06\u60a8\u7684\u9879\u76ee\u6253\u5305\u5230 ",(0,i.jsx)(n.code,{children:"15"})," \u4e2a\u6587\u4ef6\u4e2d\uff0c\u6bcf\u4e2a\u6587\u4ef6\u7684\u6700\u5c0f\u5927\u5c0f",(0,i.jsx)(n.strong,{children:"\u5c3d\u53ef\u80fd"}),"\u5927\u4e8e ",(0,i.jsx)(n.code,{children:"200KB"})," \u3002"]}),"\n",(0,i.jsx)(n.h3,{id:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77",children:"\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n enforceResources: [\n {\n name: 'index',\n test: ['.+'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c\u6211\u4eec\u5f3a\u5236\u5c06\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\uff0c\u5e76\u5ffd\u7565\u6240\u6709\u5176\u4ed6\u7ea6\u675f\uff08\u4f8b\u5982\uff0c\u8bf7\u6c42\u6570\u91cf\u3001\u6587\u4ef6\u5927\u5c0f\uff09\u3002\u60a8\u4e5f\u53ef\u4ee5\u4f7f\u7528 ",(0,i.jsx)(n.code,{children:"enforceResources"})," \u5f3a\u5236\u5c06\u67d0\u4e9b\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\uff1a"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { defineConfig } from '@farmfe/core';\n\nexport default defineConfig({\n compilation: {\n partialBundling: {\n // c-highlight-start\n enforceResources: [\n {\n name: 'index',\n test: ['\\\\./src/components/.+'],\n }\n ]\n // c-highlight-end\n },\n },\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["\u6211\u4eec\u5f3a\u5236\u5c06 ",(0,i.jsx)(n.code,{children:"src/components"})," \u76ee\u5f55\u4e0b\u7684\u6240\u6709\u6a21\u5757\u6253\u5305\u5728\u4e00\u8d77\u3002"]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"enforceResources"})," \u4f1a\u7834\u574f\u6253\u5305\u7684\u5185\u90e8\u4f18\u5316\uff0c\u4f7f\u7528\u65f6\u8bf7\u5c0f\u5fc3\u3002"]})})]})}function a(e={}){const{wrapper:n}={...(0,c.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},5710:(e,n,s)=>{s.d(n,{R:()=>d,x:()=>l});var i=s(758);const c={},r=i.createContext(c);function d(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:d(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/zh/assets/js/00d8e6cc.9e07615a.js b/zh/assets/js/00d8e6cc.a05a9905.js similarity index 98% rename from zh/assets/js/00d8e6cc.9e07615a.js rename to zh/assets/js/00d8e6cc.a05a9905.js index a0b437fa2..857b8fda7 100644 --- a/zh/assets/js/00d8e6cc.9e07615a.js +++ b/zh/assets/js/00d8e6cc.a05a9905.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[1116],{1965:(n,e,i)=>{i.r(e),i.d(e,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>c,metadata:()=>a,toc:()=>d});var t=i(6070),o=i(5710);const c={},r="\u4ea7\u7269\u538b\u7f29",a={id:"advanced/minification",title:"\u4ea7\u7269\u538b\u7f29",description:"Farm \u652f\u6301\u5f00\u7bb1\u5373\u7528\u7684\u751f\u4ea7\u538b\u7f29\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u5728\u751f\u4ea7\u4e2d\u81ea\u52a8\u542f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7compilation.minify \u9009\u9879\u542f\u7528\u6216\u7981\u7528\u3002",source:"@site/i18n/zh/docusaurus-plugin-content-docs/current/advanced/minification.md",sourceDirName:"advanced",slug:"/advanced/minification",permalink:"/zh/docs/advanced/minification",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/advanced/minification.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Tree Shake",permalink:"/zh/docs/advanced/tree-shake"},next:{title:"\u8bed\u6cd5\u964d\u7ea7\u548c Polyfill",permalink:"/zh/docs/advanced/polyfill"}},s={},d=[];function l(n){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...n.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h1,{id:"\u4ea7\u7269\u538b\u7f29",children:"\u4ea7\u7269\u538b\u7f29"}),"\n",(0,t.jsxs)(e.p,{children:["Farm \u652f\u6301\u5f00\u7bb1\u5373\u7528\u7684\u751f\u4ea7\u538b\u7f29\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u5728\u751f\u4ea7\u4e2d\u81ea\u52a8\u542f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7",(0,t.jsx)(e.a,{href:"/zh/docs/config/compilation-options#minify",children:"compilation.minify"})," \u9009\u9879\u542f\u7528\u6216\u7981\u7528\u3002"]}),"\n",(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default {\n compilation: {\n // enable minification for both development and production\n minify: true,\n },\n};\n"})}),"\n",(0,t.jsx)(e.p,{children:"\u5982\u679c\u542f\u7528\u538b\u7f29:"}),"\n",(0,t.jsxs)(e.ul,{children:["\n",(0,t.jsxs)(e.li,{children:["\u5bf9\u4e8e js/ts \u6a21\u5757\uff0c\u4ee3\u7801\u5c06\u88ab",(0,t.jsx)(e.code,{children:"compressed"}),"\u548c ",(0,t.jsx)(e.code,{children:"mangled"}),"\uff0c\u6240\u6709\u7a7a\u767d\u5b57\u7b26\u5c06\u88ab\u5220\u9664."]}),"\n",(0,t.jsx)(e.li,{children:"\u5bf9\u4e8ecss\u548chtml\u6a21\u5757\uff0c\u6240\u6709\u7a7a\u683c\u90fd\u5c06\u88ab\u5220\u9664"}),"\n"]}),"\n",(0,t.jsx)(e.admonition,{type:"note",children:(0,t.jsxs)(e.p,{children:["Farm \u4f7f\u7528 swc minifier\uff0c\u6709\u5173\u8be6\u7ec6\u9009\u9879\uff0c\u8bf7\u53c2\u9605",(0,t.jsx)(e.a,{href:"/zh/docs/config/compilation-options#minify",children:"compilation.minify"})]})})]})}function m(n={}){const{wrapper:e}={...(0,o.R)(),...n.components};return e?(0,t.jsx)(e,{...n,children:(0,t.jsx)(l,{...n})}):l(n)}},5710:(n,e,i)=>{i.d(e,{R:()=>r,x:()=>a});var t=i(758);const o={},c=t.createContext(o);function r(n){const e=t.useContext(c);return t.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function a(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(o):n.components||o:r(n.components),t.createElement(c.Provider,{value:e},n.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[1116],{6518:(n,e,i)=>{i.r(e),i.d(e,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>c,metadata:()=>a,toc:()=>d});var t=i(6070),o=i(5710);const c={},r="\u4ea7\u7269\u538b\u7f29",a={id:"advanced/minification",title:"\u4ea7\u7269\u538b\u7f29",description:"Farm \u652f\u6301\u5f00\u7bb1\u5373\u7528\u7684\u751f\u4ea7\u538b\u7f29\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u5728\u751f\u4ea7\u4e2d\u81ea\u52a8\u542f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7compilation.minify \u9009\u9879\u542f\u7528\u6216\u7981\u7528\u3002",source:"@site/i18n/zh/docusaurus-plugin-content-docs/current/advanced/minification.md",sourceDirName:"advanced",slug:"/advanced/minification",permalink:"/zh/docs/advanced/minification",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/advanced/minification.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Tree Shake",permalink:"/zh/docs/advanced/tree-shake"},next:{title:"\u8bed\u6cd5\u964d\u7ea7\u548c Polyfill",permalink:"/zh/docs/advanced/polyfill"}},s={},d=[];function l(n){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...n.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(e.h1,{id:"\u4ea7\u7269\u538b\u7f29",children:"\u4ea7\u7269\u538b\u7f29"}),"\n",(0,t.jsxs)(e.p,{children:["Farm \u652f\u6301\u5f00\u7bb1\u5373\u7528\u7684\u751f\u4ea7\u538b\u7f29\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u5728\u751f\u4ea7\u4e2d\u81ea\u52a8\u542f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7",(0,t.jsx)(e.a,{href:"/zh/docs/config/compilation-options#minify",children:"compilation.minify"})," \u9009\u9879\u542f\u7528\u6216\u7981\u7528\u3002"]}),"\n",(0,t.jsx)(e.pre,{children:(0,t.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default {\n compilation: {\n // enable minification for both development and production\n minify: true,\n },\n};\n"})}),"\n",(0,t.jsx)(e.p,{children:"\u5982\u679c\u542f\u7528\u538b\u7f29:"}),"\n",(0,t.jsxs)(e.ul,{children:["\n",(0,t.jsxs)(e.li,{children:["\u5bf9\u4e8e js/ts \u6a21\u5757\uff0c\u4ee3\u7801\u5c06\u88ab",(0,t.jsx)(e.code,{children:"compressed"}),"\u548c ",(0,t.jsx)(e.code,{children:"mangled"}),"\uff0c\u6240\u6709\u7a7a\u767d\u5b57\u7b26\u5c06\u88ab\u5220\u9664."]}),"\n",(0,t.jsx)(e.li,{children:"\u5bf9\u4e8ecss\u548chtml\u6a21\u5757\uff0c\u6240\u6709\u7a7a\u683c\u90fd\u5c06\u88ab\u5220\u9664"}),"\n"]}),"\n",(0,t.jsx)(e.admonition,{type:"note",children:(0,t.jsxs)(e.p,{children:["Farm \u4f7f\u7528 swc minifier\uff0c\u6709\u5173\u8be6\u7ec6\u9009\u9879\uff0c\u8bf7\u53c2\u9605",(0,t.jsx)(e.a,{href:"/zh/docs/config/compilation-options#minify",children:"compilation.minify"})]})})]})}function m(n={}){const{wrapper:e}={...(0,o.R)(),...n.components};return e?(0,t.jsx)(e,{...n,children:(0,t.jsx)(l,{...n})}):l(n)}},5710:(n,e,i)=>{i.d(e,{R:()=>r,x:()=>a});var t=i(758);const o={},c=t.createContext(o);function r(n){const e=t.useContext(c);return t.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function a(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(o):n.components||o:r(n.components),t.createElement(c.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/zh/assets/js/0478a834.36b479c1.js b/zh/assets/js/0478a834.36b479c1.js new file mode 100644 index 000000000..83a1da5bc --- /dev/null +++ b/zh/assets/js/0478a834.36b479c1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6480],{8808:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>l});var r=s(6070),c=s(5710);const i={},a="Tree Shake",t={id:"features/tree-shake",title:"Tree Shake",description:"Farm \u652f\u6301 Tree Shake\uff0c\u5728\u9ed8\u8ba4 Production \u73af\u5883\u4e0b\u81ea\u52a8\u5f00\u542f\u3002\u901a\u8fc7 compilation.treeShake \u9009\u9879\u53ef\u63a7\u5236\u5f00\u542f\u6216\u8005\u5173\u95ed\u3002",source:"@site/i18n/zh/docusaurus-plugin-content-docs/version-0.x/features/tree-shake.md",sourceDirName:"features",slug:"/features/tree-shake",permalink:"/zh/docs/0.x/features/tree-shake",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/versioned_docs/version-0.x/features/tree-shake.md",tags:[],version:"0.x",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Source Map",permalink:"/zh/docs/0.x/features/sourcemap"},next:{title:"\u538b\u7f29",permalink:"/zh/docs/0.x/features/minification"}},o={},l=[{value:"\u914d\u7f6e Tree Shake",id:"\u914d\u7f6e-tree-shake",level:2},{value:"\u5904\u7406 Side Effects",id:"\u5904\u7406-side-effects",level:2}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...(0,c.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"tree-shake",children:"Tree Shake"}),"\n",(0,r.jsxs)(n.p,{children:["Farm \u652f\u6301 Tree Shake\uff0c\u5728\u9ed8\u8ba4 Production \u73af\u5883\u4e0b\u81ea\u52a8\u5f00\u542f\u3002\u901a\u8fc7 ",(0,r.jsx)(n.code,{children:"compilation.treeShake"})," \u9009\u9879\u53ef\u63a7\u5236\u5f00\u542f\u6216\u8005\u5173\u95ed\u3002"]}),"\n",(0,r.jsx)(n.p,{children:"Tree Shake \u65f6\uff0c\u4f1a\u81ea\u52a8\u8bfb\u53d6 package.json \u4e2d\u7684 sideEffects \u5b57\u6bb5\uff0c\u6709 sideEffect \u7684\u6a21\u5757\u5c06\u4e0d\u4f1a\u8fdb\u884c Tree Shake\u3002"}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsx)(n.p,{children:"Farm \u4f1a\u5c06\u6240\u6709\u5faa\u73af\u4f9d\u8d56\u7684\u6a21\u5757\u89c6\u4f5c sideEffect\uff0c\u4e0d\u4f1a\u8fdb\u884c Tree Shake\uff0c\u8bf7\u5c3d\u91cf\u907f\u514d\u9879\u76ee\u4e2d\u5b58\u5728\u5faa\u73af\u4f9d\u8d56\u3002"})}),"\n",(0,r.jsx)(n.p,{children:"Tree shake \u793a\u4f8b:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1, b2 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\nexport b2 = "B2";\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"a.js"})," \u662f\u5165\u53e3\uff0c\u5b83\u5bfc\u5165\u4e86 ",(0,r.jsx)(n.code,{children:"b.js"}),"\uff0c\u7ecf\u8fc7 Tree Shaking\uff0c\u7ed3\u679c\u662f\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"b2"}),"\u672a\u4f7f\u7528\uff0c\u5c06\u5728",(0,r.jsx)(n.code,{children:"a.js"}),"\u548c",(0,r.jsx)(n.code,{children:"b.js"}),"\u4e2d\u5220\u9664"]}),"\n",(0,r.jsx)(n.h2,{id:"\u914d\u7f6e-tree-shake",children:"\u914d\u7f6e Tree Shake"}),"\n",(0,r.jsxs)(n.p,{children:["\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728\u751f\u4ea7\u6a21\u5f0f\u4e0b\u542f\u7528 Tree Shake\uff0c\u8981\u7981\u7528 Tree Shake\uff0c\u8bf7\u4f7f\u7528",(0,r.jsx)(n.code,{children:"compilation.treeShake"}),"\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default {\n compilation: {\n treeShake: false,\n },\n};\n"})}),"\n",(0,r.jsx)(n.h2,{id:"\u5904\u7406-side-effects",children:"\u5904\u7406 Side Effects"}),"\n",(0,r.jsxs)(n.p,{children:["\u5f53\u6a21\u5757\u5305\u542b",(0,r.jsx)(n.code,{children:"\u526f\u4f5c\u7528"}),"\u65f6\uff0cFarm \u4e0d\u4f1a\u5bf9\u5176\u5e94\u7528 tree shake\uff0c\u5e76\u4e14\u5176\u6240\u6709\u5bfc\u5165\u548c\u5bfc\u51fa\u90fd\u5c06\u88ab\u89c6\u4e3a\u5df2\u4f7f\u7528\u3002 Farm \u4f1a\u8ba4\u4e3a\u4ee5\u4e0b\u6a21\u5757\u6709",(0,r.jsx)(n.code,{children:"\u526f\u4f5c\u7528"}),"\uff1a"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"CommonJs \u6a21\u5757\u603b\u662f\u6709\u526f\u4f5c\u7528\u3002"}),"\n",(0,r.jsxs)(n.li,{children:["\u6a21\u5757\u5728\u5168\u5c40\u8303\u56f4\u5185\u5305\u542b",(0,r.jsx)(n.code,{children:"\u81ea\u6267\u884c"}),"\u8bed\u53e5\u6709\u526f\u4f5c\u7528"]}),"\n",(0,r.jsx)(n.li,{children:"\u5305\u542b\u5faa\u73af\u4f9d\u8d56\u7684\u6a21\u5757\u6709\u526f\u4f5c\u7528"}),"\n",(0,r.jsxs)(n.li,{children:["\u6a21\u5757\u4e0e\u6700\u63a5\u8fd1\u7684 ",(0,r.jsx)(n.code,{children:"package.json"})," \u4e2d\u7684 ",(0,r.jsx)(n.code,{children:"sideEffects"})," \u914d\u7f6e\u76f8\u5339\u914d\n5.\u5165\u53e3\u6a21\u5757\u603b\u662f\u6709\u526f\u4f5c\u7528\u3002"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Example 1:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:"const a = require('./')\nmodule.exports = a;\n"})}),"\n",(0,r.jsx)(n.p,{children:"CommonJs \u6a21\u5757\u603b\u662f\u6709\u526f\u4f5c\u7528\u3002"}),"\n",(0,r.jsx)(n.p,{children:"Example 2:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:"import a from './';\n\na();\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"a()"})," \u5728\u5168\u5c40\u8303\u56f4\u5185\u6267\u884c\uff0c\u6211\u4eec\u5c06\u5176\u89c6\u4e3a\u526f\u4f5c\u7528\u3002"]}),"\n",(0,r.jsx)(n.p,{children:"Example 3:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:"// a.js\nimport b from './b.js'\n\n// b.js\nimport a from './a.js'\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"a"}),"\u3001",(0,r.jsx)(n.code,{children:"b"})," \u662f\u5faa\u73af\u4f9d\u8d56\uff0c\u56e0\u6b64\u5b83\u4eec\u4e5f\u5c06\u88ab\u89c6\u4e3a\u526f\u4f5c\u7528\u3002"]}),"\n",(0,r.jsx)(n.p,{children:"Example 4:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",metastring:'title="package.json"',children:'{\n "name": "my-package",\n "sideEffects": [\n "./global/**.ts"\n ]\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"global/"})," \u4e0b\u7684\u6240\u6709 ts \u6a21\u5757\u90fd\u88ab\u89c6\u4e3a\u526f\u4f5c\u7528\u3002"]})]})}function h(e={}){const{wrapper:n}={...(0,c.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},5710:(e,n,s)=>{s.d(n,{R:()=>a,x:()=>t});var r=s(758);const c={},i=r.createContext(c);function a(e){const n=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:a(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/zh/assets/js/0478a834.a427a02e.js b/zh/assets/js/0478a834.a427a02e.js deleted file mode 100644 index 8a65c5a9c..000000000 --- a/zh/assets/js/0478a834.a427a02e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6480],{599:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>l});var r=s(6070),c=s(5710);const i={},a="Tree Shake",t={id:"features/tree-shake",title:"Tree Shake",description:"Farm \u652f\u6301 Tree Shake\uff0c\u5728\u9ed8\u8ba4 Production \u73af\u5883\u4e0b\u81ea\u52a8\u5f00\u542f\u3002\u901a\u8fc7 compilation.treeShake \u9009\u9879\u53ef\u63a7\u5236\u5f00\u542f\u6216\u8005\u5173\u95ed\u3002",source:"@site/i18n/zh/docusaurus-plugin-content-docs/version-0.x/features/tree-shake.md",sourceDirName:"features",slug:"/features/tree-shake",permalink:"/zh/docs/0.x/features/tree-shake",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/versioned_docs/version-0.x/features/tree-shake.md",tags:[],version:"0.x",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Source Map",permalink:"/zh/docs/0.x/features/sourcemap"},next:{title:"\u538b\u7f29",permalink:"/zh/docs/0.x/features/minification"}},o={},l=[{value:"\u914d\u7f6e Tree Shake",id:"\u914d\u7f6e-tree-shake",level:2},{value:"\u5904\u7406 Side Effects",id:"\u5904\u7406-side-effects",level:2}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...(0,c.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"tree-shake",children:"Tree Shake"}),"\n",(0,r.jsxs)(n.p,{children:["Farm \u652f\u6301 Tree Shake\uff0c\u5728\u9ed8\u8ba4 Production \u73af\u5883\u4e0b\u81ea\u52a8\u5f00\u542f\u3002\u901a\u8fc7 ",(0,r.jsx)(n.code,{children:"compilation.treeShake"})," \u9009\u9879\u53ef\u63a7\u5236\u5f00\u542f\u6216\u8005\u5173\u95ed\u3002"]}),"\n",(0,r.jsx)(n.p,{children:"Tree Shake \u65f6\uff0c\u4f1a\u81ea\u52a8\u8bfb\u53d6 package.json \u4e2d\u7684 sideEffects \u5b57\u6bb5\uff0c\u6709 sideEffect \u7684\u6a21\u5757\u5c06\u4e0d\u4f1a\u8fdb\u884c Tree Shake\u3002"}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsx)(n.p,{children:"Farm \u4f1a\u5c06\u6240\u6709\u5faa\u73af\u4f9d\u8d56\u7684\u6a21\u5757\u89c6\u4f5c sideEffect\uff0c\u4e0d\u4f1a\u8fdb\u884c Tree Shake\uff0c\u8bf7\u5c3d\u91cf\u907f\u514d\u9879\u76ee\u4e2d\u5b58\u5728\u5faa\u73af\u4f9d\u8d56\u3002"})}),"\n",(0,r.jsx)(n.p,{children:"Tree shake \u793a\u4f8b:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1, b2 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\nexport b2 = "B2";\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"a.js"})," \u662f\u5165\u53e3\uff0c\u5b83\u5bfc\u5165\u4e86 ",(0,r.jsx)(n.code,{children:"b.js"}),"\uff0c\u7ecf\u8fc7 Tree Shaking\uff0c\u7ed3\u679c\u662f\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="a.js"',children:"import { b1 } from 'b';\nconsole.log(b1);\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",metastring:'title="b.js"',children:'export b1 = "B1";\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"b2"}),"\u672a\u4f7f\u7528\uff0c\u5c06\u5728",(0,r.jsx)(n.code,{children:"a.js"}),"\u548c",(0,r.jsx)(n.code,{children:"b.js"}),"\u4e2d\u5220\u9664"]}),"\n",(0,r.jsx)(n.h2,{id:"\u914d\u7f6e-tree-shake",children:"\u914d\u7f6e Tree Shake"}),"\n",(0,r.jsxs)(n.p,{children:["\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728\u751f\u4ea7\u6a21\u5f0f\u4e0b\u542f\u7528 Tree Shake\uff0c\u8981\u7981\u7528 Tree Shake\uff0c\u8bf7\u4f7f\u7528",(0,r.jsx)(n.code,{children:"compilation.treeShake"}),"\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"export default {\n compilation: {\n treeShake: false,\n },\n};\n"})}),"\n",(0,r.jsx)(n.h2,{id:"\u5904\u7406-side-effects",children:"\u5904\u7406 Side Effects"}),"\n",(0,r.jsxs)(n.p,{children:["\u5f53\u6a21\u5757\u5305\u542b",(0,r.jsx)(n.code,{children:"\u526f\u4f5c\u7528"}),"\u65f6\uff0cFarm \u4e0d\u4f1a\u5bf9\u5176\u5e94\u7528 tree shake\uff0c\u5e76\u4e14\u5176\u6240\u6709\u5bfc\u5165\u548c\u5bfc\u51fa\u90fd\u5c06\u88ab\u89c6\u4e3a\u5df2\u4f7f\u7528\u3002 Farm \u4f1a\u8ba4\u4e3a\u4ee5\u4e0b\u6a21\u5757\u6709",(0,r.jsx)(n.code,{children:"\u526f\u4f5c\u7528"}),"\uff1a"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"CommonJs \u6a21\u5757\u603b\u662f\u6709\u526f\u4f5c\u7528\u3002"}),"\n",(0,r.jsxs)(n.li,{children:["\u6a21\u5757\u5728\u5168\u5c40\u8303\u56f4\u5185\u5305\u542b",(0,r.jsx)(n.code,{children:"\u81ea\u6267\u884c"}),"\u8bed\u53e5\u6709\u526f\u4f5c\u7528"]}),"\n",(0,r.jsx)(n.li,{children:"\u5305\u542b\u5faa\u73af\u4f9d\u8d56\u7684\u6a21\u5757\u6709\u526f\u4f5c\u7528"}),"\n",(0,r.jsxs)(n.li,{children:["\u6a21\u5757\u4e0e\u6700\u63a5\u8fd1\u7684 ",(0,r.jsx)(n.code,{children:"package.json"})," \u4e2d\u7684 ",(0,r.jsx)(n.code,{children:"sideEffects"})," \u914d\u7f6e\u76f8\u5339\u914d\n5.\u5165\u53e3\u6a21\u5757\u603b\u662f\u6709\u526f\u4f5c\u7528\u3002"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Example 1:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:"const a = require('./')\nmodule.exports = a;\n"})}),"\n",(0,r.jsx)(n.p,{children:"CommonJs \u6a21\u5757\u603b\u662f\u6709\u526f\u4f5c\u7528\u3002"}),"\n",(0,r.jsx)(n.p,{children:"Example 2:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:"import a from './';\n\na();\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"a()"})," \u5728\u5168\u5c40\u8303\u56f4\u5185\u6267\u884c\uff0c\u6211\u4eec\u5c06\u5176\u89c6\u4e3a\u526f\u4f5c\u7528\u3002"]}),"\n",(0,r.jsx)(n.p,{children:"Example 3:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:"// a.js\nimport b from './b.js'\n\n// b.js\nimport a from './a.js'\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"a"}),"\u3001",(0,r.jsx)(n.code,{children:"b"})," \u662f\u5faa\u73af\u4f9d\u8d56\uff0c\u56e0\u6b64\u5b83\u4eec\u4e5f\u5c06\u88ab\u89c6\u4e3a\u526f\u4f5c\u7528\u3002"]}),"\n",(0,r.jsx)(n.p,{children:"Example 4:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",metastring:'title="package.json"',children:'{\n "name": "my-package",\n "sideEffects": [\n "./global/**.ts"\n ]\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"global/"})," \u4e0b\u7684\u6240\u6709 ts \u6a21\u5757\u90fd\u88ab\u89c6\u4e3a\u526f\u4f5c\u7528\u3002"]})]})}function h(e={}){const{wrapper:n}={...(0,c.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},5710:(e,n,s)=>{s.d(n,{R:()=>a,x:()=>t});var r=s(758);const c={},i=r.createContext(c);function a(e){const n=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:a(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/zh/assets/js/04b9aafc.51766bf9.js b/zh/assets/js/04b9aafc.e923b223.js similarity index 99% rename from zh/assets/js/04b9aafc.51766bf9.js rename to zh/assets/js/04b9aafc.e923b223.js index 13cf0017e..a1cd04e18 100644 --- a/zh/assets/js/04b9aafc.51766bf9.js +++ b/zh/assets/js/04b9aafc.e923b223.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[5387],{7855:(n,e,s)=>{s.r(e),s.d(e,{assets:()=>o,contentTitle:()=>t,default:()=>a,frontMatter:()=>l,metadata:()=>c,toc:()=>d});var i=s(6070),r=s(5710);const l={},t="\u4f7f\u7528\u63d2\u4ef6",c={id:"using-plugins",title:"\u4f7f\u7528\u63d2\u4ef6",description:"Farm\u652f\u63014\u79cd\u63d2\u4ef6\uff1a",source:"@site/i18n/zh/docusaurus-plugin-content-docs/current/using-plugins.md",sourceDirName:".",slug:"/using-plugins",permalink:"/zh/docs/using-plugins",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/using-plugins.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"\u5feb\u901f\u5f00\u59cb",permalink:"/zh/docs/quick-start"},next:{title:"Contribution Guide",permalink:"/zh/docs/contribution"}},o={},d=[{value:"Farm \u7f16\u8bd1\u63d2\u4ef6",id:"farm-\u7f16\u8bd1\u63d2\u4ef6",level:2},{value:"\u4f7f\u7528 Rust \u63d2\u4ef6",id:"\u4f7f\u7528-rust-\u63d2\u4ef6",level:3},{value:"\u4f7f\u7528 Js \u63d2\u4ef6",id:"\u4f7f\u7528-js-\u63d2\u4ef6",level:3},{value:"\u4f7f\u7528 Vite/Rollup/Unplugin \u63d2\u4ef6",id:"\u4f7f\u7528-viterollupunplugin-\u63d2\u4ef6",level:2},{value:"Farm \u8fd0\u884c\u65f6\u63d2\u4ef6",id:"farm-\u8fd0\u884c\u65f6\u63d2\u4ef6",level:2},{value:"\u4f7f\u7528 SWC \u63d2\u4ef6",id:"\u4f7f\u7528-swc-\u63d2\u4ef6",level:2}];function u(n){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"\u4f7f\u7528\u63d2\u4ef6",children:"\u4f7f\u7528\u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"Farm\u652f\u63014\u79cd\u63d2\u4ef6\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Farm \u7f16\u8bd1\u63d2\u4ef6"})}),"\uff1a\u652f\u6301 Rust \u63d2\u4ef6\u548c Js \u63d2\u4ef6\uff0c\u91c7\u7528 rollup \u98ce\u683c\u7684 hooks\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Vite/Rollup/Unplugin \u63d2\u4ef6"})}),"\uff1aFarm \u5f00\u7bb1\u5373\u7528\u652f\u6301 Vite/Rollup/Unplugin \u63d2\u4ef6"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Farm \u8fd0\u884c\u65f6\u63d2\u4ef6"})}),"\uff1a\u4e3a Farm \u7684\u8fd0\u884c\u65f6\u7cfb\u7edf\u6dfb\u52a0\u529f\u80fd\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Swc \u63d2\u4ef6"})}),"\uff1aFarm \u5f00\u7bb1\u5373\u7528\u652f\u6301 Swc \u63d2\u4ef6\u3002"]}),"\n"]}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u5982\u4f55\u7f16\u5199\u81ea\u5df1\u7684\u63d2\u4ef6\uff0c\u8bf7\u53c2\u8003",(0,i.jsx)(e.a,{href:"/docs/plugins/writing-plugins/overview",children:"\u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h2,{id:"farm-\u7f16\u8bd1\u63d2\u4ef6",children:"Farm \u7f16\u8bd1\u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"\u9996\u5148\uff0c\u5b89\u88c5\u60a8\u9700\u8981\u7684\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u4f7f\u7528 ",(0,i.jsx)(e.code,{children:"plugins"})," \u914d\u7f6e Farm \u7f16\u8bd1\u63d2\u4ef6\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'import farmPostcssPlugin from "@farmfe/js-plugin-postcss";\n\nexport default defineConfig({\n // ...\n plugins: [\n // Rust\u63d2\u4ef6\uff0c\u914d\u7f6e\u5176\u5305\u540d\n "@farmfe/plugin-sass",\n // JS\u63d2\u4ef6\uff0c\u914d\u7f6e\u63d2\u4ef6\u5bf9\u8c61\n farmPostcssPlugin()\n ],\n});\n'})}),"\n",(0,i.jsx)(e.p,{children:"Farm\u7f16\u8bd1\u63d2\u4ef6\u67092\u79cd\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Rust Plugins"})}),"\uff1a\u7528 Rust \u7f16\u5199\uff0c\u5177\u6709\u6700\u4f73\u6027\u80fd\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Js Plugins"})}),"\uff1a\u7528JS/TS\u7f16\u5199\uff0c\u7528\u4e8e\u517c\u5bb9\u5f53\u524d\u7684JS\u751f\u6001\u7cfb\u7edf"]}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"\u4f7f\u7528-rust-\u63d2\u4ef6",children:"\u4f7f\u7528 Rust \u63d2\u4ef6"}),"\n",(0,i.jsxs)(e.p,{children:["\u4f7f\u7528 ",(0,i.jsx)(e.code,{children:"package name"})," \u6765\u914d\u7f6e Rust \u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'export default defineConfig({\n // ...\n plugins: [\n "@farmfe/plugin-sass",\n ],\n});\n'})}),"\n",(0,i.jsxs)(e.p,{children:["\u5bf9\u4e8e\u4e0a\u9762\u7684\u4f8b\u5b50\uff0cFarm \u5c06\u89e3\u6790\u5305 ",(0,i.jsx)(e.code,{children:"@farmfe/plugin-sass"})," \u5e76\u5c06\u5176\u89c6\u4e3a Farm Rust \u63d2\u4ef6\u3002"]}),"\n",(0,i.jsxs)(e.p,{children:["\u5982\u679c\u8981\u4e3a Rust \u63d2\u4ef6\u914d\u7f6e\u9009\u9879\uff0c\u53ef\u4ee5\u4f7f\u7528",(0,i.jsx)(e.code,{children:"\u6570\u7ec4\u8bed\u6cd5"}),"\uff0c\u5982",(0,i.jsx)(e.code,{children:"[packageName, optionsObject]"}),"\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'export default defineConfig({\n // ...\n plugins: [\n // \u4f7f\u7528\u6570\u7ec4\u8bed\u6cd5\u6765\u914d\u7f6e Rust \u63d2\u4ef6\n [\n // Rust \u63d2\u4ef6\u7684\u540d\u79f0\n "@farmfe/plugin-sass",\n // Rust \u63d2\u4ef6\u7684\u9009\u9879\n {\n additionalData: \'@use "@/global-variables.scss";\'\n }\n ],\n ],\n});\n'})}),"\n",(0,i.jsx)(e.p,{children:"\u76ee\u524d Farm \u5b98\u65b9\u652f\u6301 2 \u4e2a Rust \u63d2\u4ef6\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-react"})}),"\uff1aFarm rust \u63d2\u4ef6\uff0c\u7528\u4e8e React jsx \u7f16\u8bd1\u548c React-refresh \u6ce8\u5165\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-sass"})}),"\uff1a\u7528\u4e8e scss \u6587\u4ef6\u7f16\u8bd1\u7684 Farm rust \u63d2\u4ef6\uff0c\u5185\u90e8\u4f7f\u7528 ",(0,i.jsx)(e.code,{children:"sass-embedded"}),"\u3002"]}),"\n"]}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u8981\u4e86\u89e3\u6709\u5173 rust \u63d2\u4ef6\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 ",(0,i.jsx)(e.a,{href:"/docs/plugins/official-plugins/overview#rust-%E6%8F%92%E4%BB%B6",children:"Rust \u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h3,{id:"\u4f7f\u7528-js-\u63d2\u4ef6",children:"\u4f7f\u7528 Js \u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"Farm JS \u63d2\u4ef6\u662f\u4e00\u4e2a\u4ee5\u65b9\u6cd5\u4e3a\u94a9\u5b50\u7684 JS \u5bf9\u8c61\uff0c\u4f8b\u5982\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'import farmPostcssPlugin from "@farmfe/js-plugin-postcss";\n\nexport default defineConfig({\n plugins: [\n farmPostcssPlugin({\n // ... \u914d\u7f6e postcss \u9009\u9879\n })\n ],\n});\n'})}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"farmPostcssPlugin()"}),"\u8fd4\u56de\u4e00\u4e2a\u63d2\u4ef6\u5bf9\u8c61\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u5176\u53c2\u6570\u4f20\u9012\u4efb\u4f55 postcss \u9009\u9879\u3002"]}),"\n",(0,i.jsxs)(e.p,{children:["\u60a8\u53ef\u4ee5\u4f7f\u7528",(0,i.jsx)(e.code,{children:"priority"}),"\u6765\u63a7\u5236\u63d2\u4ef6\u7684\u987a\u5e8f\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts" {10,11}',children:'import farmPostcssPlugin from "@farmfe/js-plugin-postcss";\n\nexport default defineConfig({\n plugins: [\n {\n ...farmPostcssPlugin({\n // ... configure postcss options\n }),\n // larger priority will be executed first, priority of internal plugin are 100.\n priority: 1000,\n }\n ],\n});\n'})}),"\n",(0,i.jsx)(e.p,{children:"\u5185\u90e8\u63d2\u4ef6\u7684\u4f18\u5148\u7ea7\u90fd\u662f100\uff0c\u5982\u679c\u60f3\u8ba9\u63d2\u4ef6\u5148\u6267\u884c\uff0c\u5c31\u8bbe\u7f6e\u5927\u4e8e100\uff0c\u5426\u5219\u8bbe\u7f6e\u5c0f\u4e8e100\u3002"}),"\n",(0,i.jsx)(e.p,{children:"\u5982\u679c\u4f60\u60f3\u5feb\u901f\u6dfb\u52a0 Farm JS \u63d2\u4ef6\uff0c\u53ea\u9700\u914d\u7f6e\u4e00\u4e2a\u63d2\u4ef6\u5bf9\u8c61\u5373\u53ef\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import readFileSync from 'fs';\n\nexport default defineConfig({\n plugins: [\n // \u914d\u7f6e\u81ea\u5b9a\u4e49\u63d2\u4ef6\n {\n // \u63d2\u4ef6\u540d\u79f0\uff0c\u5fc5\u586b\n name: 'my-first-farm-plugin',\n // \u8fd9\u4e2a\u63d2\u4ef6\u7684\u4f18\u5148\u7ea7\uff0c\u503c\u8d8a\u5927\u5148\u6267\u884c\uff0c\u9ed8\u8ba4100\u3002\n priority: 1000,\n // \u5b9a\u4e49\u4e00\u4e2a\u52a0\u8f7d\u94a9\u5b50\u6765\u786e\u5b9a\u5982\u4f55\u52a0\u8f7d\u6a21\u5757\n load: {\n // \u4e3a\u4e86\u63d0\u9ad8\u6027\u80fd\uff0c\u5982\u679c\u6a21\u5757\u4e0e\u8fc7\u6ee4\u5668\u4e0d\u5339\u914d\uff0c\u5c06\u88ab\u8df3\u8fc7\u3002\n filters: {\n // \u4ec5\u5bf9 .png \u6587\u4ef6\u6267\u884c\u3002\n resolvedPaths: ['\\\\.txt$']\n },\n // \u8be5\u94a9\u5b50\u7684\u6267\u884c\u56de\u8c03\n executor: (params, context) => {\n const { resolvedPath } = params;\n const content = readFileSync(resolvedPath, 'utf-8');\n\n return {\n content: `export default '${content}'`,\n moduleType: 'js'\n }\n }\n }\n }\n ],\n});\n"})}),"\n",(0,i.jsx)(e.admonition,{type:"warning",children:(0,i.jsxs)(e.p,{children:["Farm \u4e2d\u7684 js \u63d2\u4ef6\u9700\u8981 ",(0,i.jsx)(e.code,{children:"filters"}),"\u3002 \u56e0\u4e3aJs Plugin\u5b9e\u5728\u662f\u592a\u6162\u4e86\uff0c\u6211\u4eec\u5e94\u8be5\u5c3d\u91cf\u907f\u514d\u6267\u884c\u5b83\u3002\u914d\u7f6e filters \u540e\uff0c\u5bf9\u4e8e\u90a3\u4e9b\u4e0d\u7b26\u5408\u8fc7\u6ee4\u5668\u7684\u6a21\u5757\uff0cFarm \u6839\u672c\u4e0d\u4f1a\u4e3a\u5b83\u4eec\u89e6\u53d1 js \u63d2\u4ef6\u94a9\u5b50\uff01 \u8fd9\u610f\u5473\u7740 Farm \u53ea\u5728 Rust \u4fa7\u5c31\u80fd\u5b89\u5168\u3001\u5e76\u53d1\u5730\u8fdb\u884c\u5904\u7406\uff0c\u4ee5\u6700\u5927\u5316\u63d0\u5347\u7f16\u8bd1\u6027\u80fd\u3002"]})}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u4e86\u89e3\u66f4\u591a\u5173\u4e8e Farm Js \u63d2\u4ef6\u7684\u4fe1\u606f\uff0c\u8bf7\u53c2\u8003 ",(0,i.jsx)(e.a,{href:"/docs/plugins/official-plugins/overview#js-%E6%8F%92%E4%BB%B6",children:"JS \u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h2,{id:"\u4f7f\u7528-viterollupunplugin-\u63d2\u4ef6",children:"\u4f7f\u7528 Vite/Rollup/Unplugin \u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"Farm \u517c\u5bb9 Vite \u63d2\u4ef6\uff0cVite \u63d2\u4ef6\u53ef\u4ee5\u76f4\u63a5\u5728 Farm \u4e2d\u914d\u7f6e\u4f7f\u7528\u3002 \u9996\u5148\u9700\u8981\u5b89\u88c5 vite \u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u7136\u540e\u5c31\u53ef\u4ee5\u901a\u8fc7",(0,i.jsx)(e.code,{children:"farm.config.ts"}),"\u4e2d\u7684",(0,i.jsx)(e.code,{children:"vitePlugins"}),"\u76f4\u63a5\u4f7f\u7528vite\u63d2\u4ef6\u4e86\u3002"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import vue from '@vitejs/plugin-vue',\nimport vueJsx from '@vitejs/plugin-vue-jsx';\n\nexport default defineConfig({\n // \u914d\u7f6evite\u63d2\u4ef6\n vitePlugins: [\n vue(),\n vueJsx()\n ]\n});\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u4e3a\u4e86\u63d0\u9ad8 vite \u63d2\u4ef6\u7684\u6027\u80fd\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd4\u56de",(0,i.jsx)(e.code,{children:"\u8fc7\u6ee4\u5668"}),"\u7684",(0,i.jsx)(e.code,{children:"\u51fd\u6570\u8bed\u6cd5"}),"\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import vue from '@vitejs/plugin-vue',\n\n// // \u4f7f\u7528Farm \u4e2d Vite \u63d2\u4ef6\u7684\u51fd\u6570\u8bed\u6cd5\nfunction configureVitePluginVue() {\n // \u8fd4\u56de\u63d2\u4ef6\u53ca\u5176\u8fc7\u6ee4\u5668\n return {\n // \u4f7f\u7528 vue \u63d2\u4ef6\n vitePlugin: vue(),\n // \u4e3a\u5176\u914d\u7f6e\u8fc7\u6ee4\u5668\u3002 \u4e0d\u5339\u914d\u7684\u6a21\u5757\u8def\u5f84\u5c06\u88ab\u8df3\u8fc7\u3002\n filters: ['\\\\.vue$', '\\\\\\\\0.+']\n };\n}\n\nexport default defineConfig({\n vitePlugins: [\n configureVitePluginVue\n ]\n});\n"})}),"\n",(0,i.jsx)(e.p,{children:"\u4f7f\u7528 unplugin\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"pnpm add unplugin-auto-import unplugin-vue-components -D\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u5728 ",(0,i.jsx)(e.code,{children:"vitePlugins"})," \u4e2d\u914d\u7f6e\uff0c\u901a\u8fc7 ",(0,i.jsx)(e.code,{children:"unplugin/vite"})," \u6216\u8005 ",(0,i.jsx)(e.code,{children:"unplugin/rollup"})," \u652f\u6301:"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import vue from '@vitejs/plugin-vue',\nimport AutoImport from 'unplugin-auto-import/vite'\nimport Components from 'unplugin-vue-components/vite'\nimport { ElementPlusResolver } from 'unplugin-vue-components/resolvers'\n\nexport default defineConfig({\n vitePlugins: [\n vue(),\n // ...\n AutoImport({\n resolvers: [ElementPlusResolver({ importStyle: 'sass' })],\n }),\n Components({\n resolvers: [ElementPlusResolver({ importStyle: 'sass' })],\n }),\n ]\n});\n"})}),"\n",(0,i.jsx)(e.admonition,{type:"note",children:(0,i.jsxs)(e.p,{children:["\u76ee\u524d\uff0c\u60a8\u53ef\u4ee5\u5728 Farm \u4e2d\u4f7f\u7528",(0,i.jsx)(e.code,{children:"unplugin/farm"}),"\u3001",(0,i.jsx)(e.code,{children:"unplugin/vite"}),"\u548c",(0,i.jsx)(e.code,{children:"unplugin/rollup"}),"\u3002\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f",(0,i.jsx)(e.code,{children:"unplugin/vite"}),"\u6216",(0,i.jsx)(e.code,{children:"unplugin/Rolup"}),"\uff0c\u6709\u4e9b\u5c5e\u6027\u53ef\u80fd\u8fd8\u6ca1\u6709\u5b8c\u5168\u9002\u914d\uff0c\u6216\u8005 Farm \u56e2\u961f\u8ba4\u4e3a\u8be5 ",(0,i.jsx)(e.code,{children:"api"})," \u4e0d\u5177\u5907\u9002\u914d\u6761\u4ef6\uff0c\u53ef\u4ee5\u63d0\u4f9b",(0,i.jsx)(e.a,{href:"https://github.com/farm-fe/farm/issues/new/choose",children:"issues"})," ."]})}),"\n",(0,i.jsx)(e.h2,{id:"farm-\u8fd0\u884c\u65f6\u63d2\u4ef6",children:"Farm \u8fd0\u884c\u65f6\u63d2\u4ef6"}),"\n",(0,i.jsxs)(e.p,{children:["Farm\u6709\u4e00\u4e2a\u8fd0\u884c\u65f6\u6a21\u5757\u7cfb\u7edf\u6765\u63a7\u5236\u5982\u4f55\u52a0\u8f7d\u548c\u6267\u884c\u6a21\u5757\u3002 \u914d\u7f6e ",(0,i.jsx)(e.code,{children:"compilation.runtime.plugins"})," \u4ee5\u6dfb\u52a0\u66f4\u591a\u8fd0\u884c\u65f6\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"export default defineConfig({\n compilation: {\n // \u914d\u7f6e Farm \u8fd0\u884c\u65f6\u6a21\u5757\u7cfb\u7edf\n runtime: {\n plugins: [\n // \u8fd0\u884c\u65f6\u63d2\u4ef6\u5305\n require.resolve('farm-plugin-runtime-mock'),\n // \u672c\u5730\u8fd0\u884c\u65f6\u63d2\u4ef6\n path.join(process.cwd(), \"build/runtime-plugin.ts\")\n ]\n }\n }\n});\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u60a8\u5fc5\u987b\u914d\u7f6e\u6307\u5411\u8fd0\u884c\u65f6\u63d2\u4ef6\u7684\u8def\u5f84\u3002 \u63a8\u8350\u4f7f\u7528 ",(0,i.jsx)(e.strong,{children:"\u7edd\u5bf9\u8def\u5f84"})," \u4ee5\u907f\u514d\u8def\u5f84\u95ee\u9898\u3002"]}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u8981\u4e86\u89e3\u6709\u5173\u8fd0\u884c\u65f6\u63d2\u4ef6\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 ",(0,i.jsx)(e.a,{href:"/docs/plugins/writing-plugins/runtime-plugin",children:"\u8fd0\u884c\u65f6\u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h2,{id:"\u4f7f\u7528-swc-\u63d2\u4ef6",children:"\u4f7f\u7528 SWC \u63d2\u4ef6"}),"\n",(0,i.jsxs)(e.p,{children:["Swc Plugin \u4e5f\u53ef\u4ee5\u76f4\u63a5\u5728Farm\u4e2d\u4f7f\u7528\uff0c\u914d\u7f6e",(0,i.jsx)(e.code,{children:"compilation.script.plugins"}),"\u6765\u6dfb\u52a0SWC\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"import jsPluginVue from '@farmfe/js-plugin-vue';\n\nexport default defineConfig({\n compilation: {\n script: {\n plugins: [{\n //swc\u63d2\u4ef6\u7684\u5305\u540d\n name: 'swc-plugin-vue-jsx',\n // \u8be5swc\u63d2\u4ef6\u7684\u9009\u9879\n options: {\n \"transformOn\": true,\n \"optimize\": true\n },\n // \u5f53\u8fc7\u6ee4\u5668\u5339\u914d\u65f6\u63d2\u4ef6\u6267\u884c\u3002\n filters: {\n // resolvedPaths: [\".+\"]\n moduleTypes: ['tsx', 'jsx'],\n }\n }]\n }\n },\n plugins: [jsPluginVue()],\n});\n"})}),"\n",(0,i.jsx)(e.p,{children:"\u6570\u7ec4\u7684\u6bcf\u4e2a\u63d2\u4ef6\u9879\u5305\u542b\u4e09\u4e2a\u5b57\u6bb5\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:"name"}),"\uff1aswc\u63d2\u4ef6\u7684\u5305\u540d"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:"options"}),"\uff1a\u4f20\u9012\u7ed9swc\u63d2\u4ef6\u7684\u914d\u7f6e\u9879"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:"filters"}),"\uff1a\u6267\u884c\u63d2\u4ef6\u7684\u54ea\u4e9b\u6a21\u5757\uff0c\u5fc5\u987b\u914d\u7f6e\uff0c\u652f\u6301",(0,i.jsx)(e.code,{children:"resolvedPaths"}),"\u548c",(0,i.jsx)(e.code,{children:"moduleTypes"}),"\u8fd9\u4e24\u4e2a\u8fc7\u6ee4\u9879\uff0c\u5982\u679c\u4e24\u8005\u540c\u65f6\u6307\u5b9a\uff0c\u5219\u53d6\u5e76\u96c6\u3002"]}),"\n"]}),"\n",(0,i.jsx)(e.admonition,{type:"note",children:(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SWC \u63d2\u4ef6"}),"\u53ef\u80fd\u4e0e Farm \u4f7f\u7528\u7684 ",(0,i.jsx)(e.code,{children:"SWC \u7248\u672c"}),"(rust crate ",(0,i.jsx)(e.code,{children:"swc_core v0.90"}),") \u4e0d\u517c\u5bb9\u3002 \u5982\u679c\u51fa\u73b0\u9519\u8bef\uff0c\u8bf7\u5c1d\u8bd5\u5347\u7ea7\u63d2\u4ef6\u3002"]})})]})}function a(n={}){const{wrapper:e}={...(0,r.R)(),...n.components};return e?(0,i.jsx)(e,{...n,children:(0,i.jsx)(u,{...n})}):u(n)}},5710:(n,e,s)=>{s.d(e,{R:()=>t,x:()=>c});var i=s(758);const r={},l=i.createContext(r);function t(n){const e=i.useContext(l);return i.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function c(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(r):n.components||r:t(n.components),i.createElement(l.Provider,{value:e},n.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[5387],{5076:(n,e,s)=>{s.r(e),s.d(e,{assets:()=>o,contentTitle:()=>t,default:()=>a,frontMatter:()=>l,metadata:()=>c,toc:()=>d});var i=s(6070),r=s(5710);const l={},t="\u4f7f\u7528\u63d2\u4ef6",c={id:"using-plugins",title:"\u4f7f\u7528\u63d2\u4ef6",description:"Farm\u652f\u63014\u79cd\u63d2\u4ef6\uff1a",source:"@site/i18n/zh/docusaurus-plugin-content-docs/current/using-plugins.md",sourceDirName:".",slug:"/using-plugins",permalink:"/zh/docs/using-plugins",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/using-plugins.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"\u5feb\u901f\u5f00\u59cb",permalink:"/zh/docs/quick-start"},next:{title:"Contribution Guide",permalink:"/zh/docs/contribution"}},o={},d=[{value:"Farm \u7f16\u8bd1\u63d2\u4ef6",id:"farm-\u7f16\u8bd1\u63d2\u4ef6",level:2},{value:"\u4f7f\u7528 Rust \u63d2\u4ef6",id:"\u4f7f\u7528-rust-\u63d2\u4ef6",level:3},{value:"\u4f7f\u7528 Js \u63d2\u4ef6",id:"\u4f7f\u7528-js-\u63d2\u4ef6",level:3},{value:"\u4f7f\u7528 Vite/Rollup/Unplugin \u63d2\u4ef6",id:"\u4f7f\u7528-viterollupunplugin-\u63d2\u4ef6",level:2},{value:"Farm \u8fd0\u884c\u65f6\u63d2\u4ef6",id:"farm-\u8fd0\u884c\u65f6\u63d2\u4ef6",level:2},{value:"\u4f7f\u7528 SWC \u63d2\u4ef6",id:"\u4f7f\u7528-swc-\u63d2\u4ef6",level:2}];function u(n){const e={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"\u4f7f\u7528\u63d2\u4ef6",children:"\u4f7f\u7528\u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"Farm\u652f\u63014\u79cd\u63d2\u4ef6\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Farm \u7f16\u8bd1\u63d2\u4ef6"})}),"\uff1a\u652f\u6301 Rust \u63d2\u4ef6\u548c Js \u63d2\u4ef6\uff0c\u91c7\u7528 rollup \u98ce\u683c\u7684 hooks\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Vite/Rollup/Unplugin \u63d2\u4ef6"})}),"\uff1aFarm \u5f00\u7bb1\u5373\u7528\u652f\u6301 Vite/Rollup/Unplugin \u63d2\u4ef6"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Farm \u8fd0\u884c\u65f6\u63d2\u4ef6"})}),"\uff1a\u4e3a Farm \u7684\u8fd0\u884c\u65f6\u7cfb\u7edf\u6dfb\u52a0\u529f\u80fd\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Swc \u63d2\u4ef6"})}),"\uff1aFarm \u5f00\u7bb1\u5373\u7528\u652f\u6301 Swc \u63d2\u4ef6\u3002"]}),"\n"]}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u5982\u4f55\u7f16\u5199\u81ea\u5df1\u7684\u63d2\u4ef6\uff0c\u8bf7\u53c2\u8003",(0,i.jsx)(e.a,{href:"/docs/plugins/writing-plugins/overview",children:"\u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h2,{id:"farm-\u7f16\u8bd1\u63d2\u4ef6",children:"Farm \u7f16\u8bd1\u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"\u9996\u5148\uff0c\u5b89\u88c5\u60a8\u9700\u8981\u7684\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u4f7f\u7528 ",(0,i.jsx)(e.code,{children:"plugins"})," \u914d\u7f6e Farm \u7f16\u8bd1\u63d2\u4ef6\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'import farmPostcssPlugin from "@farmfe/js-plugin-postcss";\n\nexport default defineConfig({\n // ...\n plugins: [\n // Rust\u63d2\u4ef6\uff0c\u914d\u7f6e\u5176\u5305\u540d\n "@farmfe/plugin-sass",\n // JS\u63d2\u4ef6\uff0c\u914d\u7f6e\u63d2\u4ef6\u5bf9\u8c61\n farmPostcssPlugin()\n ],\n});\n'})}),"\n",(0,i.jsx)(e.p,{children:"Farm\u7f16\u8bd1\u63d2\u4ef6\u67092\u79cd\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Rust Plugins"})}),"\uff1a\u7528 Rust \u7f16\u5199\uff0c\u5177\u6709\u6700\u4f73\u6027\u80fd\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"Js Plugins"})}),"\uff1a\u7528JS/TS\u7f16\u5199\uff0c\u7528\u4e8e\u517c\u5bb9\u5f53\u524d\u7684JS\u751f\u6001\u7cfb\u7edf"]}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"\u4f7f\u7528-rust-\u63d2\u4ef6",children:"\u4f7f\u7528 Rust \u63d2\u4ef6"}),"\n",(0,i.jsxs)(e.p,{children:["\u4f7f\u7528 ",(0,i.jsx)(e.code,{children:"package name"})," \u6765\u914d\u7f6e Rust \u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'export default defineConfig({\n // ...\n plugins: [\n "@farmfe/plugin-sass",\n ],\n});\n'})}),"\n",(0,i.jsxs)(e.p,{children:["\u5bf9\u4e8e\u4e0a\u9762\u7684\u4f8b\u5b50\uff0cFarm \u5c06\u89e3\u6790\u5305 ",(0,i.jsx)(e.code,{children:"@farmfe/plugin-sass"})," \u5e76\u5c06\u5176\u89c6\u4e3a Farm Rust \u63d2\u4ef6\u3002"]}),"\n",(0,i.jsxs)(e.p,{children:["\u5982\u679c\u8981\u4e3a Rust \u63d2\u4ef6\u914d\u7f6e\u9009\u9879\uff0c\u53ef\u4ee5\u4f7f\u7528",(0,i.jsx)(e.code,{children:"\u6570\u7ec4\u8bed\u6cd5"}),"\uff0c\u5982",(0,i.jsx)(e.code,{children:"[packageName, optionsObject]"}),"\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'export default defineConfig({\n // ...\n plugins: [\n // \u4f7f\u7528\u6570\u7ec4\u8bed\u6cd5\u6765\u914d\u7f6e Rust \u63d2\u4ef6\n [\n // Rust \u63d2\u4ef6\u7684\u540d\u79f0\n "@farmfe/plugin-sass",\n // Rust \u63d2\u4ef6\u7684\u9009\u9879\n {\n additionalData: \'@use "@/global-variables.scss";\'\n }\n ],\n ],\n});\n'})}),"\n",(0,i.jsx)(e.p,{children:"\u76ee\u524d Farm \u5b98\u65b9\u652f\u6301 2 \u4e2a Rust \u63d2\u4ef6\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-react"})}),"\uff1aFarm rust \u63d2\u4ef6\uff0c\u7528\u4e8e React jsx \u7f16\u8bd1\u548c React-refresh \u6ce8\u5165\u3002"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:(0,i.jsx)(e.code,{children:"@farmfe/plugin-sass"})}),"\uff1a\u7528\u4e8e scss \u6587\u4ef6\u7f16\u8bd1\u7684 Farm rust \u63d2\u4ef6\uff0c\u5185\u90e8\u4f7f\u7528 ",(0,i.jsx)(e.code,{children:"sass-embedded"}),"\u3002"]}),"\n"]}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u8981\u4e86\u89e3\u6709\u5173 rust \u63d2\u4ef6\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 ",(0,i.jsx)(e.a,{href:"/docs/plugins/official-plugins/overview#rust-%E6%8F%92%E4%BB%B6",children:"Rust \u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h3,{id:"\u4f7f\u7528-js-\u63d2\u4ef6",children:"\u4f7f\u7528 Js \u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"Farm JS \u63d2\u4ef6\u662f\u4e00\u4e2a\u4ee5\u65b9\u6cd5\u4e3a\u94a9\u5b50\u7684 JS \u5bf9\u8c61\uff0c\u4f8b\u5982\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'import farmPostcssPlugin from "@farmfe/js-plugin-postcss";\n\nexport default defineConfig({\n plugins: [\n farmPostcssPlugin({\n // ... \u914d\u7f6e postcss \u9009\u9879\n })\n ],\n});\n'})}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"farmPostcssPlugin()"}),"\u8fd4\u56de\u4e00\u4e2a\u63d2\u4ef6\u5bf9\u8c61\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u5176\u53c2\u6570\u4f20\u9012\u4efb\u4f55 postcss \u9009\u9879\u3002"]}),"\n",(0,i.jsxs)(e.p,{children:["\u60a8\u53ef\u4ee5\u4f7f\u7528",(0,i.jsx)(e.code,{children:"priority"}),"\u6765\u63a7\u5236\u63d2\u4ef6\u7684\u987a\u5e8f\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts" {10,11}',children:'import farmPostcssPlugin from "@farmfe/js-plugin-postcss";\n\nexport default defineConfig({\n plugins: [\n {\n ...farmPostcssPlugin({\n // ... configure postcss options\n }),\n // larger priority will be executed first, priority of internal plugin are 100.\n priority: 1000,\n }\n ],\n});\n'})}),"\n",(0,i.jsx)(e.p,{children:"\u5185\u90e8\u63d2\u4ef6\u7684\u4f18\u5148\u7ea7\u90fd\u662f100\uff0c\u5982\u679c\u60f3\u8ba9\u63d2\u4ef6\u5148\u6267\u884c\uff0c\u5c31\u8bbe\u7f6e\u5927\u4e8e100\uff0c\u5426\u5219\u8bbe\u7f6e\u5c0f\u4e8e100\u3002"}),"\n",(0,i.jsx)(e.p,{children:"\u5982\u679c\u4f60\u60f3\u5feb\u901f\u6dfb\u52a0 Farm JS \u63d2\u4ef6\uff0c\u53ea\u9700\u914d\u7f6e\u4e00\u4e2a\u63d2\u4ef6\u5bf9\u8c61\u5373\u53ef\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import readFileSync from 'fs';\n\nexport default defineConfig({\n plugins: [\n // \u914d\u7f6e\u81ea\u5b9a\u4e49\u63d2\u4ef6\n {\n // \u63d2\u4ef6\u540d\u79f0\uff0c\u5fc5\u586b\n name: 'my-first-farm-plugin',\n // \u8fd9\u4e2a\u63d2\u4ef6\u7684\u4f18\u5148\u7ea7\uff0c\u503c\u8d8a\u5927\u5148\u6267\u884c\uff0c\u9ed8\u8ba4100\u3002\n priority: 1000,\n // \u5b9a\u4e49\u4e00\u4e2a\u52a0\u8f7d\u94a9\u5b50\u6765\u786e\u5b9a\u5982\u4f55\u52a0\u8f7d\u6a21\u5757\n load: {\n // \u4e3a\u4e86\u63d0\u9ad8\u6027\u80fd\uff0c\u5982\u679c\u6a21\u5757\u4e0e\u8fc7\u6ee4\u5668\u4e0d\u5339\u914d\uff0c\u5c06\u88ab\u8df3\u8fc7\u3002\n filters: {\n // \u4ec5\u5bf9 .png \u6587\u4ef6\u6267\u884c\u3002\n resolvedPaths: ['\\\\.txt$']\n },\n // \u8be5\u94a9\u5b50\u7684\u6267\u884c\u56de\u8c03\n executor: (params, context) => {\n const { resolvedPath } = params;\n const content = readFileSync(resolvedPath, 'utf-8');\n\n return {\n content: `export default '${content}'`,\n moduleType: 'js'\n }\n }\n }\n }\n ],\n});\n"})}),"\n",(0,i.jsx)(e.admonition,{type:"warning",children:(0,i.jsxs)(e.p,{children:["Farm \u4e2d\u7684 js \u63d2\u4ef6\u9700\u8981 ",(0,i.jsx)(e.code,{children:"filters"}),"\u3002 \u56e0\u4e3aJs Plugin\u5b9e\u5728\u662f\u592a\u6162\u4e86\uff0c\u6211\u4eec\u5e94\u8be5\u5c3d\u91cf\u907f\u514d\u6267\u884c\u5b83\u3002\u914d\u7f6e filters \u540e\uff0c\u5bf9\u4e8e\u90a3\u4e9b\u4e0d\u7b26\u5408\u8fc7\u6ee4\u5668\u7684\u6a21\u5757\uff0cFarm \u6839\u672c\u4e0d\u4f1a\u4e3a\u5b83\u4eec\u89e6\u53d1 js \u63d2\u4ef6\u94a9\u5b50\uff01 \u8fd9\u610f\u5473\u7740 Farm \u53ea\u5728 Rust \u4fa7\u5c31\u80fd\u5b89\u5168\u3001\u5e76\u53d1\u5730\u8fdb\u884c\u5904\u7406\uff0c\u4ee5\u6700\u5927\u5316\u63d0\u5347\u7f16\u8bd1\u6027\u80fd\u3002"]})}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u4e86\u89e3\u66f4\u591a\u5173\u4e8e Farm Js \u63d2\u4ef6\u7684\u4fe1\u606f\uff0c\u8bf7\u53c2\u8003 ",(0,i.jsx)(e.a,{href:"/docs/plugins/official-plugins/overview#js-%E6%8F%92%E4%BB%B6",children:"JS \u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h2,{id:"\u4f7f\u7528-viterollupunplugin-\u63d2\u4ef6",children:"\u4f7f\u7528 Vite/Rollup/Unplugin \u63d2\u4ef6"}),"\n",(0,i.jsx)(e.p,{children:"Farm \u517c\u5bb9 Vite \u63d2\u4ef6\uff0cVite \u63d2\u4ef6\u53ef\u4ee5\u76f4\u63a5\u5728 Farm \u4e2d\u914d\u7f6e\u4f7f\u7528\u3002 \u9996\u5148\u9700\u8981\u5b89\u88c5 vite \u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u7136\u540e\u5c31\u53ef\u4ee5\u901a\u8fc7",(0,i.jsx)(e.code,{children:"farm.config.ts"}),"\u4e2d\u7684",(0,i.jsx)(e.code,{children:"vitePlugins"}),"\u76f4\u63a5\u4f7f\u7528vite\u63d2\u4ef6\u4e86\u3002"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import vue from '@vitejs/plugin-vue',\nimport vueJsx from '@vitejs/plugin-vue-jsx';\n\nexport default defineConfig({\n // \u914d\u7f6evite\u63d2\u4ef6\n vitePlugins: [\n vue(),\n vueJsx()\n ]\n});\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u4e3a\u4e86\u63d0\u9ad8 vite \u63d2\u4ef6\u7684\u6027\u80fd\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd4\u56de",(0,i.jsx)(e.code,{children:"\u8fc7\u6ee4\u5668"}),"\u7684",(0,i.jsx)(e.code,{children:"\u51fd\u6570\u8bed\u6cd5"}),"\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import vue from '@vitejs/plugin-vue',\n\n// // \u4f7f\u7528Farm \u4e2d Vite \u63d2\u4ef6\u7684\u51fd\u6570\u8bed\u6cd5\nfunction configureVitePluginVue() {\n // \u8fd4\u56de\u63d2\u4ef6\u53ca\u5176\u8fc7\u6ee4\u5668\n return {\n // \u4f7f\u7528 vue \u63d2\u4ef6\n vitePlugin: vue(),\n // \u4e3a\u5176\u914d\u7f6e\u8fc7\u6ee4\u5668\u3002 \u4e0d\u5339\u914d\u7684\u6a21\u5757\u8def\u5f84\u5c06\u88ab\u8df3\u8fc7\u3002\n filters: ['\\\\.vue$', '\\\\\\\\0.+']\n };\n}\n\nexport default defineConfig({\n vitePlugins: [\n configureVitePluginVue\n ]\n});\n"})}),"\n",(0,i.jsx)(e.p,{children:"\u4f7f\u7528 unplugin\uff1a"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"pnpm add unplugin-auto-import unplugin-vue-components -D\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u5728 ",(0,i.jsx)(e.code,{children:"vitePlugins"})," \u4e2d\u914d\u7f6e\uff0c\u901a\u8fc7 ",(0,i.jsx)(e.code,{children:"unplugin/vite"})," \u6216\u8005 ",(0,i.jsx)(e.code,{children:"unplugin/rollup"})," \u652f\u6301:"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:"import vue from '@vitejs/plugin-vue',\nimport AutoImport from 'unplugin-auto-import/vite'\nimport Components from 'unplugin-vue-components/vite'\nimport { ElementPlusResolver } from 'unplugin-vue-components/resolvers'\n\nexport default defineConfig({\n vitePlugins: [\n vue(),\n // ...\n AutoImport({\n resolvers: [ElementPlusResolver({ importStyle: 'sass' })],\n }),\n Components({\n resolvers: [ElementPlusResolver({ importStyle: 'sass' })],\n }),\n ]\n});\n"})}),"\n",(0,i.jsx)(e.admonition,{type:"note",children:(0,i.jsxs)(e.p,{children:["\u76ee\u524d\uff0c\u60a8\u53ef\u4ee5\u5728 Farm \u4e2d\u4f7f\u7528",(0,i.jsx)(e.code,{children:"unplugin/farm"}),"\u3001",(0,i.jsx)(e.code,{children:"unplugin/vite"}),"\u548c",(0,i.jsx)(e.code,{children:"unplugin/rollup"}),"\u3002\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f",(0,i.jsx)(e.code,{children:"unplugin/vite"}),"\u6216",(0,i.jsx)(e.code,{children:"unplugin/Rolup"}),"\uff0c\u6709\u4e9b\u5c5e\u6027\u53ef\u80fd\u8fd8\u6ca1\u6709\u5b8c\u5168\u9002\u914d\uff0c\u6216\u8005 Farm \u56e2\u961f\u8ba4\u4e3a\u8be5 ",(0,i.jsx)(e.code,{children:"api"})," \u4e0d\u5177\u5907\u9002\u914d\u6761\u4ef6\uff0c\u53ef\u4ee5\u63d0\u4f9b",(0,i.jsx)(e.a,{href:"https://github.com/farm-fe/farm/issues/new/choose",children:"issues"})," ."]})}),"\n",(0,i.jsx)(e.h2,{id:"farm-\u8fd0\u884c\u65f6\u63d2\u4ef6",children:"Farm \u8fd0\u884c\u65f6\u63d2\u4ef6"}),"\n",(0,i.jsxs)(e.p,{children:["Farm\u6709\u4e00\u4e2a\u8fd0\u884c\u65f6\u6a21\u5757\u7cfb\u7edf\u6765\u63a7\u5236\u5982\u4f55\u52a0\u8f7d\u548c\u6267\u884c\u6a21\u5757\u3002 \u914d\u7f6e ",(0,i.jsx)(e.code,{children:"compilation.runtime.plugins"})," \u4ee5\u6dfb\u52a0\u66f4\u591a\u8fd0\u884c\u65f6\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"export default defineConfig({\n compilation: {\n // \u914d\u7f6e Farm \u8fd0\u884c\u65f6\u6a21\u5757\u7cfb\u7edf\n runtime: {\n plugins: [\n // \u8fd0\u884c\u65f6\u63d2\u4ef6\u5305\n require.resolve('farm-plugin-runtime-mock'),\n // \u672c\u5730\u8fd0\u884c\u65f6\u63d2\u4ef6\n path.join(process.cwd(), \"build/runtime-plugin.ts\")\n ]\n }\n }\n});\n"})}),"\n",(0,i.jsxs)(e.p,{children:["\u60a8\u5fc5\u987b\u914d\u7f6e\u6307\u5411\u8fd0\u884c\u65f6\u63d2\u4ef6\u7684\u8def\u5f84\u3002 \u63a8\u8350\u4f7f\u7528 ",(0,i.jsx)(e.strong,{children:"\u7edd\u5bf9\u8def\u5f84"})," \u4ee5\u907f\u514d\u8def\u5f84\u95ee\u9898\u3002"]}),"\n",(0,i.jsx)(e.admonition,{type:"tip",children:(0,i.jsxs)(e.p,{children:["\u8981\u4e86\u89e3\u6709\u5173\u8fd0\u884c\u65f6\u63d2\u4ef6\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 ",(0,i.jsx)(e.a,{href:"/docs/plugins/writing-plugins/runtime-plugin",children:"\u8fd0\u884c\u65f6\u63d2\u4ef6"})]})}),"\n",(0,i.jsx)(e.h2,{id:"\u4f7f\u7528-swc-\u63d2\u4ef6",children:"\u4f7f\u7528 SWC \u63d2\u4ef6"}),"\n",(0,i.jsxs)(e.p,{children:["Swc Plugin \u4e5f\u53ef\u4ee5\u76f4\u63a5\u5728Farm\u4e2d\u4f7f\u7528\uff0c\u914d\u7f6e",(0,i.jsx)(e.code,{children:"compilation.script.plugins"}),"\u6765\u6dfb\u52a0SWC\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1a"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"import jsPluginVue from '@farmfe/js-plugin-vue';\n\nexport default defineConfig({\n compilation: {\n script: {\n plugins: [{\n //swc\u63d2\u4ef6\u7684\u5305\u540d\n name: 'swc-plugin-vue-jsx',\n // \u8be5swc\u63d2\u4ef6\u7684\u9009\u9879\n options: {\n \"transformOn\": true,\n \"optimize\": true\n },\n // \u5f53\u8fc7\u6ee4\u5668\u5339\u914d\u65f6\u63d2\u4ef6\u6267\u884c\u3002\n filters: {\n // resolvedPaths: [\".+\"]\n moduleTypes: ['tsx', 'jsx'],\n }\n }]\n }\n },\n plugins: [jsPluginVue()],\n});\n"})}),"\n",(0,i.jsx)(e.p,{children:"\u6570\u7ec4\u7684\u6bcf\u4e2a\u63d2\u4ef6\u9879\u5305\u542b\u4e09\u4e2a\u5b57\u6bb5\uff1a"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:"name"}),"\uff1aswc\u63d2\u4ef6\u7684\u5305\u540d"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:"options"}),"\uff1a\u4f20\u9012\u7ed9swc\u63d2\u4ef6\u7684\u914d\u7f6e\u9879"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.strong,{children:"filters"}),"\uff1a\u6267\u884c\u63d2\u4ef6\u7684\u54ea\u4e9b\u6a21\u5757\uff0c\u5fc5\u987b\u914d\u7f6e\uff0c\u652f\u6301",(0,i.jsx)(e.code,{children:"resolvedPaths"}),"\u548c",(0,i.jsx)(e.code,{children:"moduleTypes"}),"\u8fd9\u4e24\u4e2a\u8fc7\u6ee4\u9879\uff0c\u5982\u679c\u4e24\u8005\u540c\u65f6\u6307\u5b9a\uff0c\u5219\u53d6\u5e76\u96c6\u3002"]}),"\n"]}),"\n",(0,i.jsx)(e.admonition,{type:"note",children:(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.code,{children:"SWC \u63d2\u4ef6"}),"\u53ef\u80fd\u4e0e Farm \u4f7f\u7528\u7684 ",(0,i.jsx)(e.code,{children:"SWC \u7248\u672c"}),"(rust crate ",(0,i.jsx)(e.code,{children:"swc_core v0.90"}),") \u4e0d\u517c\u5bb9\u3002 \u5982\u679c\u51fa\u73b0\u9519\u8bef\uff0c\u8bf7\u5c1d\u8bd5\u5347\u7ea7\u63d2\u4ef6\u3002"]})})]})}function a(n={}){const{wrapper:e}={...(0,r.R)(),...n.components};return e?(0,i.jsx)(e,{...n,children:(0,i.jsx)(u,{...n})}):u(n)}},5710:(n,e,s)=>{s.d(e,{R:()=>t,x:()=>c});var i=s(758);const r={},l=i.createContext(r);function t(n){const e=i.useContext(l);return i.useMemo((function(){return"function"==typeof n?n(e):{...e,...n}}),[e,n])}function c(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(r):n.components||r:t(n.components),i.createElement(l.Provider,{value:e},n.children)}}}]); \ No newline at end of file diff --git a/zh/assets/js/0c4d97a0.9591ef90.js b/zh/assets/js/0c4d97a0.a5277837.js similarity index 99% rename from zh/assets/js/0c4d97a0.9591ef90.js rename to zh/assets/js/0c4d97a0.a5277837.js index 8b4fd7b34..971f5fa4c 100644 --- a/zh/assets/js/0c4d97a0.9591ef90.js +++ b/zh/assets/js/0c4d97a0.a5277837.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfarm_docs=self.webpackChunkfarm_docs||[]).push([[6083],{4707:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>h,frontMatter:()=>r,metadata:()=>d,toc:()=>o});var i=t(6070),s=t(5710);const r={sidebar_position:1},c="Html",d={id:"features/html",title:"Html",description:"\u57fa\u672c\u7528\u6cd5",source:"@site/i18n/zh/docusaurus-plugin-content-docs/current/features/html.md",sourceDirName:"features",slug:"/features/html",permalink:"/zh/docs/features/html",draft:!1,unlisted:!1,editUrl:"https://github.com/farm-fe/farm-fe.github.io/tree/main/docs/features/html.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"DevServer \u548c HMR",permalink:"/zh/docs/features/dev-server"},next:{title:"Css/Sass/Less",permalink:"/zh/docs/features/css"}},l={},o=[{value:"\u57fa\u672c\u7528\u6cd5",id:"\u57fa\u672c\u7528\u6cd5",level:2},{value:"\u591a\u9875\u9762\u5e94\u7528\u7a0b\u5e8f - MPA",id:"\u591a\u9875\u9762\u5e94\u7528\u7a0b\u5e8f---mpa",level:2},{value:"\u7ee7\u627f html \u6a21\u677f",id:"\u7ee7\u627f-html-\u6a21\u677f",level:2}];function a(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"html",children:"Html"}),"\n",(0,i.jsx)(n.h2,{id:"\u57fa\u672c\u7528\u6cd5",children:"\u57fa\u672c\u7528\u6cd5"}),"\n",(0,i.jsx)(n.p,{children:"Farm \u652f\u6301\u5f00\u7bb1\u5373\u7528\u5730\u7f16\u8bd1 Html\uff0c\u5e76\u4e14\u5728\u6784\u5efa Web \u9879\u76ee\u65f6\u5e94\u8be5\u4f7f\u7528 Html \u4f5c\u4e3a\u5165\u53e3\uff0c\u4f8b\u5982\uff1a"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",metastring:'title="farm.config.ts"',children:'import type { UserConfig } from "@farmfe/core";\n\nexport default defineConfig({\n input: {\n index: "./index.html", // using ./index.html as entry\n },\n});\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["\u5982\u679c\u672a\u6307\u5b9a ",(0,i.jsx)(n.code,{children:"input"}),"\uff0c\u5219\u9ed8\u8ba4\u4e3a ",(0,i.jsx)(n.code,{children:"{index: './index.html'}"}),"\u3002"]})}),"\n",(0,i.jsxs)(n.p,{children:["\u5728",(0,i.jsx)(n.code,{children:"./index.html"}),"\u4e2d\uff0c\u5e94\u8be5\u4f7f\u7528",(0,i.jsx)(n.code,{children:' - + + + - + \ No newline at end of file diff --git a/zh/blog/atom.xml b/zh/blog/atom.xml index 90af2dd57..ff90cb982 100644 --- a/zh/blog/atom.xml +++ b/zh/blog/atom.xml @@ -2,7 +2,7 @@ https://farmfe.org/zh/blog Farm Blog - 2024-07-23T01:07:06.000Z + 2024-07-29T06:04:31.000Z https://github.com/jpmonette/feed Farm Blog @@ -11,8 +11,8 @@ <![CDATA[Blob]]> https://farmfe.org/zh/blog/index - 2024-07-23T01:07:06.000Z + 2024-07-29T06:04:31.000Z - 2024]]> + 2024]]> \ No newline at end of file diff --git a/zh/blog/index.html b/zh/blog/index.html index 9928c87e5..354417036 100644 --- a/zh/blog/index.html +++ b/zh/blog/index.html @@ -3,16 +3,16 @@ -Blog | Farm +Blog | Farm - - - + + + -

    Blob

    · 阅读需 1 分钟

    2024

    +

    Blob

    · 阅读需 1 分钟

    2024

    \ No newline at end of file diff --git a/zh/blog/index/index.html b/zh/blog/index/index.html index 5ee2a4013..8f6a10920 100644 --- a/zh/blog/index/index.html +++ b/zh/blog/index/index.html @@ -3,16 +3,16 @@ -Blob | Farm +Blob | Farm - - - + + + -

    Blob

    · 阅读需 1 分钟

    2024

    +

    Blob

    · 阅读需 1 分钟

    2024

    \ No newline at end of file diff --git a/zh/blog/rss.xml b/zh/blog/rss.xml index 349c29a71..80807ee7b 100644 --- a/zh/blog/rss.xml +++ b/zh/blog/rss.xml @@ -4,7 +4,7 @@ Farm Blog https://farmfe.org/zh/blog Farm Blog - Tue, 23 Jul 2024 01:07:06 GMT + Mon, 29 Jul 2024 06:04:31 GMT https://validator.w3.org/feed/docs/rss2.html https://github.com/jpmonette/feed zh @@ -12,9 +12,9 @@ <![CDATA[Blob]]> https://farmfe.org/zh/blog/index https://farmfe.org/zh/blog/index - Tue, 23 Jul 2024 01:07:06 GMT + Mon, 29 Jul 2024 06:04:31 GMT - 2024]]> + 2024]]> \ No newline at end of file diff --git a/zh/data/index.html b/zh/data/index.html index 9a8b5b23e..5c4f9a04e 100644 --- a/zh/data/index.html +++ b/zh/data/index.html @@ -8,9 +8,9 @@ - - - + + +
    diff --git a/zh/docs/0.x/api/hmr-api/index.html b/zh/docs/0.x/api/hmr-api/index.html index 45244e9e1..bc60e29b2 100644 --- a/zh/docs/0.x/api/hmr-api/index.html +++ b/zh/docs/0.x/api/hmr-api/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/docs/0.x/api/javascript-api/index.html b/zh/docs/0.x/api/javascript-api/index.html index 29fd74d9c..719184c1b 100644 --- a/zh/docs/0.x/api/javascript-api/index.html +++ b/zh/docs/0.x/api/javascript-api/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/docs/0.x/api/js-plugin-api/index.html b/zh/docs/0.x/api/js-plugin-api/index.html index 6c549e76f..019f61fce 100644 --- a/zh/docs/0.x/api/js-plugin-api/index.html +++ b/zh/docs/0.x/api/js-plugin-api/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/docs/0.x/api/rust-api/index.html b/zh/docs/0.x/api/rust-api/index.html index 3bacbdf5b..234373a31 100644 --- a/zh/docs/0.x/api/rust-api/index.html +++ b/zh/docs/0.x/api/rust-api/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/docs/0.x/api/rust-plugin-api/index.html b/zh/docs/0.x/api/rust-plugin-api/index.html index 13660175b..26c64c0a5 100644 --- a/zh/docs/0.x/api/rust-plugin-api/index.html +++ b/zh/docs/0.x/api/rust-plugin-api/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/docs/0.x/benchmark/index.html b/zh/docs/0.x/benchmark/index.html index 86fddd8de..036e3b285 100644 --- a/zh/docs/0.x/benchmark/index.html +++ b/zh/docs/0.x/benchmark/index.html @@ -8,18 +8,18 @@ - - - + + + -
    版本:0.15

    Benchmarks

    +
    +

    xx

    +
    StartupHMR (Root)HMR (Leaf)
    Webpack7694ms334ms267ms
    Vite4625ms32ms27ms
    Turbopack2444ms9ms11ms
    Rspack406ms311ms301ms
    Farm395ms7ms12ms
    \ No newline at end of file diff --git a/zh/docs/0.x/cli/cli-api/index.html b/zh/docs/0.x/cli/cli-api/index.html index 5b94cc8c1..538b71096 100644 --- a/zh/docs/0.x/cli/cli-api/index.html +++ b/zh/docs/0.x/cli/cli-api/index.html @@ -8,31 +8,31 @@ - - - + + + -
    版本:0.15

    Farm CLI

    +
    版本:0.15

    Farm CLI

    Farm Cli 允许您启动、构建、预览和监听您的应用程序。

    如果需要查看 Farm Cli 的可用命令, 您可以在终端中执行以下命令

    -
    Terminal
    npx farm -h
    +
    Terminal
    npx farm -h

    The output look like this:

    -
    Terminal
    farm/0.5.11

    Usage:
    $ farm [root]

    Commands:
    [root]
    start 启动开发服务器
    build 在生产环境下构建项目
    watch 监听文件变化并且重新构建
    preview 在本地可以直接预览您的生产环境构建出的产物
    clean [path] 清理`farm`增量构建的缓存文件
    plugin [command] 管理插件的命令

    For more info, run any command with the `--help` flag:
    $ farm --help
    $ farm build --help
    $ farm watch --help
    $ farm preview --help
    $ farm clean --help
    $ farm plugin --help

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -v, --version 查看当前版本
    -

    Start

    +
    Terminal
    farm/0.5.11

    Usage:
    $ farm [root]

    Commands:
    [root]
    start 启动开发服务器
    build 在生产环境下构建项目
    watch 监听文件变化并且重新构建
    preview 在本地可以直接预览您的生产环境构建出的产物
    clean [path] 清理`farm`增量构建的缓存文件
    plugin [command] 管理插件的命令

    For more info, run any command with the `--help` flag:
    $ farm --help
    $ farm build --help
    $ farm watch --help
    $ farm preview --help
    $ farm clean --help
    $ farm plugin --help

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -v, --version 查看当前版本
    +

    Start

    farm start 命令用于启动开发服务器, 将代码进行开发环境的编译

    -
    Terminal
    Usage:
    $ farm [root]

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -

    Build

    +
    Terminal
    Usage:
    $ farm [root]

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    +

    Build

    farm build 命令会在默认的 dist 目录下构建出可用于生产环境的产物。

    -
    Terminal
    Usage:
    $ farm build

    Options:
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -w, --watch 是否监听文件并且重新构建
    --targetEnv <target> 构建环境 node, browser
    --format <format> 构建产物格式 esm, commonjs
    --sourcemap 是否输出 sourcemap
    --treeShaking 消除无用代码而不会产生副作用
    --minify 构建时的代码压缩
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -

    Preview

    +
    Terminal
    Usage:
    $ farm build

    Options:
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -w, --watch 是否监听文件并且重新构建
    --targetEnv <target> 构建环境 node, browser
    --format <format> 构建产物格式 esm, commonjs
    --sourcemap 是否输出 sourcemap
    --treeShaking 消除无用代码而不会产生副作用
    --minify 构建时的代码压缩
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    +

    Preview

    farm preview 用于在本地可以直接预览您的生产环境构建出的产物, 您需要提前执行 farm build 来构建出生产环境的产物

    -
    Terminal
    Usage:
    $ farm preview

    Options:
    --open [url] 启动时是否在浏览器中打开页面
    --port <port> 设置 Server 监听的端口号
    --host <host> 指定 Server 启动时监听的 host
    -c --config <config> 指定配置文件路径
    -h, --help 显示命令帮助
    -

    Watch

    +
    Terminal
    Usage:
    $ farm preview

    Options:
    --open [url] 启动时是否在浏览器中打开页面
    --port <port> 设置 Server 监听的端口号
    --host <host> 指定 Server 启动时监听的 host
    -c --config <config> 指定配置文件路径
    -h, --help 显示命令帮助
    +

    Watch

    farm watch 一般作用于 node 环境下监听文件变化并且重新构建

    -
    Terminal

    Usage:
    $ farm watch

    Options:
    --format <format> 构建产物格式 esm, commonjs
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -

    Clean

    +
    Terminal

    Usage:
    $ farm watch

    Options:
    --format <format> 构建产物格式 esm, commonjs
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    +

    Clean

    farm clean 由于 farm 提供的增量构建会在本地生成缓存文件, 如果在特定情况下(不可预知的编译错误)可能您需要清理缓存文件

    -
    Terminal
    Usage:
    $ farm clean [path]

    Options:
    --recursive 递归搜索 `node_modules` 目录并清除缓存文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    +
    Terminal
    Usage:
    $ farm clean [path]

    Options:
    --recursive 递归搜索 `node_modules` 目录并清除缓存文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    \ No newline at end of file diff --git a/zh/docs/0.x/concepts/index.html b/zh/docs/0.x/concepts/index.html index 620c15488..17613bb9a 100644 --- a/zh/docs/0.x/concepts/index.html +++ b/zh/docs/0.x/concepts/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    Concepts

    +
    版本:0.15

    Concepts

    Farm is a build tool to transform and bundle your input to deployable resources. Farm will search modules start from the input, then construct a module graph and bundle these modules into several resources

    Main Concepts:

      @@ -21,6 +21,6 @@
    • Output
    • Plugins
    • Partial Bundling
    • -
    +
    \ No newline at end of file diff --git a/zh/docs/0.x/config/cli/index.html b/zh/docs/0.x/config/cli/index.html index fd196d5c2..d1b52d938 100644 --- a/zh/docs/0.x/config/cli/index.html +++ b/zh/docs/0.x/config/cli/index.html @@ -8,27 +8,27 @@ - - - + + + -
    版本:0.15

    CLI 选项

    -

    create

    +
    版本:0.15

    CLI 选项

    +

    create

    创建一个新的农场项目。

    -
    pnpm create farm
    # 或 npm create farm
    # 或 yarn create farm
    # choose your favorite package manager
    +
    pnpm create farm
    # 或 npm create farm
    # 或 yarn create farm
    # choose your favorite package manager

    其他命令由包 @farmfe/cli 提供:

    -

    start

    +

    start

    启动开发服务器,在开发模式下编译 Farm 项目并监视文件更改。

    -
    farm start
    -

    build

    +
    farm start
    +

    build

    以生产模式构建 Farm 项目

    -
    farm build
    -

    preview

    +
    farm build
    +

    preview

    预览“build”命令的结果。

    -
    farm build && farm preview
    -

    watch

    +
    farm build && farm preview
    +

    watch

    Watch 通常用于编译库项目,它的工作方式类似于 start 命令,但它不会启动开发服务器。

    -
    farm watch
    +
    farm watch
    \ No newline at end of file diff --git a/zh/docs/0.x/config/compilation-options/index.html b/zh/docs/0.x/config/compilation-options/index.html index 13bfb000a..951953797 100644 --- a/zh/docs/0.x/config/compilation-options/index.html +++ b/zh/docs/0.x/config/compilation-options/index.html @@ -8,29 +8,29 @@ - - - + + + -
    版本:0.15

    配置参考

    +
    版本:0.15

    配置参考

    Farm 默认从项目根目录的 farm.config.ts|js|mjs 文件中读取配置,配置文件示例:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // 编译的根目录
    // 编译选项
    compilation: {
    // ...
    },
    // Dev Server 选项
    server: {
    hmr: true,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    -

    编译选项 - compilation

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // 编译的根目录
    // 编译选项
    compilation: {
    // ...
    },
    // Dev Server 选项
    server: {
    hmr: true,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    +

    编译选项 - compilation

    所有与编译相关的配置都在 compilation 字段下。

    -

    input

    +

    input

    • type: Record<string, string>

    项目的入口点。 Input 的文件可以是htmlts/js/tsx/jsxcss 或通过插件支持的其他文件。

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    -

    output

    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    +

    output

    • type: OutputOptions
    -
    interface OutputOptions {
    // 局部打包后,入口文件所在资源的文件名配置
    entryFilename?: string;
    // 局部打包后,除入口资源外的其他资源输入文件名配置
    filename?: string;
    // 输入目录
    path?: string;
    // public path:资源加载前缀
    publicPath?: string;
    // 静态资源文件名配置
    assetsFilename?: string;
    // 目标执行环境,浏览器或者 Node
    targetEnv?: "browser" | "node";
    // 输出模块格式
    format?: "cjs" | "esm";
    }
    -
    备注

    我们称编译结果为 资源(resource)

    -

    output.entryFilename

    +
    interface OutputOptions {
    // 局部打包后,入口文件所在资源的文件名配置
    entryFilename?: string;
    // 局部打包后,除入口资源外的其他资源输入文件名配置
    filename?: string;
    // 输入目录
    path?: string;
    // public path:资源加载前缀
    publicPath?: string;
    // 静态资源文件名配置
    assetsFilename?: string;
    // 目标执行环境,浏览器或者 Node
    targetEnv?: "browser" | "node";
    // 输出模块格式
    format?: "cjs" | "esm";
    }
    +
    备注

    我们称编译结果为 资源(resource)

    +

    output.entryFilename

    • 默认值: "[entryName].[ext]"
    @@ -41,7 +41,7 @@

    ou
  • [contentHash]:该资源的内容哈希。
  • [ext]:该资源的扩展名,对于 js/jsx/ts/tsxjs,对于 css/scss/lesscss
  • -

    output.filename

    +

    output.filename

    • 默认值: "[resourceName].[ext]"
    @@ -51,136 +51,136 @@

    output.
  • [contentHash]:该资源的内容哈希。
  • [ext]:该资源的扩展名,对于 js/jsx/ts/tsxjs,对于 css/scss/lesscss
  • -

    output.path

    +

    output.path

    • 默认值: "dist"

    输出资源的目录

    -

    output.publicPath

    +

    output.publicPath

    • 默认值: "/"

    资源 url 加载的前缀. 比如 URL https://xxxx,或者一个路径 /xxx.

    -

    output.assetsFileName

    +

    output.assetsFileName

    • 默认值: "[resourceName].[ext]"

    静态资源输出的文件名配置,占位符和 output.filename 相同。

    -

    output.targetEnv

    +

    output.targetEnv

    • 默认值: "browser"

    配置产物的执行环境,可以是 "browser" 或者 "node".

    -

    output.format

    +

    output.format

    • 默认值: "esm"

    配置产物的格式,可以是 "esm" 或者 "cjs".

    -
    备注

    该选项只对 Js 产物有效

    -

    resolve

    +
    备注

    该选项只对 Js 产物有效

    +

    resolve

    • type: ResolveOptions
    -
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    -

    resolve.extensions

    +
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    +

    resolve.extensions

    • 默认值: ["tsx", "ts", "jsx", "js", "mjs", "json", "html", "css"]

    配置解析依赖时的后缀,例如解析 ./index 时,如果没有解析到,则会自动加上后缀解析,如尝试 ./index.tsx, ./index.css 等。

    -

    resolve.alias

    +

    resolve.alias

    • 默认值: {}

    配置解析别名,示例:

    -
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });
    +
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });

    alias 为前缀替换,对于上述例子 /@/pages 将会被替换为,/root/src/pages

    如果希望精确匹配,可以加上 $,例如 stream$ 只会替换 stream,而不会替换 stream/xxx

    当然也支持使用正则表达式,例如 $__farm_regex:^/(utils)$,将会匹配 /utils,并替换为 /root/src/utils

    -

    resolve.mainFields

    +

    resolve.mainFields

    • 默认值: ["exports", "browser", "module", "main"]

    解析 node_modules 下依赖时,从 package.json 中将会按照 mainFields 中配置的字段和顺序进行解析。对于 package.json

    -
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }
    +
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }

    将会优先使用 es/index.js(如果路径存在),不存在则会继续向后搜索。

    -

    resolve.conditions

    +

    resolve.conditions

    暂不支持配置。

    - +
    • 默认值: true

    解析文件时,是否追踪 symlink 对应的真实目录,并从真实目录开始解析下一个依赖。如果使用 pnpm 管理依赖,该选项必须配置为 true。

    -

    resolve.strictExports

    +

    resolve.strictExports

    • 默认值: false

    是否严格遵循 package.jsonexports 中定义的导出。如果设置为 true,当 package.json 中定义了 exports,但是 exports 没有定义对应导出时,会直接报错。如果设置为 true,会按照 mainFields 继续尝试其他入口。

    -

    define

    +

    define

    • 默认值: {}

    全局变量注入,配置的变量名和值将会在编译时注入到产物中。Farm 默认注入 process.env.NODE_ENV 以及部分 Farm 自身使用的变量比如 FARM_HMR_PORT

    -
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123,
    },
    },
    });
    -
    备注
      +
      export default defineConfig({
      compilation: {
      define: {
      MY_VAR: 123,
      },
      },
      });
      +
      备注
      1. define 为了强化性能,使用的是全局变量的注入形式,这意味着,对象形式的变量无法注入,例如 process.env.XXX 形式的变量无法注入,只能配置 XXX 形式的变量。
      2. 如果在同一个 window 下挂载多个 Farm 项目,多个项目同名的 define 会相互覆盖。
      3. 注入的是字符串,如果需要转为其他类型,需要在运行时代码中手动转换,例如 Number(MY_VAR)
      -

      external

      +

      external

      • 默认值: []

      配置被 external 的导入,被 external 的导入不会出现在编译产物中。但是对应 import 语句不会删除,需要自定义 external 后如何处理,否则运行时会报错,对于 targetEnv 是 node 下的 external 模块,会自动尝试 require 该模块。

      需要使用正则方式配置,例如:

      -
      export default defineConfig({
      compilation: {
      external: ["^stream$"],
      },
      });
      -

      mode

      +
      export default defineConfig({
      compilation: {
      external: ["^stream$"],
      },
      });
      +

      mode

      • 默认值: 对于 start、watch 命令是 development,对于 build 命令是 production

      配置编译模式,为了优化开发时性能,在没有手动配置生产优化相关选项(minify,tree shake 等)时,默认在 development 下会禁用生产环境优化比如压缩和 tree shake,在 production 模式下启用。

      -

      root

      +

      root

      • 默认值: process.cwd()

      配置项目编译的 root 目录,该选项会影响默认配置文件的查找路径,编译模块依赖的查找等。

      -

      runtime

      +

      runtime

      配置 Farm 运行时能力。类型如下:

      -
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      -

      runtime.path

      +
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      +

      runtime.path

      • 默认值: Farm 内置 runtime 的路径

      自定义一个 Runtime 替换 Farm 内置的 Runtime。

      -
      注意

      正常情况下不建议配置该选项,因为一旦配置了该选项,指向的 runtime 需要所有实现 Farm Runtime 已有的能力,例如模块系统、HMR、动态资源加载等。

      -

      runtime.plugins

      +
      注意

      正常情况下不建议配置该选项,因为一旦配置了该选项,指向的 runtime 需要所有实现 Farm Runtime 已有的能力,例如模块系统、HMR、动态资源加载等。

      +

      runtime.plugins

      • 默认值: Farm 内置 runtime-plugin-hmr 的路径

      配置 Runtime 插件,通过 Runtime 插件,可以干预 Runtime 行为,如模块加载,资源加载等。具体可以参考:WIP。

      -

      runtime.namespace

      +

      runtime.namespace

      • 默认值: 项目 package.json 的 name 字段

      配置 Farm Runtime 的命名空间,保证在同一个 window 或者 global 下不同产物的执行能够相互隔离。默认使用项目 package.json 的 name 字段作为 namespace。

      -

      assets

      -

      assets.include

      +

      assets

      +

      assets.include

      • 默认值: []

      额外视为静态资源的文件后缀,例如下述示例,txt 将会被视为姿态资源,引入 txt 文件时当作静态资源处理:

      -
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"],
      },
      },
      });
      -

      script

      -

      script.target

      +
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"],
      },
      },
      });
      +

      script

      +

      script.target

      • 默认值: esnext(根据 Farm 的迭代动态调整)

      配置 Farm 解析 js/jsx/ts/tsx 的 AST 以及生成代码时支持的 ES 语法版本。 可选值:es5, es6, es2015 - es2023, esnext

      -

      script.parser

      +

      script.parser

      • 默认值: 与 SWC 相同

      配置 SWC 解析 AST 时的行为,配置项参考:https://swc.rs/docs/configuration/compilation#jscparser

      -

      script.plugins

      +

      script.plugins

      • 默认值: []
      @@ -191,9 +191,9 @@

      script.p
    1. filters: 对哪些模块执行该插件,必须配置,支持 resolvedPathsmoduleTypes 这两个过滤项,两者如果同时指定,取并集。
    2. 对于 Vue 项目支持 JSX 的配置示例如下:

      -
      import jsPluginVue from "@farmfe/js-plugin-vue";

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [
      {
      name: "swc-plugin-vue-jsx",
      options: {
      transformOn: true,
      optimize: true,
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ["tsx", "jsx"],
      },
      },
      ],
      },
      },
      plugins: [jsPluginVue()],
      };
      -

      script.decorators

      -
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * 装饰器版本: 2021-12 或者 2022-03
      * @default 2021-12
      */
      decoratorVersion: "2021-12" | "2022-03" | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }
      +
      import jsPluginVue from "@farmfe/js-plugin-vue";

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [
      {
      name: "swc-plugin-vue-jsx",
      options: {
      transformOn: true,
      optimize: true,
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ["tsx", "jsx"],
      },
      },
      ],
      },
      },
      plugins: [jsPluginVue()],
      };
      +

      script.decorators

      +
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * 装饰器版本: 2021-12 或者 2022-03
      * @default 2021-12
      */
      decoratorVersion: "2021-12" | "2022-03" | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }

      建议使用 Farm 默认的装饰器配置,除非你想提高性能,可以设置includesexcludes

      选项:

        @@ -203,36 +203,36 @@

        scrip
      • 包括:默认为[]。如果要包含排除的模块,可以设置此选项。支持正则表达式。
      • 排除:默认为['node_modules/']。变换装饰器时,这些路径下的模块将被忽略。支持正则表达式
      -

      css

      -

      css.modules

      +

      css

      +

      css.modules

      配置 Farm CSS Modules。

      -
      interface FarmCssModulesConfig {
      // 配置哪些路径会被处理为 css modules,使用正则字符串
      // 默认为 `.module.css` 或者 `.module.scss` 或者 `.module.less`
      paths?: string[];
      // 配置生成的 css 类名,默认为 `[name]-[hash]`
      indentName?: string;
      }
      -
      css.modules.paths
      +
      interface FarmCssModulesConfig {
      // 配置哪些路径会被处理为 css modules,使用正则字符串
      // 默认为 `.module.css` 或者 `.module.scss` 或者 `.module.less`
      paths?: string[];
      // 配置生成的 css 类名,默认为 `[name]-[hash]`
      indentName?: string;
      }
      +
      css.modules.paths
      • 默认值: ["\\.module\\.(css|scss|sass|less)"]

      配置哪些路径对应的模块会被视为 CSS Modules。需要配置正则字符串。默认是以 .module.(css|scss|sass|less) 结尾的文件。

      -
      css.modules.identName
      +
      css.modules.identName
      • 默认值: [name]-[hash]

      配置生成的 CSS Modules 类名,默认是 [name]-[hash][name], [hash] 为占位符(也是目前支持的所有占位符)。[name] 表示原始类名,[hash] 表示改 css 文件 id 的 hash。

      -

      css.prefixer

      +

      css.prefixer

      配置 CSS 的兼容性前缀,例如 -webkit-

      -
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | "chrome"
      | "opera"
      | "edge"
      | "firefox"
      | "safari"
      | "ie"
      | "ios"
      | "android"
      | "node"
      | "electron",
      string
      >
      > & { [key: string]: string };
      -
      css.prefixer.targets
      +
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | "chrome"
      | "opera"
      | "edge"
      | "firefox"
      | "safari"
      | "ie"
      | "ios"
      | "android"
      | "node"
      | "electron",
      string
      >
      > & { [key: string]: string };
      +
      css.prefixer.targets
      • 默认值: undefined

      配置对于哪些目标浏览器或者浏览器版本开启,示例:

      -
      import { defineConfig } from "@farmfe/core";

      export default defineConfig({
      compilation: {
      css: {
      prefixer: {
      targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
      },
      },
      },
      });
      -

      html

      -

      html.base

      +
      import { defineConfig } from "@farmfe/core";

      export default defineConfig({
      compilation: {
      css: {
      prefixer: {
      targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
      },
      },
      },
      });
      +

      html

      +

      html.base

      • 默认值: undefined

      所有的 HTML 入口会继承 html.base,详情参考 指南 - HTML

      -

      sourcemap

      +

      sourcemap

      • 默认值: true
      @@ -244,25 +244,25 @@

      sourcemapall:对所有文件生成 sourcemap,并且生成单独的 sourcemap 文件
    3. all-inline: 对所有的文件生成 sourcemap,并且内联 sourcemap 到产物中,不生成单独的文件
    4. -

      partialBundling

      +

      partialBundling

      配置 Farm 局部打包的行为,详情可以参考 局部打包

      -
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: "mutable" | "immutable";
      resourceType?: "all" | "initial" | "async";
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      }
      -

      partialBundling.targetConcurrentRequests

      +
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: "mutable" | "immutable";
      resourceType?: "all" | "initial" | "async";
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      }
      +

      partialBundling.targetConcurrentRequests

      • default: 25

      Farm 尝试生成尽可能接近此配置值的资源数量,控制初始资源加载或动态资源加载的并发请求数量。

      -

      partialBundling.targetMinSize

      +

      partialBundling.targetMinSize

      • default: 20 * 1024 bytes, 20 KB

      minify 和 gzip 之前生成的资源的最小大小。 请注意,targetMinSize 并不一定保证满足,可以配置enforceTargetMinSize可用于强制限制最小的大小。

      -

      partialBundling.targetMaxSize

      +

      partialBundling.targetMaxSize

      • default: 1500 * 1024 bytes, 1500 KB

      minify 和 gzip 之前生成的资源的最大大小。

      -

      partialBundling.groups

      +

      partialBundling.groups

      • default: []
      @@ -274,8 +274,8 @@

    5. groupType: mutableimmutable,限制该组仅适用于指定类型的模块。
    6. resourceType: allinitialasync,限制该组仅适用于指定类型的资源。
    7. -
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: "vendor-react",
      test: ["node_modules/"],
      },
      ],
      },
      },
      });
      -

      partialBundling.enforceResources

      +
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: "vendor-react",
      test: ["node_modules/"],
      },
      ],
      },
      },
      });
      +

      partialBundling.enforceResources

      • default: []
      @@ -285,90 +285,90 @@

      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      enforceResources: [
      {
      name: "index",
      test: [".+"],
      },
      ],
      },
      },
      });

    -
    注意

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    -

    partialBundling.enforceTargetConcurrentRequests

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: "index",
    test: [".+"],
    },
    ],
    },
    },
    });
    +
    注意

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    +

    partialBundling.enforceTargetConcurrentRequests

    • default: false

    对每个资源加载强制执行目标并发请求数量,当为 true 时,较小的资源将合并为较大的资源以满足目标并发请求。 这可能会导致 css 资源出现问题,请小心使用此选项

    -

    partialBundling.enforceTargetMinSize

    +

    partialBundling.enforceTargetMinSize

    • default: false

    为每个资源强制执行目标最小大小限制,如果为真,较小的资源将合并为较大的资源以满足目标并发请求。 这可能会导致 css 资源出现问题,请小心使用此选项

    -

    partialBundling.immutableModules

    +

    partialBundling.immutableModules

    • default: ['node_modules']

    匹配不可变模块的正则表达式数组

    -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });
    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });

    不可变模块会影响打包和持久缓存,如果要更改它,请小心。

    -

    partialBundling.immutableModulesWeight

    +

    partialBundling.immutableModulesWeight

    • default: 0.8

    Default to 0.8, immutable module will have 80% request numbers. For example, if targetConcurrentRequest is 25, then immutable resources will take 25 * 80% = 20 by default. This option is to make sure that mutable and immutable modules are isolate, if change your business code, code under node_modules won't be affected.

    -

    lazyCompilation

    +

    lazyCompilation

    • 默认值: 在开发模式是 true,构建模式是 false

    是否启用懒编译,配置为 false 关闭。参考 懒编译

    -

    treeShaking

    +

    treeShaking

    • 默认值: 在开发模式是 false,构建模式是 true

    是否启用 tree shake,配置为 false 关闭。参考 Tree Shake

    -

    minify

    +

    minify

    • 默认值: 在开发模式是 false,构建模式是 true

    是否启用压缩,开启后将会对产物进行压缩和混淆。参考 压缩

    -

    presetEnv

    +

    presetEnv

    • 默认值: 在开发模式是 false,构建模式是 true
    -
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };
    +
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };

    默认不会对 node_modules 下的模块注入 polyfill,如果需要,请使用 include 添加 polyfill。

    -

    presetEnv.include

    +

    presetEnv.include

    • 默认值: []

    额外包含哪些需要 polyfill 的模块,配置正则字符串,例如 include: ['node_modules/(es6-package|my-package)/']

    -

    presetEnv.exclude

    +

    presetEnv.exclude

    • 默认值: ['node_modules/']

    配置哪些不需要 polyfill 的模块,配置正则字符串,例如 exclude: ['custom-path/(es5-package|my-package)/']。默认 node_modules 被排除,如果需要包含被排除的模块,建议使用 include

    -

    presetEnv.options

    +

    presetEnv.options

    • 默认值: 降级到 ES5

    传递给 swc preset env 的选项,参考 https://swc.rs/docs/configuration/compilation#env。

    -

    persistentCache

    +

    persistentCache

    • default: true

    增量构建 的缓存配置选项. 配置成 false 来禁用缓存.

    -
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    -

    persistentCache.namespace

    +
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    +

    persistentCache.namespace

    • default: farm-cache

    缓存的命名空间,不同空间下的缓存会相互隔离,不会复用。

    -

    persistentCache.cacheDir

    +

    persistentCache.cacheDir

    • default: node_modules/.farm/cache

    缓存文件的存放目录。

    -

    persistentCache.buildDependencies

    +

    persistentCache.buildDependencies

    • default: farm.config.ts and all its deep dependencies

    所有配置文件、插件等构建依赖的路径,默认包含 farm.config.ts/js/mjs 的所有依赖以及配置的所有 rust 和 js 插件。如果任意一个构建依赖变更了,所有缓存将会失效。

    配置项可以是一个路径或者一个包名, 例如:

    -
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    -

    persistentCache.moduleCacheKeyStrategy

    +
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    +

    persistentCache.moduleCacheKeyStrategy

    • default: { timestamp: true, hash: true }
    @@ -377,10 +377,10 @@

    注意事项.
  • hash: 是否检查 load 和 transform 后的内容。
  • -

    persistentCache.envs

    +

    persistentCache.envs

    -

    可能影响构建过程的环境变量,如果任意一个环境变化了,缓存将会过期。

    +

    可能影响构建过程的环境变量,如果任意一个环境变化了,缓存将会过期。

    \ No newline at end of file diff --git a/zh/docs/0.x/config/dev-server/index.html b/zh/docs/0.x/config/dev-server/index.html index 02935050d..a4c31ff27 100644 --- a/zh/docs/0.x/config/dev-server/index.html +++ b/zh/docs/0.x/config/dev-server/index.html @@ -8,59 +8,59 @@ - - - + + + -
    版本:0.15

    dev-server

    DevServer 选项 - server

    +
    版本:0.15

    dev-server

    DevServer 选项 - server

    配置 Farm Dev Server 的行为。示例:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    port: 9000,
    // ...
    }
    });
    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    port: 9000,
    // ...
    }
    });

    类型:

    -
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: 'http' | 'https';
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    -

    port

    +
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: 'http' | 'https';
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    +

    port

    • 默认值: 9000

    DevServer 监听的端口。

    -

    hmr

    +

    hmr

    • 默认值: 对于 start 命令是 true,其他命令是 false

    启用 HMR,开启后启用 HMR 能力,将会监听编译过程中涉及到的模块的变动,当模块变化时,自动触发重编译并将结果推送给 Farm Runtime 进行更新。也可以通过一个对象来配置 HMR,例如:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    hmr: {
    // 配置 web socket 监听的端口
    port: 9802
    // 配置 web socket 监听的 host
    host: 'localhost',
    // 配置文件监听时,忽略的文件
    ignores: ['auto_generated/*']
    }
    // ...
    }
    });
    -

    hmr.port

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    hmr: {
    // 配置 web socket 监听的端口
    port: 9802
    // 配置 web socket 监听的 host
    host: 'localhost',
    // 配置文件监听时,忽略的文件
    ignores: ['auto_generated/*']
    }
    // ...
    }
    });
    +

    hmr.port

    • 默认值: 9801

    Web Socket 服务器监听的端口

    -

    hmr.host

    +

    hmr.host

    • 默认值: localhost

    Web Socket 服务器监听的 Host

    -

    proxy

    +

    proxy

    • 默认值: undefined

    配置服务器代理。基于 http-proxy 实现,具体选项参考其文档,示例:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    -

    open

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    +

    open

    • 默认值: false

    编译完成后自动打开浏览器到对应的页面。

    -

    host

    +

    host

    • 默认值: localhost

    Dev Server 监听的 host。

    -

    plugins

    +

    plugins

    • 默认值: []

    配置 Farm 的 Dev Server 插件,通过 Dev Server 插件可以扩展 DevServer 的上下文,添加 middleware 等。插件就是一个函数,插件示例如下:

    -
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(devServer.getCompiler(), devServer, logger);
    }
    }
    -

    然后将该插件配置到 server.plugins 中。

    +
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(devServer.getCompiler(), devServer, logger);
    }
    }
    +

    然后将该插件配置到 server.plugins 中。

    \ No newline at end of file diff --git a/zh/docs/0.x/config/environment-variable/index.html b/zh/docs/0.x/config/environment-variable/index.html index 62f637aac..fd229e5c2 100644 --- a/zh/docs/0.x/config/environment-variable/index.html +++ b/zh/docs/0.x/config/environment-variable/index.html @@ -8,26 +8,26 @@ - - - + + + -
    版本:0.15

    environment-variable

    Environment variable 环境变量

    +
    版本:0.15

    environment-variable

    Environment variable 环境变量

    Farm 通过 process.env.NODE_ENV 来区分开发和生产环境。

    在不同环境中, 环境变量会被静态替换, 所以请使用静态的常量来表示环境变量, 而不是动态的表达式.

    -

    .env 文件

    +

    .env 文件

    Farm 使用 dotenv 来加载您的额外的环境变量, 例如 .env 文件.

    -
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0
    +
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0

    Farm 会通过 dotenv 加载 .env 文件, 并且将其加载到 process.env 中 最终在 define 中注入.

    -
    注意

    为了保证客户端安全, 防止将当前系统中的环境变量暴露给客户端 Farm 只会识别以 FARM_ 开头和一些重要的环境变量.

    +
    注意

    为了保证客户端安全, 防止将当前系统中的环境变量暴露给客户端 Farm 只会识别以 FARM_ 开头和一些重要的环境变量.

    Farm 通过 dotenv-expand 来拓展环境变量

    如果你想自定义 env 变量的前缀,可以配置 envPrefix

    -

    envPrefix env 变量前缀

    +

    envPrefix env 变量前缀

    • 默认值: FARM_

    通过配置 envPrefix 来自定义 env 变量的前缀。

    -
    +
    \ No newline at end of file diff --git a/zh/docs/0.x/config/farm-config/index.html b/zh/docs/0.x/config/farm-config/index.html index dd29ea221..863e3a3aa 100644 --- a/zh/docs/0.x/config/farm-config/index.html +++ b/zh/docs/0.x/config/farm-config/index.html @@ -8,29 +8,29 @@ - - - + + + -
    版本:0.15

    配置参考

    +
    版本:0.15

    配置参考

    Farm 默认从项目根目录的 farm.config.ts|js|mjs 文件中读取配置,配置文件示例:

    -
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: Config) {
    return config;
    }

    export default defineConfig({
    root: process.cwd(), // 编译的根目录
    // 编译选项
    compilation: {
    // ...
    },
    // Dev Server 选项
    server: {
    hmr: true,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    -

    编译选项 - compilation

    +
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: Config) {
    return config;
    }

    export default defineConfig({
    root: process.cwd(), // 编译的根目录
    // 编译选项
    compilation: {
    // ...
    },
    // Dev Server 选项
    server: {
    hmr: true,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    +

    编译选项 - compilation

    所有与编译相关的配置都在 compilation 字段下。

    -

    input

    +

    input

    • type: Record<string, string>

    项目的入口点。 Input 的文件可以是htmlts/js/tsx/jsxcss 或通过插件支持的其他文件。

    -
    import type { UserConfig } from "@farmfe/core";

    export default <UserConfig>{
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    -

    output

    +
    import type { UserConfig } from "@farmfe/core";

    export default <UserConfig>{
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    +

    output

    • type: OutputOptions
    -
    interface OutputOptions {
    // 局部打包后,入口文件所在资源的文件名配置
    entryFilename?: string;
    // 局部打包后,除入口资源外的其他资源输入文件名配置
    filename?: string;
    // 输入目录
    path?: string;
    // public path:资源加载前缀
    publicPath?: string;
    // 静态资源文件名配置
    assetsFilename?: string;
    // 目标执行环境,浏览器或者 Node
    targetEnv?: "browser" | "node";
    // 输出模块格式
    format?: "cjs" | "esm";
    }
    -
    备注

    我们称编译结果为 资源(resource)

    -

    output.entryFilename

    +
    interface OutputOptions {
    // 局部打包后,入口文件所在资源的文件名配置
    entryFilename?: string;
    // 局部打包后,除入口资源外的其他资源输入文件名配置
    filename?: string;
    // 输入目录
    path?: string;
    // public path:资源加载前缀
    publicPath?: string;
    // 静态资源文件名配置
    assetsFilename?: string;
    // 目标执行环境,浏览器或者 Node
    targetEnv?: "browser" | "node";
    // 输出模块格式
    format?: "cjs" | "esm";
    }
    +
    备注

    我们称编译结果为 资源(resource)

    +

    output.entryFilename

    • 默认值: "[entryName].[ext]"
    @@ -41,7 +41,7 @@

    outputoutput.filename

    +

    output.filename

    • 默认值: "[resourceName].[ext]"
    @@ -51,136 +51,136 @@

    output.
  • [contentHash]:该资源的内容哈希。
  • [ext]:该资源的扩展名,对于 js/jsx/ts/tsxjs,对于 css/scss/lesscss
  • -

    output.path

    +

    output.path

    • 默认值: "dist"

    输出资源的目录

    -

    output.publicPath

    +

    output.publicPath

    • 默认值: "/"

    资源 url 加载的前缀. 比如 URL https://xxxx,或者一个路径 /xxx.

    -

    output.assetsFileName

    +

    output.assetsFileName

    • 默认值: "[resourceName].[ext]"

    静态资源输出的文件名配置,占位符和 output.filename 相同。

    -

    output.targetEnv

    +

    output.targetEnv

    • 默认值: "browser"

    配置产物的执行环境,可以是 "browser" 或者 "node".

    -

    output.format

    +

    output.format

    • 默认值: "esm"

    配置产物的格式,可以是 "esm" 或者 "cjs".

    -
    备注

    该选项只对 Js 产物有效

    -

    resolve

    +
    备注

    该选项只对 Js 产物有效

    +

    resolve

    • type: ResolveOptions
    -
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    -

    resolve.extensions

    +
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    +

    resolve.extensions

    • 默认值: ["tsx", "ts", "jsx", "js", "mjs", "json", "html", "css"]

    配置解析依赖时的后缀,例如解析 ./index 时,如果没有解析到,则会自动加上后缀解析,如尝试 ./index.tsx, ./index.css 等。

    -

    resolve.alias

    +

    resolve.alias

    • 默认值: {}

    配置解析别名,示例:

    -
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });
    +
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });

    alias 为前缀替换,对于上述例子 /@/pages 将会被替换为,/root/src/pages

    如果希望精确匹配,可以加上 $,例如 stream$ 只会替换 stream,而不会替换 stream/xxx

    当然也支持使用正则表达式,例如 $__farm_regex:^/(utils)$,将会匹配 /utils,并替换为 /root/src/utils

    -

    resolve.mainFields

    +

    resolve.mainFields

    • 默认值: ["exports", "browser", "module", "main"]

    解析 node_modules 下依赖时,从 package.json 中将会按照 mainFields 中配置的字段和顺序进行解析。对于 package.json

    -
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }
    +
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }

    将会优先使用 es/index.js(如果路径存在),不存在则会继续向后搜索。

    -

    resolve.conditions

    +

    resolve.conditions

    暂不支持配置。

    - +
    • 默认值: true

    解析文件时,是否追踪 symlink 对应的真实目录,并从真实目录开始解析下一个依赖。如果使用 pnpm 管理依赖,该选项必须配置为 true。

    -

    resolve.strictExports

    +

    resolve.strictExports

    • 默认值: false

    是否严格遵循 package.jsonexports 中定义的导出。如果设置为 true,当 package.json 中定义了 exports,但是 exports 没有定义对应导出时,会直接报错。如果设置为 true,会按照 mainFields 继续尝试其他入口。

    -

    define

    +

    define

    • 默认值: {}

    全局变量注入,配置的变量名和值将会在编译时注入到产物中。Farm 默认注入 process.env.NODE_ENV 以及部分 Farm 自身使用的变量比如 FARM_HMR_PORT

    -
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123,
    },
    },
    });
    -
    备注
      +
      export default defineConfig({
      compilation: {
      define: {
      MY_VAR: 123,
      },
      },
      });
      +
      备注
      1. define 为了强化性能,使用的是全局变量的注入形式,这意味着,对象形式的变量无法注入,例如 process.env.XXX 形式的变量无法注入,只能配置 XXX 形式的变量。
      2. 如果在同一个 window 下挂载多个 Farm 项目,多个项目同名的 define 会相互覆盖。
      3. 注入的是字符串,如果需要转为其他类型,需要在运行时代码中手动转换,例如 Number(MY_VAR)
      -

      external

      +

      external

      • 默认值: []

      配置被 external 的导入,被 external 的导入不会出现在编译产物中。但是对应 import 语句不会删除,需要自定义 external 后如何处理,否则运行时会报错,对于 targetEnv 是 node 下的 external 模块,会自动尝试 require 该模块。

      需要使用正则方式配置,例如:

      -
      export default defineConfig({
      compilation: {
      external: ["^stream$"],
      },
      });
      -

      mode

      +
      export default defineConfig({
      compilation: {
      external: ["^stream$"],
      },
      });
      +

      mode

      • 默认值: 对于 start、watch 命令是 development,对于 build 命令是 production

      配置编译模式,为了优化开发时性能,在没有手动配置生产优化相关选项(minify,tree shake 等)时,默认在 development 下会禁用生产环境优化比如压缩和 tree shake,在 production 模式下启用。

      -

      root

      +

      root

      • 默认值: process.cwd()

      配置项目编译的 root 目录,该选项会影响默认配置文件的查找路径,编译模块依赖的查找等。

      -

      runtime

      +

      runtime

      配置 Farm 运行时能力。类型如下:

      -
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      -

      runtime.path

      +
      interface FarmRuntimeOptions {
      runtime?: {
      path: string;
      plugins?: string[];
      namespace?: string;
      };
      }
      +

      runtime.path

      • 默认值: Farm 内置 runtime 的路径

      自定义一个 Runtime 替换 Farm 内置的 Runtime。

      -
      注意

      正常情况下不建议配置该选项,因为一旦配置了该选项,指向的 runtime 需要所有实现 Farm Runtime 已有的能力,例如模块系统、HMR、动态资源加载等。

      -

      runtime.plugins

      +
      注意

      正常情况下不建议配置该选项,因为一旦配置了该选项,指向的 runtime 需要所有实现 Farm Runtime 已有的能力,例如模块系统、HMR、动态资源加载等。

      +

      runtime.plugins

      • 默认值: Farm 内置 runtime-plugin-hmr 的路径

      配置 Runtime 插件,通过 Runtime 插件,可以干预 Runtime 行为,如模块加载,资源加载等。具体可以参考:WIP。

      -

      runtime.namespace

      +

      runtime.namespace

      • 默认值: 项目 package.json 的 name 字段

      配置 Farm Runtime 的命名空间,保证在同一个 window 或者 global 下不同产物的执行能够相互隔离。默认使用项目 package.json 的 name 字段作为 namespace。

      -

      assets

      -

      assets.include

      +

      assets

      +

      assets.include

      • 默认值: []

      额外视为静态资源的文件后缀,例如下述示例,txt 将会被视为姿态资源,引入 txt 文件时当作静态资源处理:

      -
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"],
      },
      },
      });
      -

      script

      -

      script.target

      +
      export default defineConfig({
      compilation: {
      assets: {
      include: ["txt"],
      },
      },
      });
      +

      script

      +

      script.target

      • 默认值: esnext(根据 Farm 的迭代动态调整)

      配置 Farm 解析 js/jsx/ts/tsx 的 AST 以及生成代码时支持的 ES 语法版本。 可选值:es5, es6, es2015 - es2023, esnext

      -

      script.parser

      +

      script.parser

      • 默认值: 与 SWC 相同

      配置 SWC 解析 AST 时的行为,配置项参考:https://swc.rs/docs/configuration/compilation#jscparser

      -

      script.plugins

      +

      script.plugins

      • 默认值: []
      @@ -191,9 +191,9 @@

      script.p
    1. filters: 对哪些模块执行该插件,必须配置,支持 resolvedPathsmoduleTypes 这两个过滤项,两者如果同时指定,取并集。
    2. 对于 Vue 项目支持 JSX 的配置示例如下:

      -
      import jsPluginVue from "@farmfe/js-plugin-vue";

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [
      {
      name: "swc-plugin-vue-jsx",
      options: {
      transformOn: true,
      optimize: true,
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ["tsx", "jsx"],
      },
      },
      ],
      },
      },
      plugins: [jsPluginVue()],
      };
      -

      script.decorators

      -
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * 装饰器版本: 2021-12 或者 2022-03
      * @default 2021-12
      */
      decoratorVersion: "2021-12" | "2022-03" | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }
      +
      import jsPluginVue from "@farmfe/js-plugin-vue";

      /**
      * @type {import('@farmfe/core').UserConfig}
      */
      export default {
      compilation: {
      script: {
      plugins: [
      {
      name: "swc-plugin-vue-jsx",
      options: {
      transformOn: true,
      optimize: true,
      },
      filters: {
      // resolvedPaths: [".+"]
      moduleTypes: ["tsx", "jsx"],
      },
      },
      ],
      },
      },
      plugins: [jsPluginVue()],
      };
      +

      script.decorators

      +
      export interface DecoratorsConfig {
      legacyDecorator: boolean;
      decoratorMetadata: boolean;
      /**
      * 装饰器版本: 2021-12 或者 2022-03
      * @default 2021-12
      */
      decoratorVersion: "2021-12" | "2022-03" | null;
      /**
      * @default []
      */
      includes: string[];
      /**
      * @default ["node_modules/"]
      */
      excludes: string[];
      }

      建议使用 Farm 默认的装饰器配置,除非你想提高性能,可以设置includesexcludes

      选项:

        @@ -203,36 +203,36 @@

        scrip
      • 包括:默认为[]。如果要包含排除的模块,可以设置此选项。支持正则表达式。
      • 排除:默认为['node_modules/']。变换装饰器时,这些路径下的模块将被忽略。支持正则表达式
      -

      css

      -

      css.modules

      +

      css

      +

      css.modules

      配置 Farm CSS Modules。

      -
      interface FarmCssModulesConfig {
      // 配置哪些路径会被处理为 css modules,使用正则字符串
      // 默认为 `.module.css` 或者 `.module.scss` 或者 `.module.less`
      paths?: string[];
      // 配置生成的 css 类名,默认为 `[name]-[hash]`
      indentName?: string;
      }
      -
      css.modules.paths
      +
      interface FarmCssModulesConfig {
      // 配置哪些路径会被处理为 css modules,使用正则字符串
      // 默认为 `.module.css` 或者 `.module.scss` 或者 `.module.less`
      paths?: string[];
      // 配置生成的 css 类名,默认为 `[name]-[hash]`
      indentName?: string;
      }
      +
      css.modules.paths
      • 默认值: ["\\.module\\.(css|scss|sass|less)"]

      配置哪些路径对应的模块会被视为 CSS Modules。需要配置正则字符串。默认是以 .module.(css|scss|sass|less) 结尾的文件。

      -
      css.modules.identName
      +
      css.modules.identName
      • 默认值: [name]-[hash]

      配置生成的 CSS Modules 类名,默认是 [name]-[hash][name], [hash] 为占位符(也是目前支持的所有占位符)。[name] 表示原始类名,[hash] 表示改 css 文件 id 的 hash。

      -

      css.prefixer

      +

      css.prefixer

      配置 CSS 的兼容性前缀,例如 -webkit-

      -
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | "chrome"
      | "opera"
      | "edge"
      | "firefox"
      | "safari"
      | "ie"
      | "ios"
      | "android"
      | "node"
      | "electron",
      string
      >
      > & { [key: string]: string };
      -
      css.prefixer.targets
      +
      interface FarmCssPrefixer {
      targets?: string[] | string | BrowserTargetsRecord;
      }

      type BrowserTargetsRecord = Partial<
      Record<
      | "chrome"
      | "opera"
      | "edge"
      | "firefox"
      | "safari"
      | "ie"
      | "ios"
      | "android"
      | "node"
      | "electron",
      string
      >
      > & { [key: string]: string };
      +
      css.prefixer.targets
      • 默认值: undefined

      配置对于哪些目标浏览器或者浏览器版本开启,示例:

      -
      import type { UserConfig } from "@farmfe/core";

      function defineConfig(config: UserConfig) {
      return config;
      }

      export default defineConfig({
      compilation: {
      css: {
      prefixer: {
      targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
      },
      },
      },
      });
      -

      html

      -

      html.base

      +
      import type { UserConfig } from "@farmfe/core";

      function defineConfig(config: UserConfig) {
      return config;
      }

      export default defineConfig({
      compilation: {
      css: {
      prefixer: {
      targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
      },
      },
      },
      });
      +

      html

      +

      html.base

      • 默认值: undefined

      所有的 HTML 入口会继承 html.base,详情参考 指南 - HTML

      -

      sourcemap

      +

      sourcemap

      • 默认值: true
      @@ -244,25 +244,25 @@

      sourcemapall:对所有文件生成 sourcemap,并且生成单独的 sourcemap 文件
    3. all-inline: 对所有的文件生成 sourcemap,并且内联 sourcemap 到产物中,不生成单独的文件
    4. -

      partialBundling

      +

      partialBundling

      配置 Farm 局部打包的行为,详情可以参考 局部打包

      -
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: "mutable" | "immutable";
      resourceType?: "all" | "initial" | "async";
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      }
      -

      partialBundling.targetConcurrentRequests

      +
      export interface FarmPartialBundlingConfig {
      targetConcurrentRequests?: number;
      targetMinSize?: number;
      targetMaxSize?: number;
      groups?: {
      name: string;
      test: string[];
      groupType?: "mutable" | "immutable";
      resourceType?: "all" | "initial" | "async";
      }[];
      enforceResources?: {
      name: string;
      test: string[];
      }[];
      enforceTargetConcurrentRequests?: boolean;
      enforceTargetMinSize?: boolean;
      immutableModules?: string[];
      }
      +

      partialBundling.targetConcurrentRequests

      • default: 25

      Farm 尝试生成尽可能接近此配置值的资源数量,控制初始资源加载或动态资源加载的并发请求数量。

      -

      partialBundling.targetMinSize

      +

      partialBundling.targetMinSize

      • default: 20 * 1024 bytes, 20 KB

      minify 和 gzip 之前生成的资源的最小大小。 请注意,targetMinSize 并不一定保证满足,可以配置enforceTargetMinSize可用于强制限制最小的大小。

      -

      partialBundling.targetMaxSize

      +

      partialBundling.targetMaxSize

      • default: 1500 * 1024 bytes, 1500 KB

      minify 和 gzip 之前生成的资源的最大大小。

      -

      partialBundling.groups

      +

      partialBundling.groups

      • default: []
      @@ -274,8 +274,8 @@

    5. groupType: mutableimmutable,限制该组仅适用于指定类型的模块。
    6. resourceType: allinitialasync,限制该组仅适用于指定类型的资源。
    7. -
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: "vendor-react",
      test: ["node_modules/"],
      },
      ],
      },
      },
      });
      -

      partialBundling.enforceResources

      +
      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      groups: [
      {
      name: "vendor-react",
      test: ["node_modules/"],
      },
      ],
      },
      },
      });
      +

      partialBundling.enforceResources

      • default: []
      @@ -285,90 +285,90 @@

      farm.config.ts
      export default defineConfig({
      compilation: {
      partialBundling: {
      enforceResources: [
      {
      name: "index",
      test: [".+"],
      },
      ],
      },
      },
      });

    -
    注意

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    -

    partialBundling.enforceTargetConcurrentRequests

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: "index",
    test: [".+"],
    },
    ],
    },
    },
    });
    +
    注意

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    +

    partialBundling.enforceTargetConcurrentRequests

    • default: false

    对每个资源加载强制执行目标并发请求数量,当为 true 时,较小的资源将合并为较大的资源以满足目标并发请求。 这可能会导致 css 资源出现问题,请小心使用此选项

    -

    partialBundling.enforceTargetMinSize

    +

    partialBundling.enforceTargetMinSize

    • default: false

    为每个资源强制执行目标最小大小限制,如果为真,较小的资源将合并为较大的资源以满足目标并发请求。 这可能会导致 css 资源出现问题,请小心使用此选项

    -

    partialBundling.immutableModules

    +

    partialBundling.immutableModules

    • default: ['node_modules']

    匹配不可变模块的正则表达式数组

    -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });
    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });

    不可变模块会影响打包和持久缓存,如果要更改它,请小心。

    -

    partialBundling.immutableModulesWeight

    +

    partialBundling.immutableModulesWeight

    • default: 0.8

    Default to 0.8, immutable module will have 80% request numbers. For example, if targetConcurrentRequest is 25, then immutable resources will take 25 * 80% = 20 by default. This option is to make sure that mutable and immutable modules are isolate, if change your business code, code under node_modules won't be affected.

    -

    lazyCompilation

    +

    lazyCompilation

    • 默认值: 在开发模式是 true,构建模式是 false

    是否启用懒编译,配置为 false 关闭。参考 懒编译

    -

    treeShaking

    +

    treeShaking

    • 默认值: 在开发模式是 false,构建模式是 true

    是否启用 tree shake,配置为 false 关闭。参考 Tree Shake

    -

    minify

    +

    minify

    • 默认值: 在开发模式是 false,构建模式是 true

    是否启用压缩,开启后将会对产物进行压缩和混淆。参考 压缩

    -

    presetEnv

    +

    presetEnv

    • 默认值: 在开发模式是 false,构建模式是 true
    -
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };
    +
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };

    默认不会对 node_modules 下的模块注入 polyfill,如果需要,请使用 include 添加 polyfill。

    -

    presetEnv.include

    +

    presetEnv.include

    • 默认值: []

    额外包含哪些需要 polyfill 的模块,配置正则字符串,例如 include: ['node_modules/(es6-package|my-package)/']

    -

    presetEnv.exclude

    +

    presetEnv.exclude

    • 默认值: ['node_modules/']

    配置哪些不需要 polyfill 的模块,配置正则字符串,例如 exclude: ['custom-path/(es5-package|my-package)/']。默认 node_modules 被排除,如果需要包含被排除的模块,建议使用 include

    -

    presetEnv.options

    +

    presetEnv.options

    • 默认值: 降级到 ES5

    传递给 swc preset env 的选项,参考 https://swc.rs/docs/configuration/compilation#env。

    -

    persistentCache

    +

    persistentCache

    • default: true

    增量构建 的缓存配置选项. 配置成 false 来禁用缓存.

    -
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    -

    persistentCache.namespace

    +
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    +

    persistentCache.namespace

    • default: farm-cache

    缓存的命名空间,不同空间下的缓存会相互隔离,不会复用。

    -

    persistentCache.cacheDir

    +

    persistentCache.cacheDir

    • default: node_modules/.farm/cache

    缓存文件的存放目录。

    -

    persistentCache.buildDependencies

    +

    persistentCache.buildDependencies

    • default: farm.config.ts and all its deep dependencies

    所有配置文件、插件等构建依赖的路径,默认包含 farm.config.ts/js/mjs 的所有依赖以及配置的所有 rust 和 js 插件。如果任意一个构建依赖变更了,所有缓存将会失效。

    配置项可以是一个路径或者一个包名, 例如:

    -
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    -

    persistentCache.moduleCacheKeyStrategy

    +
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    +

    persistentCache.moduleCacheKeyStrategy

    • default: { timestamp: true, hash: true }
    @@ -377,86 +377,86 @@

    注意事项.
  • hash: 是否检查 load 和 transform 后的内容。
  • -

    persistentCache.envs

    +

    persistentCache.envs

    可能影响构建过程的环境变量,如果任意一个环境变化了,缓存将会过期。

    -

    DevServer 选项 - server

    +

    DevServer 选项 - server

    配置 Farm Dev Server 的行为。示例:

    -
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    port: 9000,
    // ...
    },
    });
    +
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    port: 9000,
    // ...
    },
    });

    类型:

    -
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: "http" | "https";
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    -

    port

    +
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: "http" | "https";
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    +

    port

    • 默认值: 9000

    DevServer 监听的端口。

    -

    hmr

    +

    hmr

    • 默认值: 对于 start 命令是 true,其他命令是 false

    启用 HMR,开启后启用 HMR 能力,将会监听编译过程中涉及到的模块的变动,当模块变化时,自动触发重编译并将结果推送给 Farm Runtime 进行更新。也可以通过一个对象来配置 HMR,例如:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    hmr: {
    // 配置 web socket 监听的端口
    port: 9802
    // 配置 web socket 监听的 host
    host: 'localhost',
    // 配置文件监听时,忽略的文件
    ignores: ['auto_generated/*']
    }
    // ...
    }
    });
    -

    hmr.port

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    hmr: {
    // 配置 web socket 监听的端口
    port: 9802
    // 配置 web socket 监听的 host
    host: 'localhost',
    // 配置文件监听时,忽略的文件
    ignores: ['auto_generated/*']
    }
    // ...
    }
    });
    +

    hmr.port

    • 默认值: 9801

    Web Socket 服务器监听的端口

    -

    hmr.host

    +

    hmr.host

    • 默认值: localhost

    Web Socket 服务器监听的 Host

    -

    proxy

    +

    proxy

    • 默认值: undefined

    配置服务器代理。基于 http-proxy 实现,具体选项参考其文档,示例:

    -
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    -

    open

    +
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    +

    open

    • 默认值: false

    编译完成后自动打开浏览器到对应的页面。

    -

    host

    +

    host

    • 默认值: localhost

    Dev Server 监听的 host。

    -

    plugins

    +

    plugins

    • 默认值: []

    配置 Farm 的 Dev Server 插件,通过 Dev Server 插件可以扩展 DevServer 的上下文,添加 middleware 等。插件就是一个函数,插件示例如下:

    -
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host,
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(
    devServer.getCompiler(),
    devServer,
    logger
    );
    }
    }
    +
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host,
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(
    devServer.getCompiler(),
    devServer,
    logger
    );
    }
    }

    然后将该插件配置到 server.plugins 中。

    -

    Environment variable 环境变量

    +

    Environment variable 环境变量

    Farm 通过 process.env.NODE_ENV 来区分开发和生产环境。

    在不同环境中, 环境变量会被静态替换, 所以请使用静态的常量来表示环境变量, 而不是动态的表达式.

    -

    .env 文件

    +

    .env 文件

    Farm 使用 dotenv 来加载您的额外的环境变量, 例如 .env 文件.

    -
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0
    +
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0

    Farm 会通过 dotenv 加载 .env 文件, 并且将其加载到 process.env 中 最终在 define 中注入.

    -
    注意

    为了保证客户端安全, 防止将当前系统中的环境变量暴露给客户端 Farm 只会识别以 FARM_VITE_ 开头(为了更好的兼容 vite)和一些重要的环境变量.

    +
    注意

    为了保证客户端安全, 防止将当前系统中的环境变量暴露给客户端 Farm 只会识别以 FARM_VITE_ 开头(为了更好的兼容 vite)和一些重要的环境变量.

    Farm 通过 dotenv-expand 来拓展环境变量

    如果你想自定义 env 变量的前缀,可以配置 envPrefix

    -

    envPrefix env 变量前缀

    +

    envPrefix env 变量前缀

    • 默认值: FARM_VITE_

    通过配置 envPrefix 来自定义 env 变量的前缀。

    -



    ## Plugins Options
    配置 Farm 的插件,支持 Rust 插件或者 Js 插件,示例如下:

    ```ts
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass', less()],
    });
    -

    Rust Plugins

    +



    ## Plugins Options
    配置 Farm 的插件,支持 Rust 插件或者 Js 插件,示例如下:

    ```ts
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass', less()],
    });
    +

    Rust Plugins

    • 默认值: []

    Rust 插件通过 插件名或者 [插件名, 配置项选项] 方式配置,如下:

    -
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: [
    [
    "@farmfe/plugin-react",
    {
    /* options here */
    },
    ],
    "@farmfe/plugin-sass",
    ],
    });
    -

    Js Plugins

    +
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    plugins: [
    [
    "@farmfe/plugin-react",
    {
    /* options here */
    },
    ],
    "@farmfe/plugin-sass",
    ],
    });
    +

    Js Plugins

    • 默认值: []
    -

    Js 插件就是一个对象,具体可以参考 Js 插件

    +

    Js 插件就是一个对象,具体可以参考 Js 插件

    \ No newline at end of file diff --git a/zh/docs/0.x/config/plugins-options/index.html b/zh/docs/0.x/config/plugins-options/index.html index e22317eaf..36f0ac861 100644 --- a/zh/docs/0.x/config/plugins-options/index.html +++ b/zh/docs/0.x/config/plugins-options/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:0.15

    plugins-options

    Plugins Options

    +
    版本:0.15

    plugins-options

    Plugins Options

    配置 Farm 的插件,支持 Rust 插件或者 Js 插件,示例如下:

    -
    import { defineConfig } from "@farmfe/core";
    import less from "@farmfe/js-plugin-less";
    export default defineConfig({
    plugins: ["@farmfe/plugin-react", "@farmfe/plugin-sass", less()],
    });
    -

    Rust Plugins

    +
    import { defineConfig } from "@farmfe/core";
    import less from "@farmfe/js-plugin-less";
    export default defineConfig({
    plugins: ["@farmfe/plugin-react", "@farmfe/plugin-sass", less()],
    });
    +

    Rust Plugins

    • 默认值: []

    Rust 插件通过 插件名或者 [插件名, 配置项选项] 方式配置,如下:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    plugins: [
    [
    "@farmfe/plugin-react",
    {
    /* options here */
    },
    ],
    "@farmfe/plugin-sass",
    ],
    });
    -

    Js Plugins

    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    plugins: [
    [
    "@farmfe/plugin-react",
    {
    /* options here */
    },
    ],
    "@farmfe/plugin-sass",
    ],
    });
    +

    Js Plugins

    • 默认值: []
    -

    Js 插件就是一个对象,具体可以参考 Js 插件

    +

    Js 插件就是一个对象,具体可以参考 Js 插件

    \ No newline at end of file diff --git a/zh/docs/0.x/features/css/index.html b/zh/docs/0.x/features/css/index.html index fbf8d4e6d..c76272fdf 100644 --- a/zh/docs/0.x/features/css/index.html +++ b/zh/docs/0.x/features/css/index.html @@ -8,75 +8,75 @@ - - - + + + -
    版本:0.15

    CSS

    +
    版本:0.15

    CSS

    Farm 支持开箱即用的 CSS 编译,例如:

    -
    import './index.css';
    +
    import './index.css';

    然后 Farm 会自动为 css 模块启用 HMR,并自动打包 Css。

    -

    CSS Modules

    +

    CSS Modules

    Farm 默认支持 css modules,以 .module.css|less|scss|sass 结尾的模块默认将被视为 Css Modules

    -
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    -
    index.module.css
    .main {
    color: red;
    }
    +
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    +
    index.module.css
    .main {
    color: red;
    }

    您可以通过css.modules配置CSS模块。 例如,您可以将 css.modules.paths 设置为 ['.css|sass|less|scss'] 那么所有 css 文件将被视为 css 模块。

    -

    CSS 预处理器

    +

    CSS 预处理器

    Farm 官方提供了 sass、less、postcss 插件。

    -

    Sass

    +

    Sass

    Farm Sass 插件是一个 Rust 插件,使用 sass-embeded(后面我们可能会迁移到纯 Rust 编写的 grass)。

    在 Farm 中编译 sass/scss 模块的步骤如下:

    1. 安装依赖
    -
    # npm 或者 yarn 或者 pnpm,使用任意你喜欢的包管理器 
    npm install @farmfe/plugin-sass
    +
    # npm 或者 yarn 或者 pnpm,使用任意你喜欢的包管理器 
    npm install @farmfe/plugin-sass
    1. 配置插件
    -
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: ['@farmfe/plugin-sass'] // 配置 Rust 插件的包名即可引入和使用该插件
    // 如果你希望配置 plugin-sass 的参数,可以使用如下形式的配置
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    };
    +
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: ['@farmfe/plugin-sass'] // 配置 Rust 插件的包名即可引入和使用该插件
    // 如果你希望配置 plugin-sass 的参数,可以使用如下形式的配置
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    };
    1. 导入sass模块
    -
    import './index.scss';
    +
    import './index.scss';

    如果要将 sasscss modules 一起使用,请将文件名从 index.scss 更改为 index.module.scss,请参阅 css modules

    @farmfe/plugin-sass 支持很多选项,使用 plugins 的数组配置指定插件 sass 的选项:

    -
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    plugins: [
    // 通过数组语法指定插件以及配置
    [
    '@farmfe/plugin-sass',
    // 所有支持的选项如下
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    };
    -

    Less

    +
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    plugins: [
    // 通过数组语法指定插件以及配置
    [
    '@farmfe/plugin-sass',
    // 所有支持的选项如下
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    };
    +

    Less

    Farm less 插件是一个 Js 插件。 在 Farm 中编译 less 模块的步骤如下:

    1. 安装依赖
    -
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-less
    +
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-less
    1. 配置插件
    -
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default <UserConfig> {
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    +
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default <UserConfig> {
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    1. 导入 Less 模块
    -
    import './index.less';
    +
    import './index.less';

    要将 lesscss modules 一起使用,请将文件名从 index.less 更改为 index.module.less,参考 css modules

    -

    Postcss

    +

    Postcss

    Farm postcss 插件是一个 JS 插件,在 Farm 中引入 postcss 的步骤如下:

    1. 安装依赖
    -
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-postcss
    +
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-postcss
    1. 配置插件
    -
    import type { UserConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default <UserConfig> {
    // ...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    +
    import type { UserConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default <UserConfig> {
    // ...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    1. 配置 postcss.config.js,引入需要的 postcss 插件
    -
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    -

    Css Prefixer

    +
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    +

    Css Prefixer

    Farm 支持开箱即用的 css prefixer,您可以使用compilation.css.prefixer对其进行配置。

    -
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });
    +
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });

    对于输入代码

    -
    div {
    display: flex;
    }
    +
    div {
    display: flex;
    }

    输出

    -
    div{display:-ms-flexbox;display:flex}
    +
    div{display:-ms-flexbox;display:flex}
    \ No newline at end of file diff --git a/zh/docs/0.x/features/html/index.html b/zh/docs/0.x/features/html/index.html index c291f3408..bbb384506 100644 --- a/zh/docs/0.x/features/html/index.html +++ b/zh/docs/0.x/features/html/index.html @@ -8,31 +8,31 @@ - - - + + + -
    版本:0.15

    Html

    -

    基本用法

    +
    版本:0.15

    Html

    +

    基本用法

    Farm 支持开箱即用地编译 Html,并且在构建 Web 项目时应该使用 Html 作为入口,例如:

    -
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    -
    备注

    如果未指定 input,则默认为 {index: './index.html'}

    +
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    +
    备注

    如果未指定 input,则默认为 {index: './index.html'}

    ./index.html中,应该使用<script src="./xxx">来引用您的入口 Js/Ts/Jsx/Tsx 文件。

    -
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>
    +
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>

    你也可以使用<link href="./xxx">来引用你的全局 CSS。

    Farm 在编译时会将这些 scriptlink 转化为最终的生产可用的产物。请注意,当您想引用本地模块时,必须使用 相对路径,例如 <script src="./index.tsx"></script> 将引用本地模块并编译它, 但 <script src="/index.tsx"></script><script src="https://xxx.com/index.tsx"></script> 则不会。

    -
    备注

    scriptlink 可以引用 farm 支持的任何模块类型,例如,jsjsxtstsx 或插件支持的其他模块类型。 您可以根据需要使用任意数量的 scriptlink

    -

    多页面应用程序 - MPA

    +
    备注

    scriptlink 可以引用 farm 支持的任何模块类型,例如,jsjsxtstsx 或插件支持的其他模块类型。 您可以根据需要使用任意数量的 scriptlink

    +

    多页面应用程序 - MPA

    如果您正在构建多页面应用程序,只需配置多个 html,例如:

    -
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    export default defineConfig({
    input: {
    home: './index.html', // Home Page
    about: './about.html', // About Page
    // ... more pages
    }
    })
    +
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    export default defineConfig({
    input: {
    home: './index.html', // Home Page
    about: './about.html', // About Page
    // ... more pages
    }
    })

    Farm 将并行编译这些页面。

    -

    继承 html 模板

    +

    继承 html 模板

    Farm 支持通过使用 html.base 配置继承 html 模板,这在构建共享 html 的多页面应用程序时很有帮助。

    -
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });
    +
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });

    然后添加一个base.html,占位符{{children}}将被替换为子 html 的内容。

    -
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- 占位符将会在编译时替换成对应的子 html 的内容 -->
    {{children}}
    </body>
    </html>
    +
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- 占位符将会在编译时替换成对应的子 html 的内容 -->
    {{children}}
    </body>
    </html>

    继承./base.html

    -
    ./src/home.html
    <!-- 其他字段继承自../base.html -->
    <script src="./index.tsx"></script>
    +
    ./src/home.html
    <!-- 其他字段继承自../base.html -->
    <script src="./index.tsx"></script>
    \ No newline at end of file diff --git a/zh/docs/0.x/features/lazy-compilation/index.html b/zh/docs/0.x/features/lazy-compilation/index.html index a36093b6d..82a914137 100644 --- a/zh/docs/0.x/features/lazy-compilation/index.html +++ b/zh/docs/0.x/features/lazy-compilation/index.html @@ -8,25 +8,25 @@ - - - + + + -
    版本:0.15

    懒编译

    +
    版本:0.15

    懒编译

    当涉及到一个大项目时,您可能希望将它们分成小块并按需加载。 这可以通过动态导入来实现。

    -
    const page = React.lazy(() => import('./page')); // 延迟加载页面
    +
    const page = React.lazy(() => import('./page')); // 延迟加载页面

    默认情况下,Farm 会在开发时延迟编译这些动态导入,仅在模块真正执行时才编译它们。 延迟编译可以极大提速大型项目的编译。

    -
    备注

    对于生产构建,延迟编译始终被禁用。

    +
    备注

    对于生产构建,延迟编译始终被禁用。

    请注意,正确使用动态导入对于使懒编译更好地工作非常重要。 例如,如果你的一个页面有一个很大的依赖项,但是这个依赖项在这个页面渲染之前不会被使用,那么有必要确保这个大的依赖项是动态导入的,所以它不会被编译,直到页面执行。

    -

    配置延迟编译

    +

    配置延迟编译

    使用compilation.lazyCompilation来启用或禁用它:

    -
    farm.config.ts
    export default {
    compilation: {
    lazyCompilation: true,
    },
    };
    -

    懒编译如何工作

    +
    farm.config.ts
    export default {
    compilation: {
    lazyCompilation: true,
    },
    };
    +

    懒编译如何工作

    当启用延迟编译时,Farm 将首先分析您的所有动态导入,例如:

    -
    const page = React.lazy(() => import('./page'));
    +
    const page = React.lazy(() => import('./page'));

    Farm 会将 ./page 视为应该延迟编译的模块,并且不会编译它,相反,Farm 将为 ./page 返回一个虚拟占位符模块,如下所示:

    -
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // 返回一个promise,这个promise将在延迟编译完成后 resolve。
    let promise = Promise.resolve();

    // 模块已经在懒编译中
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // 请求开发服务器进行延迟编译
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    -

    上面的例子说明了虚拟占位符模块的基本结构。 当占位符执行时,它将请求开发服务器编译该模块及其依赖项。 从开发服务器获取延迟编译结果后,占位符模块会将这些更改修补到 Farm 的运行时模块系统。

    +
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // 返回一个promise,这个promise将在延迟编译完成后 resolve。
    let promise = Promise.resolve();

    // 模块已经在懒编译中
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // 请求开发服务器进行延迟编译
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    +

    上面的例子说明了虚拟占位符模块的基本结构。 当占位符执行时,它将请求开发服务器编译该模块及其依赖项。 从开发服务器获取延迟编译结果后,占位符模块会将这些更改修补到 Farm 的运行时模块系统。

    \ No newline at end of file diff --git a/zh/docs/0.x/features/minification/index.html b/zh/docs/0.x/features/minification/index.html index 217d6d005..abcfc1a3d 100644 --- a/zh/docs/0.x/features/minification/index.html +++ b/zh/docs/0.x/features/minification/index.html @@ -8,20 +8,20 @@ - - - + + + -
    版本:0.15

    压缩

    +
    版本:0.15

    压缩

    Farm 支持开箱即用的生产环境压缩,默认情况下会自动在production模式下启用。 可以通过compilation.minify选项启用或禁用。

    使用compilation.minify进行配置:

    -
    farm.config.ts
    export default {
    compilation: {
    minify: true
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    minify: true
    },
    };

    如果启用了压缩:

    • 对于js/ts模块,它将被压缩以及混淆,所有空白字符将被删除,变量等将被压缩。
    • 对于 css 和 html 模块,所有空格都将被删除。
    -
    备注

    Farm 底层使用swc minifier,swc minifier 的所有选项都可以在 Farm 中使用。

    +
    备注

    Farm 底层使用swc minifier,swc minifier 的所有选项都可以在 Farm 中使用。

    \ No newline at end of file diff --git a/zh/docs/0.x/features/partial-bundling/index.html b/zh/docs/0.x/features/partial-bundling/index.html index 5b7398ddd..57adf4362 100644 --- a/zh/docs/0.x/features/partial-bundling/index.html +++ b/zh/docs/0.x/features/partial-bundling/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    Partial Bundling

    +
    版本:0.15

    Partial Bundling

    Partial Bundling 是 Farm 用于打包模块的策略,与其他 bundler的做法类似,但 Farm 的 Partial Bundling 的目标不同。

    与其他 bundler 不同,Farm 不会尝试将所有内容打包在一起,然后使用splitChunks等优化将它们分开,相反,Farm 会将项目直接打包到多个输出文件中。 例如,如果启动一个 html 页面需要数百个模块,Farm 将尝试直接将它们打包到 20-30 个输出文件中。 Farm 将这种行为称为Partial Bundling

    Farm Partial Bundling 的目标是:

    @@ -22,8 +22,8 @@
  • 提高缓存命中率:当模块更改时,确保只有少数输出文件受到影响,以便更多缓存可以用于在线项目。
  • 对于传统的 bundler,我们可能很难配置复杂的splitChunksmanualChunks来实现上述目标,但在 Farm 中,通过Partial Bundling原生支持它。

    -
    提示

    请参阅 RFC-003 局部打包 以获取更多技术细节。

    -

    设计动机

    +
    提示

    请参阅 RFC-003 局部打包 以获取更多技术细节。

    +

    设计动机

    现在 Web 构建工具中处理模块的方法主要有两种:打包或使用原生 ESM。 但它们都有缺点:

    • 对于打包,bundler 的目标是将所有内容打包在一起,然后将它们拆分出来进行优化,但拆分通常很难配置,并且很难手动平衡资源加载性能和缓存命中率。
    • @@ -33,14 +33,14 @@

      设计动机

      后来我将Module Merging改名为Partial Bundling,因为我认为Partial Bundling可以更准确地表达我的想法。

      -

      Partial Bundling 规则

      +

      Partial Bundling 规则

      在本节中,我们将通过示例介绍Partial Bundling使用的基本规则。

      首先我们研究一个基本的 React 项目示例。 对于像下面这样的基本 react 项目,我们在入口脚本中导入 react 和 react-dom:

      -
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );
      +
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );

      打包结果将如下所示:

      -
      ./dist/
      ├── index_9c07.49b83356.js # 包含react-dom
      ├── index_a35f.0ac21082.js # 包含./index.tsx
      ├── index_b7e0.7ab9ca2d.js # 包含react及其依赖项
      ├── index_ce26.7f833381.css # 包含./index.scss
      └── index.html # 包含./index.html
      +
      ./dist/
      ├── index_9c07.49b83356.js # 包含react-dom
      ├── index_a35f.0ac21082.js # 包含./index.tsx
      ├── index_b7e0.7ab9ca2d.js # 包含react及其依赖项
      ├── index_ce26.7f833381.css # 包含./index.scss
      └── index.html # 包含./index.html

      默认情况下,Farm 会将项目打包为 5 个文件:

      • 2 个 js 文件来自 node_modules,包含 reactreact-dom 及其依赖项。
      • @@ -57,7 +57,7 @@

        Part
      • 输出文件大小应相似,默认最小资源大小应大于20KB:因为react-dom最大,超过100KB,所以它在一个单独的文件中,而 react 的依赖项小于20KB,被合并到同一个输出文件中。
      • 现在我们已经熟悉了Partial Bundling的基本规则,如果遇到部分打包的问题,可以使用上述规则来调试您的项目。 接下来我们将介绍如何配置 Partial Bundling

        -

        配置 Partial Bundling

        +

        配置 Partial Bundling

        Partial Bundling 支持很多选项,让用户自定义其行为。 所有选项如下:

        1. targetConcurrentRequests: Farm 尝试生成尽可能接近此配置值的资源数量,控制初始资源加载或动态资源加载的并发请求数量。
        2. @@ -82,27 +82,27 @@

        3. immutableModules: 匹配不可变模块的正则表达式数组
        4. immutableModulesWeight: 默认为0.8,不可变模块将拥有80%的请求数。 例如,如果targetConcurrentRequest为 25,则默认情况下不可变资源将采用25 * 80% = 20。 该选项是为了确保可变模块和不可变模块是隔离的,如果更改您的业务代码,node_modules下的代码不会受到影响。
        -
        备注

        您可以使用targetConcurrentRequeststargetMinSizetargetMaxSize来控制 Partial Bundling 的默认行为。 Farm 设置的默认值基于最佳实践,因此当您想要更改默认值时请确保有必要。

        -

        Grouping Modules

        +
        备注

        您可以使用targetConcurrentRequeststargetMinSizetargetMaxSize来控制 Partial Bundling 的默认行为。 Farm 设置的默认值基于最佳实践,因此当您想要更改默认值时请确保有必要。

        +

        Grouping Modules

        您可以使用groups将模块分组在一起,对于上面的基本React项目示例,使用以下配置将node_modules下的模块打包在一起:

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });

        我们添加一个带有nametestgroup item,将reactreact-dom分组在一起。 打包结果是:

        -
        ./dist/
        ├── index_499e.72cf733c.js # 包含`react`、`react-dom`以及node_modules下的所有其他文件
        ├── index_a35f.0ac21082.js # 包含 `./index.tsx`
        ├── index_ce26.7f833381.css # 包含 `./index.scss`
        └── index.html #包含`./index.html`
        +
        ./dist/
        ├── index_499e.72cf733c.js # 包含`react`、`react-dom`以及node_modules下的所有其他文件
        ├── index_a35f.0ac21082.js # 包含 `./index.tsx`
        ├── index_ce26.7f833381.css # 包含 `./index.scss`
        └── index.html #包含`./index.html`

        现在 node_modules 下的所有模块都打包到 index_499e.72cf733c.js 中。 请注意,groups并不强制打包所有与该组匹配的模块,一个group会生成多个output file,因为:

        1. 可变和不可变模块始终位于不同的输出文件中。 当可变模块和不可变模块都命中这个时,它们将处于不同的输出中。
        2. 当涉及多页面应用程序或 dynamic import 时,可能存在共享模块,这些模块会始终位于不同的输出文件中。

        如果需要强制打包指定的模块到一个文件中,可以使用enforceResources

        -

        Using enforceResources

        +

        Using enforceResources

        要将所有模块分组在一起并忽略所有其他条件,您可以使用enforceResources,例如:

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });

        will produce:

        -
        ./dist/
        ├── index.7f833381.css # 所有css模块都打包在一起
        ├── index.ba5550d9.js # 所有脚本模块都打包在一起
        └── index.html
        -
        注意

        enforceResources 会忽略 Farm 的所有内部优化,使用时要小心。

        -

        Configuring immutable modules

        +
        ./dist/
        ├── index.7f833381.css # 所有css模块都打包在一起
        ├── index.ba5550d9.js # 所有脚本模块都打包在一起
        └── index.html
        +
        注意

        enforceResources 会忽略 Farm 的所有内部优化,使用时要小心。

        +

        Configuring immutable modules

        使用immutableModules配置不可变模块,默认情况下,Farm 将其设置为node_modules/

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        immutableModules: ['node_modules/', '/global-constants']
        },
        },
        });
        -

        不可变模块会影响打包和传入的持久缓存,如果要更改它,请小心。

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ['node_modules/', '/global-constants']
    },
    },
    });
    +

    不可变模块会影响打包和传入的持久缓存,如果要更改它,请小心。

    \ No newline at end of file diff --git a/zh/docs/0.x/features/persistent-cache/index.html b/zh/docs/0.x/features/persistent-cache/index.html index c2667850d..d375b0d9c 100644 --- a/zh/docs/0.x/features/persistent-cache/index.html +++ b/zh/docs/0.x/features/persistent-cache/index.html @@ -8,22 +8,22 @@ - - - + + + -
    版本:0.15

    增量构建

    -
    提示

    v0.14.0起,Farm 支持通过持久缓存进行增量构建

    +
    版本:0.15

    增量构建

    +
    提示

    v0.14.0起,Farm 支持通过持久缓存进行增量构建

    从 v0.14.0 开始,Farm 支持将编译结果缓存到磁盘,这可以大大加快热启动/热构建的编译速度。 当启用persistentCache时,编译时间可以减少高达80%

    使用 examples/argo-pro 进行冷启动(无缓存)和热启动(有缓存)的性能比较:

    冷(无缓存)热(有缓存)差异
    开始1519ms371ms减少 75%
    构建3582ms562ms减少 84%
    -

    使用缓存

    +

    使用缓存

    使用compilation.persistentCache启用/禁用缓存:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    persistentCache: true
    }
    })
    -
    备注

    persistentCache: true 等于:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: 'node_modules/.farm/cache',
    // namespace of the cache
    namespace: 'farm-cache',
    buildDependencies: [
    'farm.config.ts',
    '@farmfe/core',
    '@farmfe/plugin-react'
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    }
    }
    })
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    persistentCache: true
    }
    })
    +
    备注

    persistentCache: true 等于:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: 'node_modules/.farm/cache',
    // namespace of the cache
    namespace: 'farm-cache',
    buildDependencies: [
    'farm.config.ts',
    '@farmfe/core',
    '@farmfe/plugin-react'
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    }
    }
    })

    persistentCache配置为false以禁用缓存。

    -

    缓存验证

    +

    缓存验证

    当以下条件尝试重用缓存时,缓存将被验证,如果以下任何条件发生变化,所有缓存将失效:

    如果您的缓存不起作用,请检查上述情况以找出原因。 如果缓存损坏,您还可以删除node_modules/.farm/cache来手动删除缓存。

    -

    构建依赖

    +

    构建依赖

    构建依赖项是可以影响编译过程或编译输出的依赖项,例如插件或配置文件。 如果这些依赖项中的任何一个发生更改,所有缓存都将失效。

    构建依赖项可以是包名称的文件路径,例如:

    -
    import { defineConfig } from '@farmfe/core';
    import path from 'node:path';

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), './plugins/my-plugin.js'),
    // a package name, note that this package must expose package.json
    'farm-plugin-custom-xxx'
    ]
    }
    })
    -
    备注

    默认情况下,包含所有配置文件及其依赖项。 但是如果你想添加一些额外的文件或依赖项来使缓存失效,你可以使用buildDependencies,一旦这些文件发生更改,所有缓存都将失效。

    -

    模块缓存关键策略

    +
    import { defineConfig } from '@farmfe/core';
    import path from 'node:path';

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), './plugins/my-plugin.js'),
    // a package name, note that this package must expose package.json
    'farm-plugin-custom-xxx'
    ]
    }
    })
    +
    备注

    默认情况下,包含所有配置文件及其依赖项。 但是如果你想添加一些额外的文件或依赖项来使缓存失效,你可以使用buildDependencies,一旦这些文件发生更改,所有缓存都将失效。

    +

    模块缓存关键策略

    Farm提供了2种策略来控制如何生成模块缓存密钥:

    • timestamp: 是否检查模块的时间戳,如果更新时间戳没有改变,则跳过该模块的构建,性能最佳。
    • hash: 加载和转换后是否检查内容哈希,如果内容没有改变,则跳过该模块的左侧构建。

    默认情况下,timestamphash均已启用。

    -

    插件注意事项

    +

    插件注意事项

    当启用timestamp时,所有构建阶段 hook(如loadtransform)都不会被调用。 因此,如果插件依赖于loadtransform,并且没有实现plugin_cache_loadedwrite_plugin_cache挂钩,则它可能无法按预期工作。 例如,如果一个插件在loadtransform中收集信息,并在finish钩子上发出它们,那么它应该实现plugin_cache_loadedwrite_plugin_cache钩子来加载和写入缓存,否则它将无法按预期工作 。

    -

    output.targetEnvnode时,Farm 会将timestamp设置为false

    +

    output.targetEnvnode时,Farm 会将timestamp设置为false

    \ No newline at end of file diff --git a/zh/docs/0.x/features/polyfill/index.html b/zh/docs/0.x/features/polyfill/index.html index 4f5fd0c3c..2432d91cd 100644 --- a/zh/docs/0.x/features/polyfill/index.html +++ b/zh/docs/0.x/features/polyfill/index.html @@ -8,21 +8,21 @@ - - - + + + -
    版本:0.15

    语法降级和 Polyfill

    +
    版本:0.15

    语法降级和 Polyfill

    默认情况下,Farm 将降级到ES5并在生产模式下自动注入polyfills

    -
    备注

    默认情况下,Farm 不会对 node_modules/ 下的模块进行转换并注入 polyfill,如果您需要为 node_modules/ 降级语法并注入 polyfill,您可以使用 compilation.presetEnv.include

    -

    配置 presetEnv

    +
    备注

    默认情况下,Farm 不会对 node_modules/ 下的模块进行转换并注入 polyfill,如果您需要为 node_modules/ 降级语法并注入 polyfill,您可以使用 compilation.presetEnv.include

    +

    配置 presetEnv

    您可以使用compilation.presetEnv来自定义语法降级和 polyfill。 使用 include 添加需要注入 polyfill 的额外模块

    -
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "Chrome >= 48"
    }
    }
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "Chrome >= 48"
    }
    }
    },
    };

    默认情况下,Farm 会将目标设置为> 0.25%, not dead。 如果你的项目不需要浏览器兼容性,你可以为targets设置一个更宽松的值,那么注入的 polyfills 就会更少,输出的资源大小也会更小。

    更多选项,请参阅 compilation.presetEnv

    -

    使用 script.target

    +

    使用 script.target

    script.target 也可以在生成代码时控制目标环境。 如果您想将项目降级到ES5,您应该同时设置:

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5'
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "> 0.25%, not dead"
    }
    }
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5'
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: "> 0.25%, not dead"
    }
    }
    },
    };
    \ No newline at end of file diff --git a/zh/docs/0.x/features/script/index.html b/zh/docs/0.x/features/script/index.html index 201934564..ec74e32d7 100644 --- a/zh/docs/0.x/features/script/index.html +++ b/zh/docs/0.x/features/script/index.html @@ -8,56 +8,56 @@ - - - + + + -
    版本:0.15

    Script

    +
    版本:0.15

    Script

    Farm 支持开箱即用地编译Js/Jsx/Ts/Tsx,并默认将Jsx/Tsx编译为 React。

    -
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }
    +
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }

    Farm 使用 SWC 来编译脚本,Farm 为脚本编译设置了合理的默认配置。 另外,您可以使用compilation.script来配置如何编译脚本文件。 有关详细信息,请参阅 compilation.script

    -

    配置 Swc 解析器

    +

    配置 Swc 解析器

    您可以通过compilation.script.parser配置 SWC 解析器。 请参阅 https://swc.rs/docs/configuration/compilation#jscparser。

    例如,如果你想启用装饰器,你可以设置compilation.script.parser.esConfig.decorators(如果模块是 TS,则设置 tsConfig.decorators):

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    };

    默认情况下,Farm 为.jsx|.tsx文件设置jsx: true。 其他字段默认为 SWC 的默认值。

    -

    配置目标执行环境

    +

    配置目标执行环境

    运行项目时使用compilation.script.target配置目标环境,Farm 将其默认设置为ESNext

    此选项可以与compilation.presetEnv一起使用,以针对旧浏览器优雅地降级您的项目。 例如,您可以将 target 设置为 ES5 并启用 presetEnv,那么您的项目将完全降级到 ES5。

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    };

    有关presetEnv的更多信息,请参阅 Polyfill

    -

    装饰器

    +

    装饰器

    装饰器默认不启用, 可以通过设置 compilation.script.parser.tsConfig.decoratorstrue 来启用装饰器。

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // 启用装饰器
    decorators: true,
    },
    },
    // 配置装饰器
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // 启用装饰器
    decorators: true,
    },
    },
    // 配置装饰器
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });

    Farm 提供了一个装饰器的示例,可以看 https://github.com/farm-fe/farm/tree/main/examples/decorators

    默认情况下, Farm 不会转译 node_modules 下的装饰器, 参考 compilation.script.decorators.excludes.

    -

    使用 SWC 插件

    +

    使用 SWC 插件

    SWC Plugins 可以直接在 Farm 中使用,例如我们在 Farm 中使用 swc-plugin-vue-jsx 来编译 vue jsx:

    -
    farm.config.ts
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };
    +
    farm.config.ts
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };

    有关更多详细信息,请参阅使用插件

    -

    Vite 风格的 import.meta.glob

    +

    Vite 风格的 import.meta.glob

    Farm 完整支持 Vite 风格的 import.meta.glob, 参考 glob import.

    例如:

    -
    const modules = import.meta.glob("./dir/*.js");
    +
    const modules = import.meta.glob("./dir/*.js");

    将会被编译成以下结果

    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };
    +
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };

    使用 { eager: true } 后:

    -
    const modules = import.meta.glob("./dir/*.js", { eager: true });
    +
    const modules = import.meta.glob("./dir/*.js", { eager: true });

    将会被编译成以下结果:

    -
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };
    +
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };

    支持数组形式:

    -
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);
    +
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);

    支持通过 ! 排除某些匹配:

    -
    const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    };
    -
    备注
      +
      const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
      +
      // code produced by Farm
      const modules = {
      "./dir/foo.js": () => import("./dir/foo.js"),
      };
      +
      备注
      • import.meta.glob 参数必须全部是字面量,不能使用表达式。
      • import.meta.glob 在编译时处理和转换,在运行时不存在。
      • -
    +
    \ No newline at end of file diff --git a/zh/docs/0.x/features/sourcemap/index.html b/zh/docs/0.x/features/sourcemap/index.html index 68b8c5c6e..4ad14a516 100644 --- a/zh/docs/0.x/features/sourcemap/index.html +++ b/zh/docs/0.x/features/sourcemap/index.html @@ -8,16 +8,16 @@ - - - + + + -
    版本:0.15

    Source Map

    +
    版本:0.15

    Source Map

    Farm 支持 Source Map,默认情况下自动启用。 可以通过选项启用或禁用 sourcemap。

    -
    备注

    Farm 默认不会为 node_modules 下的文件生成 sourcemap,如果你想为 node_modules 下的文件生成 sourcemap,请将 compilation.sourcemap 配置为all

    +
    备注

    Farm 默认不会为 node_modules 下的文件生成 sourcemap,如果你想为 node_modules 下的文件生成 sourcemap,请将 compilation.sourcemap 配置为all

    使用compilation.sourcemap配置 sourcemap 生成:

    -
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };

    所有选项如下:

    • true:只为不在node_modules下的文件生成 sourcemap,并生成单独的 sourcemap 文件
    • @@ -25,6 +25,6 @@
    • inline:只为不在node_modules下的文件生成 sourcemap,并将 sourcemap 内联到产物中,不生成单独的文件
    • all:为所有文件生成 sourcemap,并生成单独的 sourcemap 文件
    • all-inline:为所有文件生成 sourcemap,并将 sourcemap 内联到产品中,不生成单独的文件
    • -
    +
    \ No newline at end of file diff --git a/zh/docs/0.x/features/static/index.html b/zh/docs/0.x/features/static/index.html index e9b4ce206..613334656 100644 --- a/zh/docs/0.x/features/static/index.html +++ b/zh/docs/0.x/features/static/index.html @@ -8,33 +8,33 @@ - - - + + + -
    版本:0.15

    静态资源

    +
    版本:0.15

    静态资源

    v0.4 及以上支持 Farm 支持三种资源加载方式: url , inline , raw

    -

    以 URL 形式使用

    +

    以 URL 形式使用

    导入图片:

    -
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }
    +
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }

    导入图片时默认以 URL 的形式。 当使用 URL 形式导入图像时,图像将直接复制到输出目录,并且图像模块本身将被编译为 js 模块,如下所示:

    -
    export default '/rocket.<content hash>.svg'
    +
    export default '/rocket.<content hash>.svg'

    使用 compilation.output.assetsFilename 来配置你的资源名称。

    -

    内联

    +

    内联

    使用查询 ?inline 告诉 Farm 你想要内联你的资源,然后资源将被转换为 base64,例如:

    -
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    -

    原始字符串

    +
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    +

    原始字符串

    例如,使用查询?raw告诉 Farm 您要读取资产的原始字符串

    -
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    -

    相关配置

    +
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    +

    相关配置

    • 使用compilation.output.assetFileName来控制生产文件名
    • 使用compilation.assets.include将更多类型的文件视为资产模块。
    -
    export default {
    compilation: {
    output: {
    assetsFilename: 'assets/[resourceName].[hash].[ext]', // [] 里面的是 Farm 支持的全部占位符
    },
    assets: {
    include: ['txt'] // 额外静态资源类型
    }
    }
    }
    +
    export default {
    compilation: {
    output: {
    assetsFilename: 'assets/[resourceName].[hash].[ext]', // [] 里面的是 Farm 支持的全部占位符
    },
    assets: {
    include: ['txt'] // 额外静态资源类型
    }
    }
    }
    \ No newline at end of file diff --git a/zh/docs/0.x/features/tree-shake/index.html b/zh/docs/0.x/features/tree-shake/index.html index c0d4a6114..7cb910942 100644 --- a/zh/docs/0.x/features/tree-shake/index.html +++ b/zh/docs/0.x/features/tree-shake/index.html @@ -8,26 +8,26 @@ - - - + + + -
    版本:0.15

    Tree Shake

    +
    版本:0.15

    Tree Shake

    Farm 支持 Tree Shake,在默认 Production 环境下自动开启。通过 compilation.treeShake 选项可控制开启或者关闭。

    Tree Shake 时,会自动读取 package.json 中的 sideEffects 字段,有 sideEffect 的模块将不会进行 Tree Shake。

    -
    备注

    Farm 会将所有循环依赖的模块视作 sideEffect,不会进行 Tree Shake,请尽量避免项目中存在循环依赖。

    +
    备注

    Farm 会将所有循环依赖的模块视作 sideEffect,不会进行 Tree Shake,请尽量避免项目中存在循环依赖。

    Tree shake 示例:

    -
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    export b2 = "B2";
    +
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";
    export b2 = "B2";

    a.js 是入口,它导入了 b.js,经过 Tree Shaking,结果是:

    -
    a.js
    import { b1 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    +
    a.js
    import { b1 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";

    b2未使用,将在a.jsb.js中删除

    -

    配置 Tree Shake

    +

    配置 Tree Shake

    默认情况下,在生产模式下启用 Tree Shake,要禁用 Tree Shake,请使用compilation.treeShake

    -
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    -

    处理 Side Effects

    +
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    +

    处理 Side Effects

    当模块包含副作用时,Farm 不会对其应用 tree shake,并且其所有导入和导出都将被视为已使用。 Farm 会认为以下模块有副作用

    1. CommonJs 模块总是有副作用。
    2. @@ -37,16 +37,16 @@

      处理 S 5.入口模块总是有副作用。

    Example 1:

    -
    const a = require('./')
    module.exports = a;
    +
    const a = require('./')
    module.exports = a;

    CommonJs 模块总是有副作用。

    Example 2:

    -
    import a from './';

    a();
    +
    import a from './';

    a();

    a() 在全局范围内执行,我们将其视为副作用。

    Example 3:

    -
    // a.js
    import b from './b.js'

    // b.js
    import a from './a.js'
    +
    // a.js
    import b from './b.js'

    // b.js
    import a from './a.js'

    ab 是循环依赖,因此它们也将被视为副作用。

    Example 4:

    -
    package.json
    {
    "name": "my-package",
    "sideEffects": [
    "./global/**.ts"
    ]
    }
    -

    global/ 下的所有 ts 模块都被视为副作用。

    +
    package.json
    {
    "name": "my-package",
    "sideEffects": [
    "./global/**.ts"
    ]
    }
    +

    global/ 下的所有 ts 模块都被视为副作用。

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/community-plugins/index.html b/zh/docs/0.x/plugins/community-plugins/index.html index 74476e819..6d1d986ce 100644 --- a/zh/docs/0.x/plugins/community-plugins/index.html +++ b/zh/docs/0.x/plugins/community-plugins/index.html @@ -8,18 +8,18 @@ - - - + + + -
    版本:0.15

    社区插件

    +
    版本:0.15

    社区插件

    Farm 支持开箱即用的“Vite/Rollup”插件。 所以 Vite/Rollup 或者 unplugin 插件可以直接在 Farm 中使用。

    -
    提示

    如果您开发了兼容 Farm 的插件并且想在此处列出,欢迎 PR。

    +
    提示

    如果您开发了兼容 Farm 的插件并且想在此处列出,欢迎 PR。

    目前测试兼容的Vite/Rollup/unplugin插件如下:

    -

    Vite/Rollup Plugins

    +

    Vite/Rollup Plugins

    使用 farm.config.ts 中的 vitePlugins 来配置 Vite/Rollup 插件。

    -
    import { UserConfig } from '@farmfe/core';
    import vue from '@vitejs/plugin-vue';
    import vueJsx from '@vitejs/plugin-vue-jsx';

    const config: UserConfig = {
    vitePlugins: [
    vue(),
    vueJsx(),
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import vue from '@vitejs/plugin-vue';
    import vueJsx from '@vitejs/plugin-vue-jsx';

    const config: UserConfig = {
    vitePlugins: [
    vue(),
    vueJsx(),
    ]
    }
    -

    unplugin

    -
    备注

    目前,您可以在 Farm 中使用“unplugin/vite”进行“unplugin/rollup”。 当此 PR 合并到 unplugin 时,unplugin/farm 将可用。

    -
    import Icons from 'unplugin-icons/vite';
    import IconsResolver from 'unplugin-icons/resolver';
    import Components from 'unplugin-vue-components/rollup';
    import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
    import { FileSystemIconLoader } from 'unplugin-icons/loaders';

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: 'vue3',
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, svg =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    )
    },
    scale: 1,
    defaultClass: 'inline-block'
    }),
    Components({
    dts: 'src/typings/components.d.ts',
    types: [{ from: 'vue-router', names: ['RouterLink', 'RouterView'] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFIX })
    ]
    })
    ]
    }
    +

    unplugin

    +
    备注

    目前,您可以在 Farm 中使用“unplugin/vite”进行“unplugin/rollup”。 当此 PR 合并到 unplugin 时,unplugin/farm 将可用。

    +
    import Icons from 'unplugin-icons/vite';
    import IconsResolver from 'unplugin-icons/resolver';
    import Components from 'unplugin-vue-components/rollup';
    import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
    import { FileSystemIconLoader } from 'unplugin-icons/loaders';

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: 'vue3',
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, svg =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    )
    },
    scale: 1,
    defaultClass: 'inline-block'
    }),
    Components({
    dts: 'src/typings/components.d.ts',
    types: [{ from: 'vue-router', names: ['RouterLink', 'RouterView'] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFIX })
    ]
    })
    ]
    }

    Farm 支持所有 unplugin 插件:

    +
    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/js-dts/index.html b/zh/docs/0.x/plugins/official-plugins/js-dts/index.html index 657db1593..b920d4920 100644 --- a/zh/docs/0.x/plugins/official-plugins/js-dts/index.html +++ b/zh/docs/0.x/plugins/official-plugins/js-dts/index.html @@ -8,18 +8,18 @@ - - - + + + -
    版本:0.15

    @farmfe/js-plugin-dts

    +
    版本:0.15

    @farmfe/js-plugin-dts

    支持 .d.ts 文件。 该插件用于构建的工具库,为您的 ts 代码生成“.d.ts”

    -

    Installation

    -
    npm install @farmfe/js-plugin-dts
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    -

    Options

    -
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    +

    Installation

    +
    npm install @farmfe/js-plugin-dts
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    +

    Options

    +
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/js-less/index.html b/zh/docs/0.x/plugins/official-plugins/js-less/index.html index b522e4304..c4dde7aca 100644 --- a/zh/docs/0.x/plugins/official-plugins/js-less/index.html +++ b/zh/docs/0.x/plugins/official-plugins/js-less/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:0.15

    @farmfe/js-plugin-less

    +
    版本:0.15

    @farmfe/js-plugin-less

    支持 Less 编译

    -

    Installation

    -
    npm install @farmfe/js-plugin-less less
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    -

    Options

    -
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    lessOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-less less
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    +

    Options

    +
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    lessOptions

    请参阅Less 选项

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由 less 处理。 默认为“ {resolvedPaths: ['\\.less$'] }”用于加载,“{ moduleTypes: ['less'] }”用于转换。

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-less$'],
    moduleTypes: ['less']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    lessimplementation 包名称。 默认为 less

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    要添加到每个 less 文件的附加数据。示例:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }

    Less 文件:

    -
    index.less
    .foo {
    color: @primary-color;
    }
    +
    index.less
    .foo {
    color: @primary-color;
    }

    additionalData 将会被添加到这个文件的头部:

    -
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }
    +
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }

    函数形式用法:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/js-postcss/index.html b/zh/docs/0.x/plugins/official-plugins/js-postcss/index.html index 36a9ca678..128de221e 100644 --- a/zh/docs/0.x/plugins/official-plugins/js-postcss/index.html +++ b/zh/docs/0.x/plugins/official-plugins/js-postcss/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:0.15

    @farmfe/js-plugin-postcss

    +
    版本:0.15

    @farmfe/js-plugin-postcss

    支持 postcss 的前置编译工作

    -

    Installation

    -
    npm install @farmfe/js-plugin-postcss postcss
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    -

    Options

    -
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    -

    postcssLoadConfig

    +

    Installation

    +
    npm install @farmfe/js-plugin-postcss postcss
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    +

    Options

    +
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    +

    postcssLoadConfig

    Farm 使用 postcss-load-config 来加载 postcss 配置,因此您可以使用 postcss-load-config 的选项。 参考postcss-load-config

    示例:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由postcss处理。 默认为 { moduleTypes: ['css'] }

    -

    implementation

    -

    postcssimplementation 包名称。 默认为 postcss

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-css$'],
    moduleTypes: ['css']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    +

    postcssimplementation 包名称。 默认为 postcss

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/js-sass/index.html b/zh/docs/0.x/plugins/official-plugins/js-sass/index.html index d75173781..04254cd9d 100644 --- a/zh/docs/0.x/plugins/official-plugins/js-sass/index.html +++ b/zh/docs/0.x/plugins/official-plugins/js-sass/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:0.15

    @farmfe/js-plugin-sass

    +
    版本:0.15

    @farmfe/js-plugin-sass

    支持 sass 编译

    -

    Installation

    -
    npm install @farmfe/js-plugin-sass sass
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    -

    Options

    -
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    sassOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-sass sass
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    +

    Options

    +
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    sassOptions

    请参阅 sass 选项

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由 sass 处理。 对于 load 钩子默认为 {resolvedPaths: ['\\.(s[ac]ss)$'] }, 对于 transform 钩子默认为 { moduleTypes: ['sass'] }

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-sass$'],
    moduleTypes: ['sass']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    sassimplementation 包名称。 默认为 sass。 如果你想使用sass-embedded,可以将其设置为sass-embedded

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    -
    备注

    您应该手动安装 sass-embedded

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    +
    备注

    您应该手动安装 sass-embedded

    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    要添加到每个 sass 文件的附加数据。 例子:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }

    Sass 文件

    -
    index.scss
    .foo {
    color: @primary-color;
    }
    +
    index.scss
    .foo {
    color: @primary-color;
    }

    additionalData 将会被添加到这个文件的头部:

    -
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }
    +
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }

    函数形式用法:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    -

    globals

    -

    全局 sass 文件。 这些文件将添加到每个 sass 文件的顶部。 它与 additionalData 相同,但更方便。

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    +

    globals

    +

    全局 sass 文件。 这些文件将添加到每个 sass 文件的顶部。 它与 additionalData 相同,但更方便。

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/js-svgr/index.html b/zh/docs/0.x/plugins/official-plugins/js-svgr/index.html index cf49c578f..514d25777 100644 --- a/zh/docs/0.x/plugins/official-plugins/js-svgr/index.html +++ b/zh/docs/0.x/plugins/official-plugins/js-svgr/index.html @@ -8,29 +8,29 @@ - - - + + + -
    版本:0.15

    @farmfe/js-plugin-svgr

    +
    版本:0.15

    @farmfe/js-plugin-svgr

    支持将 SVG 编译成 React 组建

    -

    Installation

    -
    npm install @farmfe/js-plugin-svgr
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    -

    Options

    -
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    -

    svgrOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-svgr
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    +

    Options

    +
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    +

    svgrOptions

    请参阅 svgr 选项

    示例:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由 svgr 处理。 默认为 {resolvedPaths: ['\\.svg$'] }

    • resolvedPaths: 仅处理这些路径下的文件。 支持正则表达式。

    示例:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/overview/index.html b/zh/docs/0.x/plugins/official-plugins/overview/index.html index 30d401a63..9eed6721f 100644 --- a/zh/docs/0.x/plugins/official-plugins/overview/index.html +++ b/zh/docs/0.x/plugins/official-plugins/overview/index.html @@ -8,20 +8,20 @@ - - - + + + -
    版本:0.15

    插件概览

    +
    版本:0.15

    插件概览

    Farm官方提供了很多有用的插件,包括Rust插件和JS插件。 Rust 插件比 Js 插件快得多,我们建议尽可能使用 Rust 插件。

    -
    提示

    关于如何在 Farm 中使用插件,请参阅使用插件

    -

    Rust 插件

    +
    提示

    关于如何在 Farm 中使用插件,请参阅使用插件

    +

    Rust 插件

    -

    Js 插件

    +

    Js 插件

    -
    提示

    如果官方插件不能满足您的需求,您可以尝试社区插件

    +
    提示

    如果官方插件不能满足您的需求,您可以尝试社区插件

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/react/index.html b/zh/docs/0.x/plugins/official-plugins/react/index.html index 5de8ff956..28dfe7ef9 100644 --- a/zh/docs/0.x/plugins/official-plugins/react/index.html +++ b/zh/docs/0.x/plugins/official-plugins/react/index.html @@ -8,19 +8,19 @@ - - - + + + -
    版本:0.15

    @farmfe/plugin-react

    +
    版本:0.15

    @farmfe/plugin-react

    支持 React JsxReact Refresh

    -

    Installation

    -
    npm install @farmfe/plugin-react
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-react
    +

    Usage

    @farmfe/plugin-react 是一个 Rust 插件,你只需要在 farm.config.tsplugins 字段中配置它的包名。

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    -

    Options

    -

    请参阅SWC 转换 React 选项

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    +

    Options

    +

    请参阅SWC 转换 React 选项

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/official-plugins/sass/index.html b/zh/docs/0.x/plugins/official-plugins/sass/index.html index a8801c290..9d647b43a 100644 --- a/zh/docs/0.x/plugins/official-plugins/sass/index.html +++ b/zh/docs/0.x/plugins/official-plugins/sass/index.html @@ -8,23 +8,23 @@ - - - + + + -
    版本:0.15

    @farmfe/plugin-sass

    +
    版本:0.15

    @farmfe/plugin-sass

    支持 sass 编译

    -

    Installation

    -
    npm install @farmfe/plugin-sass
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-sass
    +

    Usage

    @farmfe/plugin-sass 是一个 Rust 插件,你只需要在 farm.config.tsplugins 字段中配置它的包名。

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    -

    Options

    -

    additionalData

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    +

    Options

    +

    additionalData

    • 类型: string
    -

    在每个 sass 文件头部添加额外内容,例如 @import '@/styles/variables.scss'; 语句。

    +

    在每个 sass 文件头部添加额外内容,例如 @import '@/styles/variables.scss'; 语句。

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/writing-plugins/js-plugin/index.html b/zh/docs/0.x/plugins/writing-plugins/js-plugin/index.html index de38e9291..da45d1d68 100644 --- a/zh/docs/0.x/plugins/writing-plugins/js-plugin/index.html +++ b/zh/docs/0.x/plugins/writing-plugins/js-plugin/index.html @@ -8,15 +8,15 @@ - - - + + + -
    版本:0.15

    Js Plugins

    +
    版本:0.15

    Js Plugins

    JS 插件就是一个纯粹的 Javascript 对象.

    -
    import { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: [
    // a plugin object
    {
    name: 'my-resolve-plugin',
    priority: 1000, // the priority of this plugin, the larger the value, the earlier the execution. Normally internal plugins is 100.
    resolve: {
    filters: { // Only execute the hook when following conditions satisfied
    sources: ['\\./index.ts'], // a regex array
    importers: ['None'],
    },
    executor: async (param) => { // this hook executor
    console.log(param); // resolve params
    // return the resolve result
    return {
    resolvedPath: 'virtual:my-module',
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // load, transform are similar to resolve, refer to their types
    ],
    };
    +
    import { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: [
    // a plugin object
    {
    name: 'my-resolve-plugin',
    priority: 1000, // the priority of this plugin, the larger the value, the earlier the execution. Normally internal plugins is 100.
    resolve: {
    filters: { // Only execute the hook when following conditions satisfied
    sources: ['\\./index.ts'], // a regex array
    importers: ['None'],
    },
    executor: async (param) => { // this hook executor
    console.log(param); // resolve params
    // return the resolve result
    return {
    resolvedPath: 'virtual:my-module',
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // load, transform are similar to resolve, refer to their types
    ],
    };

    可以使用闭包来导出插件,实现参数传递。

    -
    // my-resolve-plugin.ts
    export function myResolvePlugin(options: Options) {
    const { xx } = options

    return {
    name: 'my-resolve-plugin',
    resolve: {
    // ...
    }
    };
    }

    // farm.config.ts
    import { defineFarmConfig } from '@farmfe/core/dist/config';
    import { myResolvePlugin } from './myResolvePlugin.ts';

    export default defineFarmConfig({
    // ...
    plugins: [myResolvePlugin({ xx:'xx' })],
    });
    +
    // my-resolve-plugin.ts
    export function myResolvePlugin(options: Options) {
    const { xx } = options

    return {
    name: 'my-resolve-plugin',
    resolve: {
    // ...
    }
    };
    }

    // farm.config.ts
    import { defineFarmConfig } from '@farmfe/core/dist/config';
    import { myResolvePlugin } from './myResolvePlugin.ts';

    export default defineFarmConfig({
    // ...
    plugins: [myResolvePlugin({ xx:'xx' })],
    });
    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/writing-plugins/overview/index.html b/zh/docs/0.x/plugins/writing-plugins/overview/index.html index aabdaf887..8ef64e3a9 100644 --- a/zh/docs/0.x/plugins/writing-plugins/overview/index.html +++ b/zh/docs/0.x/plugins/writing-plugins/overview/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    概览

    +
    版本:0.15

    概览

    Farm 采用完全插件化的形式,提供了多种类型的插件来干预 Farm 的几乎所有行为,Farm 支持的主要插件类型分为以下几类:

    • 编译插件:干预、增强 Farm 的编译能力,支持使用 Rust(推荐)以及 Js 编写插件
    • @@ -21,11 +21,11 @@
    • Dev Server 插件:干预、增强 Farm 的 Dev Server,例如挂载更多变量,注册 middleware 等

    To use a Rust plugin, configuring plugins in farm.config.ts.

    -
    import { defineFarmConfig } from '@farmfe/core/dist/config';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    +
    import { defineFarmConfig } from '@farmfe/core/dist/config';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    Farm support both rust plugins and js plugins:

    +
    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html b/zh/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html index 0b8c4a5da..c09ca6762 100644 --- a/zh/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html +++ b/zh/docs/0.x/plugins/writing-plugins/runtime-plugin/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    Runtime Plugin

    -

    Working in progress.

    +
    版本:0.15

    Runtime Plugin

    +

    Working in progress.

    \ No newline at end of file diff --git a/zh/docs/0.x/plugins/writing-plugins/rust-plugin/index.html b/zh/docs/0.x/plugins/writing-plugins/rust-plugin/index.html index 73659d5a2..d3e6de3d6 100644 --- a/zh/docs/0.x/plugins/writing-plugins/rust-plugin/index.html +++ b/zh/docs/0.x/plugins/writing-plugins/rust-plugin/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    Rust Plugins

    -

    Rust Plugins are not stable for now...

    +
    版本:0.15

    Rust Plugins

    +

    Rust Plugins are not stable for now...

    \ No newline at end of file diff --git a/zh/docs/0.x/quick-start/index.html b/zh/docs/0.x/quick-start/index.html index 69e19e92f..94b43851f 100644 --- a/zh/docs/0.x/quick-start/index.html +++ b/zh/docs/0.x/quick-start/index.html @@ -8,39 +8,39 @@ - - - + + + -
    版本:0.15

    快速开始

    -
    备注

    Farm 需要 Node 16 及以上

    -

    在线体验

    -

    Edit Farm

    -

    1. 创建一个 Farm 项目

    -
    npm create farm@latest
    +
    版本:0.15

    快速开始

    +
    备注

    Farm 需要 Node 16 及以上

    +

    在线体验

    +

    Edit Farm

    +

    1. 创建一个 Farm 项目

    +
    npm create farm@latest

    然后按照提示操作即可!

    -
    备注

    您还可以通过附加命令行选项直接指定项目名称和要使用的模板:

    -
    npm create farm@latest my-vue-app --template react
    -

    2.启动项目

    +
    备注

    您还可以通过附加命令行选项直接指定项目名称和要使用的模板:

    +
    npm create farm@latest my-vue-app --template react
    +

    2.启动项目

    选择您喜欢的包管理器,安装依赖项,然后启动项目。

    -
    cd farm-project && npm start
    +
    cd farm-project && npm start

    默认情况下,该项目将从http://localhost:9000启动。

    -

    3. 配置项目

    +

    3. 配置项目

    该项目由项目根目录中的“farm.config.ts/js/mjs”文件进行配置。

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // 编译相关配置
    compilation: {
    input: {
    // 可以配置相对或者绝对路径
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Dev Server 相关配置
    server: {
    port: 9000,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    -
    备注

    Farm 配置的细节,参考 配置

    -

    4. 构建项目

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // 编译相关配置
    compilation: {
    input: {
    // 可以配置相对或者绝对路径
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Dev Server 相关配置
    server: {
    port: 9000,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    +
    备注

    Farm 配置的细节,参考 配置

    +

    4. 构建项目

    将 Farm 项目构建为生产环境可用的静态文件:

    -
    npm run build
    +
    npm run build

    构建后的产物默认降级到 ES5,同时会对产物进行压缩和 Tree Shake。如果希望本地预览 Build 的产物,可以执行 npm run preview 或者 npx farm preview

    -

    下一步

    +

    下一步

    -
    +
    \ No newline at end of file diff --git a/zh/docs/0.x/tutorials/build/index.html b/zh/docs/0.x/tutorials/build/index.html index 2ed67ec63..89bc5a9e1 100644 --- a/zh/docs/0.x/tutorials/build/index.html +++ b/zh/docs/0.x/tutorials/build/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    3. 使用 Farm 构建生产项目

    +
    版本:0.15

    3. 使用 Farm 构建生产项目

    默认情况下,Farm 已经为生产构建开启了以下功能的支持:

    • Tree Shake:裁剪和过滤无关模块和代码
    • @@ -21,19 +21,19 @@
    • 自动注入 Polyfill:Farm 默认对项目降级到 ES5,这意味着 Farm 构建的产物几乎可以在所有浏览器上运行
    • 自动进行局部打包: 依据依赖关系以及大小,将项目进行局部打包,对于每次资源请求,生成 25 个左右的资源,在保证并行加载性能的同时,尽可能提升缓存命中率
    -

    添加 build script

    +

    添加 build script

    package.json 中添加 build script:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build"
    },
    // ... ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build"
    },
    // ... ignore other fields
    }

    然后执行 npm run build 即可。

    -

    配置 Tree Shake 和压缩

    -

    Configure Tree Shake and compression

    +

    配置 Tree Shake 和压缩

    +

    Configure Tree Shake and compression

    -

    配置局部打包策略

    +

    配置局部打包策略

    +
    \ No newline at end of file diff --git a/zh/docs/0.x/tutorials/create/index.html b/zh/docs/0.x/tutorials/create/index.html index 63ff2a4d4..b6ad6be70 100644 --- a/zh/docs/0.x/tutorials/create/index.html +++ b/zh/docs/0.x/tutorials/create/index.html @@ -8,34 +8,34 @@ - - - + + + -
    版本:0.15

    1. 创建一个项目

    +
    版本:0.15

    1. 创建一个项目

    在本章中,我们将从头开始创建一个新的 Farm React 项目,并以开发模式启动它。

    -
    备注

    在本教程中,我们使用pnpm作为默认包管理器。 本章是从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令pnpm create farm

    -

    创建一个 Npm 包

    +
    备注

    在本教程中,我们使用pnpm作为默认包管理器。 本章是从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令pnpm create farm

    +

    创建一个 Npm 包

    首先我们执行pnpm init来创建一个新包。

    -
    mkdir farm-react && cd farm-react && pnpm init
    +
    mkdir farm-react && cd farm-react && pnpm init

    将自动生成package.json文件。

    -

    安装依赖项

    +

    安装依赖项

    安装必要的依赖项(react 以及 react-dom:):

    -
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D
    +
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D

    然后安装 Farm 相关依赖:

    -
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react
    +
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react

    React 项目需要 3 个包:

    • @farmfe/cli:该包提供了farm startfarm buildfarm Preview等命令,必须与@farmfe/core一起使用,不能单独使用。
    • @farmfe/core:该软件包提供编译Dev Server,为本地开发和产品构建提供所有必要的组件。 它导出CompilerDevServerWatcher,用于编译项目以开发模式服务项目监视项目的热模块替换
    • @farmfe/plugin-react:此包提供 React Jsx 编译和 React-refresh 支持。
    -

    创建 Farm 配置文件

    +

    创建 Farm 配置文件

    在项目根目录下创建一个farm.config.ts文件:

    -
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml
    +
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml

    并添加以下配置:

    -
    import { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig): UserConfig {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });
    +
    import { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig): UserConfig {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });

    对于上面的配置文件,我们使用了inputoutputplugins,这是Farm中最基本的配置。

    • input:配置入口点。 Farm 将根据条目编译并构建模块图。
    • @@ -43,20 +43,20 @@

    • plugins:配置farm插件,React、Vue SFC等所有扩展能力均由插件支持。 这里我们使用一个 Rust 插件(@farmfe/plugin-react)来支持编译 React jsx。

    查阅配置参考以获取更多选项。

    -
    备注

    在上面的例子中,我们将 input 配置为 index: './src/index.html',如果我们不配置 input,则默认为 index: './index.html'。 并且我们可以在input中配置多个条目,详细信息请参见多页面应用

    -

    创建一个入口Html和Js

    +
    备注

    在上面的例子中,我们将 input 配置为 index: './src/index.html',如果我们不配置 input,则默认为 index: './index.html'。 并且我们可以在input中配置多个条目,详细信息请参见多页面应用

    +

    创建一个入口Html和Js

    在项目根目录下创建 2 个文件 src/index.htmlsrc/index.tsx

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx

    src/index.html 的内容是:

    -
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    -
    备注

    请注意,我们必须添加至少一个<script>来引用脚本模块。

    +
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    +
    备注

    请注意,我们必须添加至少一个<script>来引用脚本模块。

    src/index.tsx 的内容是:

    -
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    -

    Start Your Farm Project!

    +
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    +

    Start Your Farm Project!

    现在一切都准备好了,将启动脚本添加到您的package.json中:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }

    然后运行npm start,如果 Farm 输出以下消息,则意味着您的项目已成功启动:

    -
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    -

    在浏览器中打开http://localhost:9000

    +
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    +

    在浏览器中打开http://localhost:9000

    \ No newline at end of file diff --git a/zh/docs/0.x/tutorials/overview/index.html b/zh/docs/0.x/tutorials/overview/index.html index 4550418c4..70a882fde 100644 --- a/zh/docs/0.x/tutorials/overview/index.html +++ b/zh/docs/0.x/tutorials/overview/index.html @@ -8,14 +8,14 @@ - - - + + + -
    版本:0.15

    概述

    +
    版本:0.15

    概述

    在本教程中,我们将从头开始创建一个 Farm React 项目,并介绍如何添加有用的组件库和 Farm 插件。

    -
    备注

    Vue项目也得到了Farm的全力支持。 Farm中可以直接使用Vite@vitejs/plugin-vue。 Farm 与大多数 vite 插件兼容,并且可以开箱即用。

    +
    备注

    Vue项目也得到了Farm的全力支持。 Farm中可以直接使用Vite@vitejs/plugin-vue。 Farm 与大多数 vite 插件兼容,并且可以开箱即用。

    你将学习:

    • 如何从头开始构建一个生产就绪的 Farm React 项目。 我们将介绍如何添加流行组件
    • @@ -23,13 +23,13 @@
    • Farm的日常配置和常用插件。

    我们的目标是通过本教程简化您使用 Farm 生态系统的开发体验。 如果您想从其他工具迁移到 Farm,它也会很有帮助。

    -
    备注

    本教程是从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令pnpm create farm

    +
    备注

    本教程是从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令pnpm create farm

    跟着我们的教程,开启你的超快农场开发之旅吧!

    -
    备注

    本教程的源代码在Farm 教程仓库

    +
    备注

    本教程的源代码在Farm 教程仓库

    \ No newline at end of file diff --git a/zh/docs/0.x/tutorials/start/index.html b/zh/docs/0.x/tutorials/start/index.html index 11b916697..ffff15487 100644 --- a/zh/docs/0.x/tutorials/start/index.html +++ b/zh/docs/0.x/tutorials/start/index.html @@ -8,77 +8,77 @@ - - - + + + -
    版本:0.15

    2. 使用 Farm 开发项目

    +
    版本:0.15

    2. 使用 Farm 开发项目

    在本章中,我们将介绍常用的配置和插件来帮助您使用 Farm 构建复杂的生产就绪的 Web 项目。

    -
    备注

    本章重用我们在第 1 章中创建的项目

    +
    备注

    本章重用我们在第 1 章中创建的项目

    我们将逐步设置我们的项目: 1.引入流行的组件库antd,并为其配置必要的插件 2.介绍postcss、svgr、less等常用插件。 3. 配置代理和其他有用的开发服务器选项

    -

    引入组件库

    +

    引入组件库

    开发 Web 项目时常常需要用到组件库,本节我们将使用ant-design作为 demo 来展示如何在 Farm 中添加组件库。

    我们这里使用ant design只是为了说明,你可以引入任何组件库。 对于组件库选择,Farm 没有任何倾向。

    首先我们需要将 ant-design 安装到我们的项目中:

    -
    pnpm add antd # 在项目根目录下执行
    +
    pnpm add antd # 在项目根目录下执行

    Ant Design需要Sass,所以我们还需要安装编译 scss 的插件。 我们可以使用 Farm 官方提供的 Rust 插件 @farmfe/plugin-sass

    -
    pnpm add @farmfe/plugin-sass -D
    +
    pnpm add @farmfe/plugin-sass -D

    然后将此插件添加到plugins中:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ]
    });
    +
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ]
    });

    现在 Antd 已经准备好了,将其添加到我们的项目中:

    -
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    antd DatePicker: <DatePicker />
    </div>
    );
    +
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    antd DatePicker: <DatePicker />
    </div>
    );

    然后执行npm start并在浏览器中打开http://localhost:9000

     

    -

    给项目添加 CSS 样式

    +

    给项目添加 CSS 样式

    现在我们已经成功地将组件库引入到我们的项目中。 接下来我们将学习如何给项目添加样式。

    -

    创建基本的管理站点布局

    +

    创建基本的管理站点布局

    首先,我们在index.tsx旁边创建一个新的app.tsx

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx

    app.tsx的内容(来自Antd官网的演示代码):

    -
    app.tsx
    import React from 'react';
    import { Breadcrumb, Layout, Menu, theme } from 'antd';

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: 'flex', alignItems: 'center' }}>
    <div className="demo-logo" />
    <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: '0 50px' }}>
    <Breadcrumb style={{ margin: '16px 0' }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div className="site-layout-content" style={{ background: colorBgContainer }}>
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
    </Layout>
    );
    };

    export default App;
    +
    app.tsx
    import React from 'react';
    import { Breadcrumb, Layout, Menu, theme } from 'antd';

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: 'flex', alignItems: 'center' }}>
    <div className="demo-logo" />
    <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: '0 50px' }}>
    <Breadcrumb style={{ margin: '16px 0' }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div className="site-layout-content" style={{ background: colorBgContainer }}>
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
    </Layout>
    );
    };

    export default App;

    然后将 index.tsx 修改为:

    -
    index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import App from './app';
    // import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );

    +
    index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import App from './app';
    // import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );

    然后我们得到一个基本的管理站点布局:

    -

    使用 CSS Modules

    +

    使用 CSS Modules

    Farm 开箱即用地支持css modules,默认情况下,Farm 会将任何.module.(css|scss|less)视为css 模块。 首先我们创建一个app.module.scss

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx

    Content of app.module.scss:

    -
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }
    +
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }

    然后在app.tsx中导入app.module.scss并保存:

    -
    import styles from './app.module.scss';
    // ...
    +
    import styles from './app.module.scss';
    // ...

    然后你的页面应该更新成如下:

    -

    使用 CSS 预处理器

    +

    使用 CSS 预处理器

    Farm 为 postcss(@farmfe/js-plugin-postcss) 和 less(@farmfe/js-plugin-less) 提供了官方 js 插件(在上文中,我们已经安装了 sass 插件(@farmfe/plugin-sass))。

    要使用postcss,首先我们需要安装插件:

    -
    pnpm add -D @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/js-plugin-postcss

    然后在farm.config.tsplugins中配置它:

    -
    farm.config.ts
    // ...
    import farmPluginPostcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass',
    farmPluginPostcss()
    ]
    });
    +
    farm.config.ts
    // ...
    import farmPluginPostcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass',
    farmPluginPostcss()
    ]
    });

    现在 Farm 完全支持 postcss,我们不会在这里介绍 postcss 细节,请参阅 postcss 文档以获取更多详细信息。

    -
    提示

    请参阅 使用 Farm 插件 了解有关 Farm 插件的更多信息。

    -

    配置 Alias 以及 Externals

    +
    提示

    请参阅 使用 Farm 插件 了解有关 Farm 插件的更多信息。

    +

    配置 Alias 以及 Externals

    Alias 和 externals 是最常用的配置之一, 在 Farm 中,可以使用 compilation.resolve.aliascompilation.externals 配置项:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '@/': path.join(process.cwd(), 'src')
    },
    externals: [
    'node:fs'
    ]
    }
    }
    // ...
    });
    -

    配置开发服务器

    +
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '@/': path.join(process.cwd(), 'src')
    },
    externals: [
    'node:fs'
    ]
    }
    }
    // ...
    });
    +

    配置开发服务器

    您可以在Farm Dev Server Config中找到服务器配置。

    -

    常用配置

    +

    常用配置

    配置示例:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有开发服务器选项都在 server 下
    server: {
    open: true,
    port: 9001,
    hmr: {
    // 配置Websocket的监听端口
    port: 9801
    host: 'localhost',
    // 配置文件监听时要忽略的文件
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有开发服务器选项都在 server 下
    server: {
    open: true,
    port: 9001,
    hmr: {
    // 配置Websocket的监听端口
    port: 9801
    host: 'localhost',
    // 配置文件监听时要忽略的文件
    ignores: ['auto_generated/*']
    }
    //...
    }
    });

    对于上面的示例,我们使用了以下选项:

    • 打开:自动打开指定端口的浏览器
    • 端口:将开发服务器端口设置为“9001”
    • hmr:设置 hmr 端口和监视文件,我们忽略 auto_generate 目录下的文件更改。
    -

    Setup Proxy

    +

    Setup Proxy

    配置服务器代理。基于 http-proxy 实现,具体选项参考其文档,示例:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });

    \ No newline at end of file diff --git a/zh/docs/0.x/using-plugins/index.html b/zh/docs/0.x/using-plugins/index.html index 7d6f1e844..115abf7c1 100644 --- a/zh/docs/0.x/using-plugins/index.html +++ b/zh/docs/0.x/using-plugins/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    使用插件

    +
    版本:0.15

    使用插件

    Farm支持4种插件:

    • Farm Compilation Plugins:支持 Rust 插件和 Js 插件,采用 rollup 风格的 hooks。
    • @@ -21,66 +21,66 @@
    • Farm Runtime Plugin:为 Farm 的运行时系统添加功能。
    • Swc 插件:Farm 开箱即用支持 Swc 插件。
    -
    提示

    如何编写自己的插件,请参考插件

    -

    Farm 编译插件

    +
    提示

    如何编写自己的插件,请参考插件

    +

    Farm 编译插件

    首先,安装您需要的插件,例如:

    -
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss

    使用 plugins 配置 Farm 编译插件:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust插件,配置其包名
    "@farmfe/plugin-sass",
    // JS插件,配置插件对象
    farmPostcssPlugin()
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust插件,配置其包名
    "@farmfe/plugin-sass",
    // JS插件,配置插件对象
    farmPostcssPlugin()
    ],
    });

    Farm编译插件有2种:

    • Rust Plugins:用 Rust 编写,具有最佳性能。
    • Js Plugins:用JS/TS编写,用于兼容当前的JS生态系统
    -

    使用 Rust 插件

    +

    使用 Rust 插件

    使用 package name 来配置 Rust 插件,例如:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    "@farmfe/plugin-sass",
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    "@farmfe/plugin-sass",
    ],
    });

    对于上面的例子,Farm 将解析包 @farmfe/plugin-sass 并将其视为 Farm Rust 插件。

    如果要为 Rust 插件配置选项,可以使用数组语法,如[packageName, optionsObject],例如:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // 使用数组语法来配置 Rust 插件
    [
    // Rust 插件的名称
    "@farmfe/plugin-sass",
    // Rust 插件的选项
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // 使用数组语法来配置 Rust 插件
    [
    // Rust 插件的名称
    "@farmfe/plugin-sass",
    // Rust 插件的选项
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });

    目前 Farm 官方支持 2 个 Rust 插件:

    • @farmfe/plugin-react:Farm rust 插件,用于 React jsx 编译和 React-refresh 注入。
    • @farmfe/plugin-sass:用于 scss 文件编译的 Farm rust 插件,内部使用 sass-embedded
    -
    提示

    要了解有关 rust 插件的更多信息,请参阅 Rust 插件

    -

    使用 Js 插件

    +
    提示

    要了解有关 rust 插件的更多信息,请参阅 Rust 插件

    +

    使用 Js 插件

    Farm JS 插件是一个以方法为钩子的 JS 对象,例如:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    farmPostcssPlugin({
    // ... 配置 postcss 选项
    })
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    farmPostcssPlugin({
    // ... 配置 postcss 选项
    })
    ],
    });

    farmPostcssPlugin()返回一个插件对象,您可以通过其参数传递任何 postcss 选项。

    您可以使用priority来控制插件的顺序,例如:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });

    内部插件的优先级都是100,如果想让插件先执行,就设置大于100,否则设置小于100。

    如果你想快速添加 Farm JS 插件,只需配置一个插件对象即可:

    -
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // 配置自定义插件
    {
    // 插件名称,必填
    name: 'my-first-farm-plugin',
    // 这个插件的优先级,值越大先执行,默认100。
    priority: 1000,
    // 定义一个加载钩子来确定如何加载模块
    load: {
    // 为了提高性能,如果模块与过滤器不匹配,将被跳过。
    filters: {
    // 仅对 .png 文件执行。
    resolvedPaths: ['\\.txt$']
    },
    // 该钩子的执行回调
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    -
    注意

    Farm 中的 js 插件需要 filters。 因为Js Plugin实在是太慢了,我们应该尽量避免执行它。配置 filters 后,对于那些不符合过滤器的模块,Farm 根本不会为它们触发 js 插件钩子! 这意味着 Farm 只在 Rust 侧就能安全、并发地进行处理,以最大化提升编译性能。

    -
    提示

    了解更多关于 Farm Js 插件的信息,请参考 JS 插件

    -

    使用 Vite/Rollup/Unplugin 插件

    +
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // 配置自定义插件
    {
    // 插件名称,必填
    name: 'my-first-farm-plugin',
    // 这个插件的优先级,值越大先执行,默认100。
    priority: 1000,
    // 定义一个加载钩子来确定如何加载模块
    load: {
    // 为了提高性能,如果模块与过滤器不匹配,将被跳过。
    filters: {
    // 仅对 .png 文件执行。
    resolvedPaths: ['\\.txt$']
    },
    // 该钩子的执行回调
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    +
    注意

    Farm 中的 js 插件需要 filters。 因为Js Plugin实在是太慢了,我们应该尽量避免执行它。配置 filters 后,对于那些不符合过滤器的模块,Farm 根本不会为它们触发 js 插件钩子! 这意味着 Farm 只在 Rust 侧就能安全、并发地进行处理,以最大化提升编译性能。

    +
    提示

    了解更多关于 Farm Js 插件的信息,请参考 JS 插件

    +

    使用 Vite/Rollup/Unplugin 插件

    Farm 兼容 Vite 插件,Vite 插件可以直接在 Farm 中配置使用。 首先需要安装 vite 插件,例如:

    -
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D
    +
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D

    然后就可以通过farm.config.ts中的vitePlugins直接使用vite插件了。

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // 配置vite插件
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // 配置vite插件
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });

    为了提高 vite 插件的性能,您可以使用返回过滤器函数语法,例如:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // // 使用Farm 中 Vite 插件的函数语法
    function configureVitePluginVue() {
    // 返回插件及其过滤器
    return {
    // 使用 vue 插件
    vitePlugin: vue(),
    // 为其配置过滤器。 不匹配的模块路径将被跳过。
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    vitePlugins: [
    configureVitePluginVue()
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // // 使用Farm 中 Vite 插件的函数语法
    function configureVitePluginVue() {
    // 返回插件及其过滤器
    return {
    // 使用 vue 插件
    vitePlugin: vue(),
    // 为其配置过滤器。 不匹配的模块路径将被跳过。
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    vitePlugins: [
    configureVitePluginVue()
    ]
    });

    使用 unplugin:

    -
    pnpm add unplugin-auto-import unplugin-vue-components -D
    +
    pnpm add unplugin-auto-import unplugin-vue-components -D

    vitePlugins 中配置,通过 unplugin/vite 或者 unplugin/rollup 支持:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    -
    备注

    当前可用 unplugin/vite 或者 unplugin/rollup. unplugin/farm这个 PR 合进 unplugin 后可用

    -

    Farm 运行时插件

    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    +
    备注

    当前可用 unplugin/vite 或者 unplugin/rollup. unplugin/farm这个 PR 合进 unplugin 后可用

    +

    Farm 运行时插件

    Farm有一个运行时模块系统来控制如何加载和执行模块。 配置 compilation.runtime.plugins 以添加更多运行时插件,例如:

    -
    export default defineConfig({
    compilation: {
    // 配置 Farm 运行时模块系统
    runtime: {
    plugins: [
    // 运行时插件包
    require.resolve('farm-plugin-runtime-mock'),
    // 本地运行时插件
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });
    +
    export default defineConfig({
    compilation: {
    // 配置 Farm 运行时模块系统
    runtime: {
    plugins: [
    // 运行时插件包
    require.resolve('farm-plugin-runtime-mock'),
    // 本地运行时插件
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });

    您必须配置指向运行时插件条目的路径。 推荐使用绝对路径以避免路径问题。

    -
    提示

    要了解有关运行时插件的更多信息,请参阅运行时插件

    -

    使用 SWC 插件

    +
    提示

    要了解有关运行时插件的更多信息,请参阅运行时插件

    +

    使用 SWC 插件

    Swc Plugin 也可以直接在Farm中使用,配置compilation.script.plugins来添加SWC插件,例如:

    -
    import jsPluginVue from '@farmfe/js-plugin-vue';

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [{
    //swc插件的包名
    name: 'swc-plugin-vue-jsx',
    // 该swc插件的选项
    options: {
    "transformOn": true,
    "optimize": true
    },
    // 当过滤器匹配时插件执行。
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    };
    +
    import jsPluginVue from '@farmfe/js-plugin-vue';

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [{
    //swc插件的包名
    name: 'swc-plugin-vue-jsx',
    // 该swc插件的选项
    options: {
    "transformOn": true,
    "optimize": true
    },
    // 当过滤器匹配时插件执行。
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    };

    数组的每个插件项包含三个字段:

    • name:swc插件的包名
    • options:传递给swc插件的配置项
    • filters:执行插件的哪些模块,必须配置,支持resolvedPathsmoduleTypes这两个过滤项,如果两者同时指定,则取并集。
    -
    备注

    SWC 插件可能与 Farm 使用的 SWC 版本不兼容。 如果出现错误,请尝试升级插件。

    +
    备注

    SWC 插件可能与 Farm 使用的 SWC 版本不兼容。 如果出现错误,请尝试升级插件。

    \ No newline at end of file diff --git a/zh/docs/0.x/why-farm/index.html b/zh/docs/0.x/why-farm/index.html index 1b3103d31..250a53017 100644 --- a/zh/docs/0.x/why-farm/index.html +++ b/zh/docs/0.x/why-farm/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:0.15

    为什么需要 Farm?

    +
    版本:0.15

    为什么需要 Farm?

    随着 web 项目规模的扩大,构建性能已经成为主要瓶颈,对于一个庞大的项目,使用 webpack 编译可能需要 10min 甚至更多,一次 hmr 更新可能需要 10s 甚至更多,严重降低了研发效率。

    因此我们急需极速的构建工具,解决项目编译性能问题。然后 vite/snowpack 这样的 unbundled 工具应运而生,此类工具主要有下面三个特性:

      @@ -28,9 +28,9 @@
    1. 而 Vite 在 dev 上之所以这么快,esbuild 功不可没,它是用 go 编写的。 Go 利用了原生平台的优势,远快于 Js。
    2. 事实上,我们真正需要的是一个快速、强大、一致的 Web 构建工具,可以在解决上述问题的基础上,提供更加极致的编译效率。因此我们开发了 Farm。

      -
      备注

      Farm 的设计主要都是针对 web 浏览器场景(包括 pc、移动、webview 等等),期望从构建速度到资源加载速度全方面提升 web 性能。因此 Farm 不会尝试成为一个传统意义上的通用打包器,Farm 的打包只是为了减少资源请求时的模块数量。

      +
      备注

      Farm 的设计主要都是针对 web 浏览器场景(包括 pc、移动、webview 等等),期望从构建速度到资源加载速度全方面提升 web 性能。因此 Farm 不会尝试成为一个传统意义上的通用打包器,Farm 的打包只是为了减少资源请求时的模块数量。

      不过 Farm 不仅仅是一个用 Rust 重写的打包工具,它还有很多强大且先进的设计:

      -

      Farm 设计理念

      +

      Farm 设计理念

      • 性能优先:一切都会用 Rust 编写,只有少数不是性能瓶颈的部分会用 JS 编写
      • 一致性:默认情况下确保开发和生产完全相同,您在开发中看到的将与您在生产中得到的相同。
      • @@ -39,6 +39,6 @@

        Farm 设
      • 兼容性:Farm 将适用于旧版 (ES5) 和现代浏览器。
      • Rollup 风格的插件系统:轻松创建自己的插件,并轻松从 rollup/vite/webpack 迁移您的插件/项目。
      -

      Farm 的目标是成为真正的下一代构建工具,快速、强大、一致,并为 Web 开发人员提供最佳的开发体验。

    +

    Farm 的目标是成为真正的下一代构建工具,快速、强大、一致,并为 Web 开发人员提供最佳的开发体验。

    \ No newline at end of file diff --git a/zh/docs/advanced/minification/index.html b/zh/docs/advanced/minification/index.html index 48757c0b4..1fae22537 100644 --- a/zh/docs/advanced/minification/index.html +++ b/zh/docs/advanced/minification/index.html @@ -8,19 +8,19 @@ - - - + + + -
    版本:1.0.0

    产物压缩

    +
    版本:1.0.0

    产物压缩

    Farm 支持开箱即用的生产压缩,默认情况下在生产中自动启用,可以通过compilation.minify 选项启用或禁用。

    -
    farm.config.ts
    export default {
    compilation: {
    // enable minification for both development and production
    minify: true,
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    // enable minification for both development and production
    minify: true,
    },
    };

    如果启用压缩:

    • 对于 js/ts 模块,代码将被compressedmangled,所有空白字符将被删除.
    • 对于css和html模块,所有空格都将被删除
    -
    备注

    Farm 使用 swc minifier,有关详细选项,请参阅compilation.minify

    +
    备注

    Farm 使用 swc minifier,有关详细选项,请参阅compilation.minify

    \ No newline at end of file diff --git a/zh/docs/advanced/partial-bundling/index.html b/zh/docs/advanced/partial-bundling/index.html index ed786cc3a..22ca176b1 100644 --- a/zh/docs/advanced/partial-bundling/index.html +++ b/zh/docs/advanced/partial-bundling/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:1.0.0

    局部打包

    +
    版本:1.0.0

    局部打包

    局部打包(Partial Bundling)是 Farm 用来打包模块的策略,类似于其他打包工具,但 Farm 的 局部打包 目标不同。

    与其它打包工具不同,Farm不会尝试将所有内容打包在一起,而是使用像 splitChunks 之类的优化策略将其拆分出来,相反,Farm会将项目直接捆打包成多个输出文件。例如,如果需要数百个模块来启动一个html页面,Farm将尝试将它们直接打包成20到30个输出文件。Farm将这种行为称为局部打包

    Farm局部打包的目标是:

    @@ -23,8 +23,8 @@

    对于传统打包工具,我们可能很难通过复杂的 splitChunksmanualChunks 配置来实现上述目标,但是 Farm 原生支持局部打包

    请注意,默认的打包策略是为浏览器设计的,但它也适用于 Node.js。 如果想要更改 Node.js 的打包策略,请尝试配置局部打包

    -
    提示

    请参考 RFC-003 Partial Bundling 局部打包以获取更多技术细节。

    -

    动机

    +
    提示

    请参考 RFC-003 Partial Bundling 局部打包以获取更多技术细节。

    +

    动机

    目前,Web构建工具处理模块的主要方法有两种:完全打包或原生ESM。但它们都有缺点:

    • 对于完全打包,打包工具旨在将所有内容打包在一起,然后拆分出来进行优化,但拆分通常难以配置,手动平衡资源加载性能和缓存命中率很难。
    • @@ -34,14 +34,14 @@

      动机局部打包规则

      +

      局部打包规则

      在这一节中,我们将通过示例介绍局部打包的基本规则。

      首先,我们来看一个基本的React项目示例。对于一个基本的React项目,我们只在入口文件中导入react和react-dom:

      -
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );
      +
      index.tsx
      import React from 'react';
      import { createRoot } from 'react-dom/client';
      import './index.scss';

      const container = document.querySelector('#root');
      const root = createRoot(container);

      root.render(
      <>
      <div>Index page</div>
      </>
      );

      打包结果将如下所示:

      -
      ./dist/
      ├── index_9c07.49b83356.js # contains react-dom
      ├── index_a35f.0ac21082.js # contains ./index.tsx
      ├── index_b7e0.7ab9ca2d.js # contains react and its dependencies
      ├── index_ce26.7f833381.css $ contains ./index.scss
      └── index.html # contains ./index.html
      +
      ./dist/
      ├── index_9c07.49b83356.js # contains react-dom
      ├── index_a35f.0ac21082.js # contains ./index.tsx
      ├── index_b7e0.7ab9ca2d.js # contains react and its dependencies
      ├── index_ce26.7f833381.css $ contains ./index.scss
      └── index.html # contains ./index.html

      默认情况下,Farm会将你的项目打包成5个文件:

      • 2个js文件来自 node_modules ,包含 reactreact-dom 其依赖项。
      • @@ -58,14 +58,14 @@

        局部打
      • 输出文件应具有相似的大小,最小资源大小应默认大于20KB: 因为 react-dom 是最大的,超过100KB,所以它位于单独的文件中,而 react 及其依赖项小于20KB,因此被合并到同一输出文件中。
      • 现在我们已经熟悉了局部打包的基本规则,如果遇到局部打包问题,请使用上述规则调试您的项目。接下来,我们将介绍如何配置局部打包。

        -

        配置局部打包

        -

        两种配置方法

        +

        配置局部打包

        +

        两种配置方法

        有两种不同的方式来控制打包:

        • groups: 告诉Farm您希望将这些模块尽可能地打包在一起,但由于Farm的优化策略,这并不是强制执行的。请参阅模块分组以了解此方法。
        • enforceResources: 告诉Farm您希望这些模块始终打包在一起,忽略所有其他优化策略约束。请参阅使用 enforceResources 以了解此方法。
        -

        局部打包选项

        +

        局部打包选项

        局部打包支持许多选项,使用户可以自定义其行为。所有选项如下:

        1. targetConcurrentRequests: Farm尝试为初始资源加载或动态资源加载生成尽可能接近此配置值的资源数量。
        2. @@ -90,41 +90,41 @@

          局部打
        3. immutableModules: 匹配不可变模块的正则表达式数组。
        4. immutableModulesWeight: 默认为0.8,不可变模块将具有80%的请求数量。例如,如果 targetConcurrentRequest 为25,则不可变资源将默认为 25 * 80% = 20 。此选项是为了确保可变和不可变模块是隔离的,如果您更改了业务代码,node_modules下的代码将不会受到影响。
        -
        备注

        通常,您可以使用 targetConcurrentRequeststargetMinSizetargetMaxSize 来控制局部打包的默认行为。Farm设置的默认值基于最佳实践,因此请确认是否必须修改默认值。

        -

        模块分组

        +
        备注

        通常,您可以使用 targetConcurrentRequeststargetMinSizetargetMaxSize 来控制局部打包的默认行为。Farm设置的默认值基于最佳实践,因此请确认是否必须修改默认值。

        +

        模块分组

        您可以使用 groups 将模块分组在一起。对于上述基本React项目示例,可以使用以下配置将 node_modules 下的模块打包在一起:

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'vendor-react',
        test: ['node_modules/'],
        }
        ]
        },
        },
        });

        我们添加了一个 group item ,其中包含 nametest ,以将 reactreact-dom 分组在一起。打包结果如下:

        -
        ./dist/
        ├── index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules
        ├── index_a35f.0ac21082.js # contains `./index.tsx`
        ├── index_ce26.7f833381.css # contains `./index.scss`
        └── index.html # contains `./index.html`
        +
        ./dist/
        ├── index_499e.72cf733c.js # contains `react`, `react-dom` and all other files under node_modules
        ├── index_a35f.0ac21082.js # contains `./index.tsx`
        ├── index_ce26.7f833381.css # contains `./index.scss`
        └── index.html # contains `./index.html`

        现在, node_modules 下的所有模块都打包到 index_499e.72cf733c.js 中。请注意,groups并不强制所有匹配该组的模块都打包在一起,一个 group可以产生多个 output file ,因为:

        1. 可变和不可变模块始终位于不同的输出文件中。当可变和不可变模块都匹配到这个 group 时,它们将位于不同的输出中。
        2. 对于多页面应用或动态导入的入口,可能存在共享模块,这些模块应始终位于不同的输出文件中。

        如果您需要强制将模块放在同一输出文件中,可以使用 enforceResources

        -

        使用 enforceResources

        +

        使用 enforceResources

        要将所有模块分组在一起并忽略所有其他条件,可以使用 enforceResources ,例如:

        -
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });
        +
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });

        打包结果:

        -
        ./dist/
        ├── index.7f833381.css # all css modules are bundled together
        ├── index.ba5550d9.js # all script modules are bundled together
        └── index.html
        -
        注意

        enforceResources 将忽略Farm的所有内部优化,使用时请小心。

        -

        配置 immutable modules

        +
        ./dist/
        ├── index.7f833381.css # all css modules are bundled together
        ├── index.ba5550d9.js # all script modules are bundled together
        └── index.html
        +
        注意

        enforceResources 将忽略Farm的所有内部优化,使用时请小心。

        +

        配置 immutable modules

        使用 immutableModules 配置不可变模块,默认情况下,Farm将其设置为 node_modules/

        -
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        immutableModules: ['node_modules/', '/global-constants']
        },
        },
        });
        +
        farm.config.ts
        export default defineConfig({
        compilation: {
        partialBundling: {
        immutableModules: ['node_modules/', '/global-constants']
        },
        },
        });

        不可变模块会影响打包和传入的持久化缓存,如果您想修改它,请小心。

        -

        示例

        -
        备注

        通常您不需要手动配置打包,如果您想手动配置打包,请确保您确实需要它。这些示例仅用于帮助您轻松学习如何配置打包策略。

        -

        将同一目录下的文件分组

        +

        示例

        +
        备注

        通常您不需要手动配置打包,如果您想手动配置打包,请确保您确实需要它。这些示例仅用于帮助您轻松学习如何配置打包策略。

        +

        将同一目录下的文件分组

        src/components 下的 modules 分组,并尽可能将它们输出到同一资源中。

        -
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'components',
        test: ['./src/components'],
        }
        ]
        },
        },
        });
        -

        配置打包的数量和大小

        -
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        targetConcurrentRequests: 15,
        targetMinSize: 200 * 1024 // 200 KB
        },
        },
        });
        +
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        groups: [
        {
        name: 'components',
        test: ['./src/components'],
        }
        ]
        },
        },
        });
        +

        配置打包的数量和大小

        +
        farm.config.ts
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        targetConcurrentRequests: 15,
        targetMinSize: 200 * 1024 // 200 KB
        },
        },
        });

        在上面的示例中,Farm将尝试尽可能地将您的项目打包到 15 个文件中,每个文件的最小大小尽可能大于 200KB

        -

        将所有模块打包在一起

        -
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });
        +

        将所有模块打包在一起

        +
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['.+'],
        }
        ]
        },
        },
        });

        在上面的示例中,我们强制将所有模块打包在一起,并忽略所有其他约束(例如,请求数量、文件大小)。您也可以使用 enforceResources 强制将某些模块打包在一起:

        -
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['\\./src/components/.+'],
        }
        ]
        },
        },
        });
        +
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        compilation: {
        partialBundling: {
        enforceResources: [
        {
        name: 'index',
        test: ['\\./src/components/.+'],
        }
        ]
        },
        },
        });

        我们强制将 src/components 目录下的所有模块打包在一起。

        -
        备注

        enforceResources 会破坏打包的内部优化,使用时请小心。

    +
    备注

    enforceResources 会破坏打包的内部优化,使用时请小心。

    \ No newline at end of file diff --git a/zh/docs/advanced/persistent-cache/index.html b/zh/docs/advanced/persistent-cache/index.html index cc9b1ae99..2a7696ca2 100644 --- a/zh/docs/advanced/persistent-cache/index.html +++ b/zh/docs/advanced/persistent-cache/index.html @@ -8,22 +8,22 @@ - - - + + + -
    版本:1.0.0

    增量构建

    -
    提示

    Farm 从v0.14.0开始支持通过持久缓存的增量构建

    +
    版本:1.0.0

    增量构建

    +
    提示

    Farm 从v0.14.0开始支持通过持久缓存的增量构建

    v0.14.0开始,Farm 支持将编译结果缓存到磁盘,这可以大大加快热启动/热构建的编译速度。当启用persistentCache时,编译时间可以减少高达80%

    冷启动(无缓存)和热启动(有缓存)的性能比较使用 examples/argo-pro:

    Cold(without cache)Hot(with cache)diff
    start1519ms371msreduced 75%
    build3582ms562msreduced 84%
    -

    使用缓存

    +

    使用缓存

    使用compilation.persistentCache启用/禁用缓存:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    persistentCache: true,
    },
    });
    -
    备注

    persistentCache: true 相当于:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: 'node_modules/.farm/cache',
    // namespace of the cache
    namespace: 'farm-cache',
    buildDependencies: [
    'farm.config.ts',
    '@farmfe/core',
    '@farmfe/plugin-react',
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    },
    },
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    persistentCache: true,
    },
    });
    +
    备注

    persistentCache: true 相当于:

    ({
    persistentCache: {
    // Directory that cache is stored
    cacheDir: 'node_modules/.farm/cache',
    // namespace of the cache
    namespace: 'farm-cache',
    buildDependencies: [
    'farm.config.ts',
    '@farmfe/core',
    '@farmfe/plugin-react',
    // ... all other dependencies
    ],
    moduleCacheKeyStrategy: {
    timestamp: true,
    hash: true,
    },
    },
    });

    persistentCachefalse以禁用缓存

    -

    缓存验证

    +

    缓存验证

    缓存在尝试重用时会通过以下条件进行验证,如果以下任何条件发生变化,所有缓存都将失效

    • @@ -43,20 +43,20 @@

      缓存验证

    如果您的缓存不起作用,请查看上述条件以找出原因。如果缓存损坏,您还可以删除 node_modules/.farm/cache 以手动删除缓存。

    -

    构建依赖项

    +

    构建依赖项

    构建依赖是可以影响编译过程或编译输出的依赖,例如插件或 config 文件。如果这些依赖中的任何一个发生了变化,所有缓存都将失效

    构建依赖项可以是包名的文件路径,例如:

    -
    import { defineConfig } from '@farmfe/core';
    import path from 'node:path';

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), './plugins/my-plugin.js'),
    // a package name, note that this package must expose package.json
    'farm-plugin-custom-xxx',
    ],
    },
    });
    -
    备注

    默认情况下,所有配置文件及其依赖项都包含在内。但是,如果您想添加一些额外的文件或依赖项来使缓存失效,您可以使用buildDependencies一旦这些文件更改,所有缓存都将失效

    -

    模块缓存密钥策略

    +
    import { defineConfig } from '@farmfe/core';
    import path from 'node:path';

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), './plugins/my-plugin.js'),
    // a package name, note that this package must expose package.json
    'farm-plugin-custom-xxx',
    ],
    },
    });
    +
    备注

    默认情况下,所有配置文件及其依赖项都包含在内。但是,如果您想添加一些额外的文件或依赖项来使缓存失效,您可以使用buildDependencies一旦这些文件更改,所有缓存都将失效

    +

    模块缓存密钥策略

    Farm 提供了 2 种策略来控制如何生成模块缓存键:

    • timestamp: 检查模块的时间戳,如果更新时间戳没有变化,则跳过此模块的构建,具有最佳性能.
    • hash: 加载和转换后检查 content hash,如果内容没有变化,将跳过此模块的剩余构建.

    默认情况下,timestamphash都是启用的

    -

    插件注意事项

    +

    插件注意事项

    当启用timestamp时,不会调用所有构建阶段钩子,如loadtransform。因此,如果插件依赖于loadtransform,并且没有实现 plugin_cache_loadedwrite_plugin_cache 钩子,它可能无法按预期工作。例如,如果插件在loadtransform中收集信息,所有在finish hook 时发出它们,它应该实现 plugin_cache_loadedwrite_plugin_cache hook 来加载和写入缓存,否则它将无法按预期工作。

    -

    Farm 将设置timestampfalseoutput.targetEnvnode

    +

    Farm 将设置timestampfalseoutput.targetEnvnode

    \ No newline at end of file diff --git a/zh/docs/advanced/polyfill/index.html b/zh/docs/advanced/polyfill/index.html index 9c3704976..cbc3d7367 100644 --- a/zh/docs/advanced/polyfill/index.html +++ b/zh/docs/advanced/polyfill/index.html @@ -8,33 +8,33 @@ - - - + + + -
    版本:1.0.0

    语法降级和 Polyfill

    +
    版本:1.0.0

    语法降级和 Polyfill

    默认情况下,Farm 将降级到 ES2017(原生支持 async/await),并在生产模式下自动注入必要的polyfills

    -
    备注

    默认情况下,Farm 不会为 node_modules/ 下的模块进行转换和注入 polyfills ,如果您需要降级语法并为 node_modules/ 注入 polyfills ,您可以使用 compilation.presetEnv.include

    -

    配置 targetEnv

    +
    备注

    默认情况下,Farm 不会为 node_modules/ 下的模块进行转换和注入 polyfills ,如果您需要降级语法并为 node_modules/ 注入 polyfills ,您可以使用 compilation.presetEnv.include

    +

    配置 targetEnv

    Farm 提供一个规范化的output.targetEnv选项来配置你的应用程序的目标执行环境。Farm 会自动为你的目标环境执行正确的syntax downgradepolyfill injection。例如:

    -
    farm.config.ts
    export default {
    compilation: {
    output: {
    targetEnv: 'browser-legacy',
    },
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    output: {
    targetEnv: 'browser-legacy',
    },
    },
    };

    Farm 会将您的应用程序编译为旧版浏览器(ES5)

    • 将所有的 Js/Jsx/Ts/Tsx模块编译到 ES5,并注入所有的 polyfills(Promise,regenerator-runtime 等)
    • 为所有 css/scss/less 模块添加前缀,例如--webkit-

    Farm 支持许多规范化的targetEnv选项,如browser-modernbrowser-es2017browser-es2015node16node-legacy等。默认情况下,targetEnvbrowser-es2017。请参阅output.targetEnv

    -
    备注

    您可能需要手动安装 core-js@3regeneration-runtime,如果需要 polyfill 。尝试运行pnpm add core-js 如果你遇到了一些错误例如:can not resolve 'core-js/modules/xxx'

    -

    分别配置语法和 Polyfill

    +
    备注

    您可能需要手动安装 core-js@3regeneration-runtime,如果需要 polyfill 。尝试运行pnpm add core-js 如果你遇到了一些错误例如:can not resolve 'core-js/modules/xxx'

    +

    分别配置语法和 Polyfill

    在内部,targetEnv只是 presetEnvscript.targetcss.prefixer的预设。如果需要,您可以更精确地配置它们

    -

    配置 presetEnv

    +

    配置 presetEnv

    您可以使用 compilation.presetEnv 自定义语法降级和 polyfill injection。默认情况下,node_modules下的所有模块都将被忽略。使用include添加需要被 polyfill 的额外模块。

    -
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: 'Chrome >= 48',
    },
    },
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: 'Chrome >= 48',
    },
    },
    },
    };

    请注意,如果您的项目不需要浏览器兼容性,您可以为 targets 设置一个较宽松的值,那么注入的 polyfills 会更少,产物体积也会更小

    有关更多选项,请参阅compilation.presetEnv

    -

    配置 script.target

    +

    配置 script.target

    script.target 用于在生成代码时控制目标环境。如果要将项目降级为 ES5,则应同时设置:

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5',
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: '> 0.25%, not dead',
    },
    },
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: 'ES5',
    },
    presetEnv: {
    // include a package under node_modules
    include: ['node_modules/package-name'],
    options: {
    targets: '> 0.25%, not dead',
    },
    },
    },
    };
    \ No newline at end of file diff --git a/zh/docs/advanced/ssr/index.html b/zh/docs/advanced/ssr/index.html index 23749d422..18c7393e0 100644 --- a/zh/docs/advanced/ssr/index.html +++ b/zh/docs/advanced/ssr/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:1.0.0

    服务端渲染 (SSR)

    +
    版本:1.0.0

    服务端渲染 (SSR)

    Server-Side Rendering(SSR)意味着在Node.js(服务器端)中将前端框架(例如React、Vue、Solid等)渲染为 html ,并在客户端对已经渲染好的HTML( rendered html )进行注水 (hydrate)。

    -
    备注

    本文档描述了如何从头开始在 Farm 上构建 SSR 应用程序。

    -

    示例项目

    +
    备注

    本文档描述了如何从头开始在 Farm 上构建 SSR 应用程序。

    +

    示例项目

    Farm为流行的框架提供了 SSR 示例

    -

    Project Structure

    +

    Project Structure

    一个典型的SSR应用程序通常具有以下源文件结构:

    -
    .
    ├── index.html
    ├── farm.config.ts
    ├── farm.config.server.ts
    ├── server.js
    └── src
    ├── index-client.tsx
    ├── index-server.tsx
    └── main.tsx
    +
    .
    ├── index.html
    ├── farm.config.ts
    ├── farm.config.server.ts
    ├── server.js
    └── src
    ├── index-client.tsx
    ├── index-server.tsx
    └── main.tsx
    • index.html: 应用程序运行在客户端(浏览器)上的入口HTML
    • farm.config.ts: 构建项目到客户端的farm配置
    • @@ -36,34 +36,34 @@

      Project St
    • src/main.tsx: 客户端和服务器共享的应用程序代码

    index.html 需要引用 index-client.tsx 并包含一个占位符,其中应注入服务器渲染的标记(markup):

    -
    <div id="root"><div>app-html-to-replace</div></div>
    <script src="./src/index-client.tsx"></script>
    +
    <div id="root"><div>app-html-to-replace</div></div>
    <script src="./src/index-client.tsx"></script>

    你应该将 <div>app-html-to-replace</div> 替换为服务器渲染的markup

    -
    提示

    我们必须为客户端(浏览器)和服务端(Node.js)分别构建SSR应用程序共两次。因此,需要 farm.config.tsfarm.config.server.ts ,我们将在后面的章节中讨论详细信息。

    -

    设置开发服务器

    +
    提示

    我们必须为客户端(浏览器)和服务端(Node.js)分别构建SSR应用程序共两次。因此,需要 farm.config.tsfarm.config.server.ts ,我们将在后面的章节中讨论详细信息。

    +

    设置开发服务器

    对于上述示例, farm.config.ts 用于构建浏览器端项目并设置开发服务器进行服务器渲染。 farm.config.ts 的通常这样写:

    -
    farm.config.ts
    import path from 'path';
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index_client: './index.html'
    },
    output: {
    path: './build'
    },
    },
    server: {
    hmr: true,
    cors: true,
    middlewares: [
    // 注册一个中间件,在服务端渲染应用,
    // 然后注入到服务器渲染的标记并返回最终的index.html
    (server) => {
    server.app().use(async (ctx, next) => {
    await next();

    // 处理index.html或单页面应用路由设置
    if (ctx.path === '/' || ctx.status === 404) {
    // 加载服务端入口,并通过ctx.path渲染
    const render = await import(path.join(process.cwd(), 'dist', 'index.js')).then(
    (m) => m.default
    );
    const renderedHtml = render(ctx.path);

    // 通过server.getCompiler()获取编译的index.html内容
    // 这里的html经过编译并注入了所有客户端bundles文件
    const template = server
    .getCompiler()
    .resource('index_client.html')
    .toString();

    // 将占位符替换为渲染好的内容,并将其作为HTML返回
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    renderedHtml
    );
    ctx.body = html;
    ctx.type = 'text/html';
    ctx.status = 200;
    }

    console.log('ctx.path outer', ctx.path);
    });
    }
    ]
    },
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass']
    });
    +
    farm.config.ts
    import path from 'path';
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index_client: './index.html'
    },
    output: {
    path: './build'
    },
    },
    server: {
    hmr: true,
    cors: true,
    middlewares: [
    // 注册一个中间件,在服务端渲染应用,
    // 然后注入到服务器渲染的标记并返回最终的index.html
    (server) => {
    server.app().use(async (ctx, next) => {
    await next();

    // 处理index.html或单页面应用路由设置
    if (ctx.path === '/' || ctx.status === 404) {
    // 加载服务端入口,并通过ctx.path渲染
    const render = await import(path.join(process.cwd(), 'dist', 'index.js')).then(
    (m) => m.default
    );
    const renderedHtml = render(ctx.path);

    // 通过server.getCompiler()获取编译的index.html内容
    // 这里的html经过编译并注入了所有客户端bundles文件
    const template = server
    .getCompiler()
    .resource('index_client.html')
    .toString();

    // 将占位符替换为渲染好的内容,并将其作为HTML返回
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    renderedHtml
    );
    ctx.body = html;
    ctx.type = 'text/html';
    ctx.status = 200;
    }

    console.log('ctx.path outer', ctx.path);
    });
    }
    ]
    },
    plugins: ['@farmfe/plugin-react', '@farmfe/plugin-sass']
    });

    在上面的示例中,需要一个中间件(middleware)来将应用程序渲染为标记并将其作为HTML提供。中间件中SSR的正常工作流程:

    • 加载编译后的服务端入口: 需要一个导出 render 函数的index-server入口,然后通过 import(server_entry_path) 来获取这个 render 函数。
    • 获取编译后的客户端index.html: 所有客户端打包代码和Farm运行时都注入到 index.html中,用于在客户端进行水合作用(hydrate)。
    • 将占位符替换为渲染后的代码: 替换占位符并返回最终的html代码(final html)。
    -
    备注

    在这个示例中,我们使用 if (ctx.path === '/' || ctx.status === 404) { 来构建一个 SPA SSR应用程序,如果你需要构建一个 MPA SSR应用程序,请将 ctx.path 传递到你的页面。

    -

    构建 Node.js 服务端产物

    +
    备注

    在这个示例中,我们使用 if (ctx.path === '/' || ctx.status === 404) { 来构建一个 SPA SSR应用程序,如果你需要构建一个 MPA SSR应用程序,请将 ctx.path 传递到你的页面。

    +

    构建 Node.js 服务端产物

    farm.config.server.ts 用于构建 Node.js 端产物,生成编译后的服务端入口,可用于在服务端将应用渲染为标记(markup)。

    -
    farm.config.server.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index-server.tsx'
    },
    output: {
    path: './dist',
    targetEnv: 'node'
    }
    },
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: false,
    development: false
    }
    ],
    '@farmfe/plugin-sass'
    ]
    });
    +
    farm.config.server.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index-server.tsx'
    },
    output: {
    path: './dist',
    targetEnv: 'node'
    }
    },
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: false,
    development: false
    }
    ],
    '@farmfe/plugin-sass'
    ]
    });

    对于 farm.config.server.ts ,我们将 input 设置为服务端入口,并将 output.targetEnv 设置为 node

    -
    备注

    默认情况下,Farm将服务端入口脚本编译为 esm ,如果你想要将其编译为cjs,请尝试设置 output.format

    -

    开发SSR项目

    +
    备注

    默认情况下,Farm将服务端入口脚本编译为 esm ,如果你想要将其编译为cjs,请尝试设置 output.format

    +

    开发SSR项目

    你需要为客户端和服务端启动编译,例如,你可能会在package.json中有以下脚本:

    -
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    }
    }
    +
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    }
    }

    当你开发SSR项目时,你需要在不同的终端中运行 npm run startnpm run start:server 。同时监听 server 和 client 的变动并重新编译。

    -

    生产环境构建

    +

    生产环境构建

    你需要同时为客户端和服务器构建项目,例如,你可能需要在 scripts 中添加以下命令:

    -
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    "build": "farm build",
    "build:server": "farm build --config farm.config.server.mjs"
    }
    }
    +
    package.json
    {
    "name": "@farmfe-examples/react-ssr",
    "scripts": {
    "start": "farm start",
    "start:server": "farm watch --config farm.config.server.mjs",
    "build": "farm build",
    "build:server": "farm build --config farm.config.server.mjs"
    }
    }

    打包构建时,你需要运行 npm run buildnpm run build:server,客户端打包将被输出到 build 目录,服务端打包将被输出到 dist 目录。

    对于生产环境,你需要一个 node server 来渲染和提供 rendered html。在这个示例中,我们使用了一个 server.js 作为生产服务端:

    -
    server.js
    import path from 'node:path';
    import { fileURLToPath } from 'node:url'
    import fsp from 'fs/promises';
    import express from 'express';

    function resolve(p) {
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    return path.resolve(__dirname, p);
    }

    // 创建一个Node生产服务端
    async function createServer() {
    let app = express();
    // 为客户端打包产物提供静态文件服务,也可以将客户端构建部署到CDN或单独的开发服务器,按照你的需求。
    app.use(express.static(resolve('build')));
    // 监听 '/' 路由, 你也可以将其替换为你需要的路由.
    app.use('/', async (req, res) => {
    let url = req.originalUrl;

    try {
    let template;
    let render;

    // 加载客户端html
    template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // 加载服务端渲染函数
    render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );
    // 将应用渲染为标记
    const markup = render(url);

    let html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // 返回包含客户端打包的rendered html
    // 客户端打包代码和服务器渲染的标记进行水和作用,
    // 并使其具有交互性
    res.setHeader('Content-Type', 'text/html');
    return res.status(200).end(html);
    } catch (error) {
    console.log(error.stack);
    res.status(500).end(error.stack);
    }
    });

    return app;
    }
    // create and listen the server
    createServer().then((app) => {
    app.listen(3000, () => {
    console.log('HTTP server is running at http://localhost:3000');
    });
    });
    +
    server.js
    import path from 'node:path';
    import { fileURLToPath } from 'node:url'
    import fsp from 'fs/promises';
    import express from 'express';

    function resolve(p) {
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    return path.resolve(__dirname, p);
    }

    // 创建一个Node生产服务端
    async function createServer() {
    let app = express();
    // 为客户端打包产物提供静态文件服务,也可以将客户端构建部署到CDN或单独的开发服务器,按照你的需求。
    app.use(express.static(resolve('build')));
    // 监听 '/' 路由, 你也可以将其替换为你需要的路由.
    app.use('/', async (req, res) => {
    let url = req.originalUrl;

    try {
    let template;
    let render;

    // 加载客户端html
    template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // 加载服务端渲染函数
    render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );
    // 将应用渲染为标记
    const markup = render(url);

    let html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // 返回包含客户端打包的rendered html
    // 客户端打包代码和服务器渲染的标记进行水和作用,
    // 并使其具有交互性
    res.setHeader('Content-Type', 'text/html');
    return res.status(200).end(html);
    } catch (error) {
    console.log(error.stack);
    res.status(500).end(error.stack);
    }
    });

    return app;
    }
    // create and listen the server
    createServer().then((app) => {
    app.listen(3000, () => {
    console.log('HTTP server is running at http://localhost:3000');
    });
    });

    我们在这里使用 express 作为服务端,但你可以使用任何你想要的服务端框架。渲染过程是相同的:

    • 加载客户端编译后的HTML(client index.html)
    • @@ -71,8 +71,8 @@

      生产环
    • 调用 const markup = render(url) 函数以获取应用的服务器端渲染标记
    • client index.html 中占位符替换为服务端渲染标记,并将替换后的html作为最终结果返回
    -

    静态站点生成(SSG)

    +

    静态站点生成(SSG)

    SSG的流程与SSR相同,不同的是SSG将替换的html输出到最终产物。SSG的示例脚本:

    -
    // 加载 client html
    const template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // 加载服务端渲染函数
    const render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );

    const pages = renderDirEntry('src/pages');

    for (const page of pages) {
    // 将应用渲染为标记
    const markup = render(url);
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // 输出静态生成的页面,例如将其写入硬盘
    emitPage(page, html);
    }
    +
    // 加载 client html
    const template = await fsp.readFile(resolve('build/index_client.html'), 'utf8');
    // 加载服务端渲染函数
    const render = await import(resolve('dist/index.js')).then(
    (m) => m.default
    );

    const pages = renderDirEntry('src/pages');

    for (const page of pages) {
    // 将应用渲染为标记
    const markup = render(url);
    const html = template.replace(
    '<div>app-html-to-replace</div>',
    markup
    );
    // 输出静态生成的页面,例如将其写入硬盘
    emitPage(page, html);
    }
    \ No newline at end of file diff --git a/zh/docs/advanced/tree-shake/index.html b/zh/docs/advanced/tree-shake/index.html index c202b2067..77f3ab183 100644 --- a/zh/docs/advanced/tree-shake/index.html +++ b/zh/docs/advanced/tree-shake/index.html @@ -8,26 +8,26 @@ - - - + + + -
    版本:1.0.0

    Tree Shake

    +
    版本:1.0.0

    Tree Shake

    Farm 支持 Tree Shake,该功能在默认的生产环境中自动启用,可以通过compilation.treeShaking选项打开或关闭。

    在 Tree Shake 期间,package.json 中的 sideEffects 字段将被自动读取,具有 sideEffects 的模块将不会执行 Tree Shake。

    -
    备注

    Farm 会将所有循环依赖的模块视为 sideEffects,不会执行 Tree Shake。请尽量避免项目中的循环依赖。

    +
    备注

    Farm 会将所有循环依赖的模块视为 sideEffects,不会执行 Tree Shake。请尽量避免项目中的循环依赖。

    Tree shake 示例:

    -
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    export b2 = "B2";
    +
    a.js
    import { b1, b2 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";
    export b2 = "B2";

    a.js 是 entry,它导入b.js,tree shaking 后,结果是:

    -
    a.js
    import { b1 } from 'b';
    console.log(b1);
    -
    b.js
    export b1 = "B1";
    +
    a.js
    import { b1 } from 'b';
    console.log(b1);
    +
    b.js
    export b1 = "B1";

    b2未使用,将在a.jsb.js中删除

    -

    配置 Tree Shake

    +

    配置 Tree Shake

    Tree Shake 默认在生产模式下启用,要禁用 tree Shake,请使用 compilation. treeShake

    -
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    -

    处理 Side Effects

    +
    farm.config.ts
    export default {
    compilation: {
    treeShake: false,
    },
    };
    +

    处理 Side Effects

    当一个模块包含Side Effects时,Farm 不会为其应用 tree shake,其所有导入和导出都被视为已使用。Farm 会认为以下模块有 Side effects

    1. Common Js 模块总是有副作用.
    2. @@ -37,16 +37,16 @@

      处理 S
    3. 入口模块总是有副作用

    示例 1:

    -
    const a = require('./');
    module.exports = a;
    +
    const a = require('./');
    module.exports = a;

    Common Js 模块总是有副作用.

    示例 2:

    -
    import a from './';

    a();
    +
    import a from './';

    a();

    a() 在全局范围内执行,我们将其视为副作用.

    Example 3:

    -
    // a.js
    import b from './b.js';

    // b.js
    import a from './a.js';
    +
    // a.js
    import b from './b.js';

    // b.js
    import a from './a.js';

    ab是循环依赖关系,所以它们也会被视为副作用.

    Example 4:

    -
    package.json
    {
    "name": "my-package",
    "sideEffects": ["./global/**.ts"]
    }
    -

    所有 global/ 下的 ts 模块都被视为副作用.

    +
    package.json
    {
    "name": "my-package",
    "sideEffects": ["./global/**.ts"]
    }
    +

    所有 global/ 下的 ts 模块都被视为副作用.

    \ No newline at end of file diff --git a/zh/docs/api/hmr-api/index.html b/zh/docs/api/hmr-api/index.html index 34af97e0d..13f4f89e5 100644 --- a/zh/docs/api/hmr-api/index.html +++ b/zh/docs/api/hmr-api/index.html @@ -8,55 +8,55 @@ - - - + + + -
    版本:1.0.0

    Hmr Api

    -
    备注

    HMR API 兼容Vite 的 HMR API

    +
    版本:1.0.0

    Hmr Api

    +
    备注

    HMR API 兼容Vite 的 HMR API

    Farm 通过特殊的 import.meta.hot 对象导出 HMR API(与Vite兼容):

    -
    export interface ViteHotContext {
    readonly data: any;

    accept(): void;
    accept(cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(
    deps: readonly string[],
    cb: (mods: Array<ModuleNamespace | undefined>) => void
    ): void;

    dispose(cb: (data: any) => void): void;
    prune(cb: (data: any) => void): void;
    invalidate(message?: string): void;

    on<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    off<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    send<T extends string>(event: T, data?: InferCustomEventPayload<T>): void;
    }
    -

    HMR 前置判断

    +
    export interface ViteHotContext {
    readonly data: any;

    accept(): void;
    accept(cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void;
    accept(
    deps: readonly string[],
    cb: (mods: Array<ModuleNamespace | undefined>) => void
    ): void;

    dispose(cb: (data: any) => void): void;
    prune(cb: (data: any) => void): void;
    invalidate(message?: string): void;

    on<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    off<T extends string>(
    event: T,
    cb: (payload: InferCustomEventPayload<T>) => void
    ): void;
    send<T extends string>(event: T, data?: InferCustomEventPayload<T>): void;
    }
    +

    HMR 前置判断

    HMR 仅适用于开发模式,请确保使用条件块保护 HMR API 使用:

    -
    if (import.meta.hot) {
    // HMR Code
    }
    -

    Typescript 支持

    +
    if (import.meta.hot) {
    // HMR Code
    }
    +

    Typescript 支持

    和 Vite 一样,Farm 在 @farmfe/core/client.d.ts 中提供了 import.meta.hot 的类型定义。 您可以在 src 目录中创建一个 env.d.ts ,以便 TypeScript 获取类型定义:

    -
    /// <reference types="@farmfe/core/client" />
    -

    hot.accept()

    +
    /// <reference types="@farmfe/core/client" />
    +

    hot.accept()

    对于接收自身更新的模块,请使用 import.meta.hot.accept()

    -
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept();

    const div = document.getElementById(id);
    // update the page
    if (div) {
    const comp = SelfAcceptedEmpty().render();
    div.replaceWith(comp);
    }
    }
    -

    hot.accept(cb)

    +
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept();

    const div = document.getElementById(id);
    // update the page
    if (div) {
    const comp = SelfAcceptedEmpty().render();
    div.replaceWith(comp);
    }
    }
    +

    hot.accept(cb)

    如果你想根据 更新模块的导出 来更新模块状态,可以使用 import.meta.hot.accept(cb)

    -
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    const comp = mod[id]().render();
    div?.replaceWith(comp);
    });
    }
    +
    if (import.meta.hot) {
    // self accept without reload the page
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    const comp = mod[id]().render();
    div?.replaceWith(comp);
    });
    }

    cb 的参数是 更新模块的导出 ,您可以基于它进行更新。

    -

    hot.accept(deps, cb)

    +

    hot.accept(deps, cb)

    模块还可以接受来自直接依赖项的更新,而无需重新加载自身。

    接受单一依赖:

    -
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept('./accept-deps-data', (data) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }
    +
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept('./accept-deps-data', (data) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }

    接受多个依赖项:

    -
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept(['./accept-deps-data'], ([data]) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }
    -

    hot.dispose(cb)

    +
    if (import.meta.hot) {
    // accept dependencies
    import.meta.hot.accept(['./accept-deps-data'], ([data]) => {
    console.log(data);
    const div = document.getElementById(id);
    const renderData = data.compData(id);
    div!.innerText = renderData;
    });
    }
    +

    hot.dispose(cb)

    自我接受模块或期望被其他模块接受的模块可以使用 hot.dispose 来清理其更新副本所产生的任何持久副作用:

    -
    if (import.meta.hot) {
    // 接受 HMR 更新以避免页面刷新
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    div?.appendChild(mod.createChild());
    });

    // 清理副作用
    import.meta.hot.dispose(() => {
    // 删除div的所有子元素
    const div = document.getElementById(id);

    if (div) {
    while (div.firstChild) {
    console.log('dispose', div.firstChild);
    div.removeChild(div.firstChild);
    }
    }
    });
    }
    -

    hot.prune(cb)

    +
    if (import.meta.hot) {
    // 接受 HMR 更新以避免页面刷新
    import.meta.hot.accept(mod => {
    const div = document.getElementById(id);
    div?.appendChild(mod.createChild());
    });

    // 清理副作用
    import.meta.hot.dispose(() => {
    // 删除div的所有子元素
    const div = document.getElementById(id);

    if (div) {
    while (div.firstChild) {
    console.log('dispose', div.firstChild);
    div.removeChild(div.firstChild);
    }
    }
    });
    }
    +

    hot.prune(cb)

    注册一个回调,当页面上不再导入模块时将调用该回调。 与 hot.dispose 相比,如果源代码在更新时自行清除副作用,并且您只需要在从页面中删除它时进行清除,则可以使用此方法。 Farm 目前使用它来导入 .css(与 Vite 相同)。

    -
    if (import.meta.hot) {{
    import.meta.hot.accept();
    import.meta.hot.prune(() => {{
    style.remove();
    }});
    }}
    -

    hot.data

    +
    if (import.meta.hot) {{
    import.meta.hot.accept();
    import.meta.hot.prune(() => {{
    style.remove();
    }});
    }}
    +

    hot.data

    import.meta.hot.data 对象在同一更新模块的不同实例中保留。 它可用于将信息从模块的前一版本传递到下一版本。

    -
    import.meta.hot.data.value = 'value';
    -

    hot.invalidate(message?: string)

    +
    import.meta.hot.data.value = 'value';
    +

    hot.invalidate(message?: string)

    自接受模块可能会在运行时意识到它无法处理 HMR 更新,因此需要将更新强制传播到祖先模块。 通过调用 import.meta.hot.invalidate(),HMR 服务器将使调用者的接收更新状态失效,并将此次更新通知以此到所有祖先模块,如果有任意祖先模块接收本次更新,HMR 成功,否则,将会刷新页面。 这将在浏览器控制台和终端中打印一条消息。 您可以传递一条消息来提供有关失效发生原因的一些背景信息。

    请注意,即使您计划随后立即调用 invalidate,您也应该始终调用 import.meta.hot.accept,否则 HMR 客户端将不会监听自我接受模块的未来更改。 为了清楚地传达您的意图,我们建议在接受回调中调用 invalidate,如下所示:

    -
    if (import.meta.hot) {
    import.meta.hot.accept((mod) => {
    if (cannotHandleUpdate(mod)) {
    import.meta.hot.invalidate('parent module should accept this');
    }
    });
    }
    -

    hot.on(event, cb)

    +
    if (import.meta.hot) {
    import.meta.hot.accept((mod) => {
    if (cannotHandleUpdate(mod)) {
    import.meta.hot.invalidate('parent module should accept this');
    }
    });
    }
    +

    hot.on(event, cb)

    与Vite相同,参见 Vite hot.on

    -

    hot.off(event, cb)

    +

    hot.off(event, cb)

    从事件监听器中删除回调

    -

    hot.send(event, data)

    +

    hot.send(event, data)

    从 HMR 客户端向开发服务器发送消息:

    -
    import.meta.hot.send('event-name', { data: '123' });
    +
    import.meta.hot.send('event-name', { data: '123' });

    在开发服务器上接收消息:

    -
    server.ws.on('event-name', (data) => {});
    +
    server.ws.on('event-name', (data) => {});
    \ No newline at end of file diff --git a/zh/docs/api/javascript-api/index.html b/zh/docs/api/javascript-api/index.html index 607c5642c..3d283a954 100644 --- a/zh/docs/api/javascript-api/index.html +++ b/zh/docs/api/javascript-api/index.html @@ -8,180 +8,180 @@ - - - + + + -
    版本:1.0.0

    JavaScript Api

    +
    版本:1.0.0

    JavaScript Api

    Farm 提供完整的开发服务器、编译器、监听器等 JavaScript Api, 开发者可以通过引入 @farmfe/core 包来使用这些 Api。

    安装 @farmfe/core 包:

    -
    npm install @farmfe/core@latest
    -

    Start

    +
    npm install @farmfe/core@latest
    +

    Start

    Start 方法用于快速启动开发服务器

    调用 start 方法之后就可以在当前控制台看见可用的 ip 地址的日志信息, 默认会编译当前目录下的 index.html 文件

    类型:

    -
    start(options: InlineConfig): Promise<void>
    +
    start(options: InlineConfig): Promise<void>

    基本示例:

    -
    import { start, logger } from "@farmfe/core";
    try {
    await start(options);
    } catch (error) {
    logger.error(`Failed to start server:\n ${error.stack}`);
    process.exit(1);
    }
    -

    Build

    +
    import { start, logger } from "@farmfe/core";
    try {
    await start(options);
    } catch (error) {
    logger.error(`Failed to start server:\n ${error.stack}`);
    process.exit(1);
    }
    +

    Build

    Build 方法对生产环境进行构建

    调用 build 方法之后默认构建浏览器产物, 并且会在当前目录下生成一个 dist 文件夹, 如若需要构建不同环境以及不同版本产物, 例如 nodenode-nextbrowserbrowser-es2017 等, 可以通过查看 output targetEnv 来进行配置. 类型:

    -
    build(options: InlineConfig): Promise<void>
    +
    build(options: InlineConfig): Promise<void>

    基本示例:

    -
    import { build, logger } from "@farmfe/core";
    try {
    await build(options);
    } catch (error) {
    logger.error(`error during build:\n ${error.stack}`);
    process.exit(1);
    }
    -

    Watch

    +
    import { build, logger } from "@farmfe/core";
    try {
    await build(options);
    } catch (error) {
    logger.error(`error during build:\n ${error.stack}`);
    process.exit(1);
    }
    +

    Watch

    Watch 方法对当前项目的编译进行实时更新, 等同于 npx farm build --watch, 一般作用于 node 环境

    类型:

    -
    watch(options: InlineConfig): Promise<void>
    +
    watch(options: InlineConfig): Promise<void>

    基本示例:

    -
    import { watch, logger } from "@farmfe/core";
    try {
    await watch(defaultOptions);
    } catch (error) {
    logger.error(`error during watch project:\n ${error.stack}`);
    process.exit(1);
    }
    -

    Preview

    +
    import { watch, logger } from "@farmfe/core";
    try {
    await watch(defaultOptions);
    } catch (error) {
    logger.error(`error during watch project:\n ${error.stack}`);
    process.exit(1);
    }
    +

    Preview

    Preview 方法启动一个预览服务器, 对生产环境产物进行预览, 使用时需要确保已经通过 build 方法进行构建, 并且生成了正确的生产环境产物

    类型:

    -
    preview(options: InlineConfig): Promise<void>
    +
    preview(options: InlineConfig): Promise<void>

    基本示例:

    -
    import { preview, logger } from "@farmfe/core";
    try {
    await preview(defaultOptions);
    } catch (error) {
    logger.error(`Failed to start preview server:\n ${error.stack}`);
    process.exit(1);
    }
    -

    Clean

    +
    import { preview, logger } from "@farmfe/core";
    try {
    await preview(defaultOptions);
    } catch (error) {
    logger.error(`Failed to start preview server:\n ${error.stack}`);
    process.exit(1);
    }
    +

    Clean

    Clean 方法清理 farm 增量构建所产生缓存, 如果您开启了增量构建功能, 那么这个方法可能对您有所帮助

    -
    注意

    对于目前使用增量构建功能而导致某些不可预知或者未发现的问题所导致的程序崩溃, 可以尝试通过清理缓存来解决问题, 若并不能解决请在 github 上提交 issues

    +
    注意

    对于目前使用增量构建功能而导致某些不可预知或者未发现的问题所导致的程序崩溃, 可以尝试通过清理缓存来解决问题, 若并不能解决请在 github 上提交 issues

    类型:

    -
    clean(options: InlineConfig): Promise<void>
    +
    clean(options: InlineConfig): Promise<void>

    基本示例:

    -
    import { clean, logger } from "@farmfe/core";
    try {
    await clean(defaultOptions);
    } catch (error) {
    logger.error(`Failed to clean cache:\n ${error.stack}`);
    process.exit(1);
    }
    -

    loadEnv

    +
    import { clean, logger } from "@farmfe/core";
    try {
    await clean(defaultOptions);
    } catch (error) {
    logger.error(`Failed to clean cache:\n ${error.stack}`);
    process.exit(1);
    }
    +

    loadEnv

    从 .env 文件加载环境变量。

    -
    type LoadEnvFunc = (
    mode: string,
    envDir: string,
    prefixes: string | string[] = ['FARM_', 'VITE_']
    ) => [env: Record<string, string>, existsEnvFiles: string[]];
    +
    type LoadEnvFunc = (
    mode: string,
    envDir: string,
    prefixes: string | string[] = ['FARM_', 'VITE_']
    ) => [env: Record<string, string>, existsEnvFiles: string[]];
    • modedevelopmentProduction 或任何字符串。 loadEnv 将尝试加载 [``.env``, ``.env.local``, ``.env.${mode}``, ``.env.${mode}.local``] envDir
    • envDir.env 文件所在的目录。
    • prefixes 是环境变量的前缀。 默认值为 ['FARM_', 'VITE_'] 。 带有这些前缀的环境变量将自动注入到define中。
    -
    const [env, files] = loadEnv('development', '/path/to/project/env');
    // use env
    -

    createDevServer

    +
    const [env, files] = loadEnv('development', '/path/to/project/env');
    // use env
    +

    createDevServer

    createDevServer 方法用于启动本地开发服务器, 需要先实例化 Server 对象, 传递参数需要 farmcompiler

    类型:

    -
    createDevServer(options: DevServerOptions): Promise<void>
    +
    createDevServer(options: DevServerOptions): Promise<void>

    基本示例:

    -
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    -

    createPreviewServer

    +
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    +

    createPreviewServer

    创建一个 预览服务器,用于预览生产环境产物

    类型:

    -
    createPreviewServer(options: DevServerOptions): Promise<void>
    +
    createPreviewServer(options: DevServerOptions): Promise<void>

    基本示例:

    -
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createPreviewServer(options);
    -

    getCompiler

    +
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createPreviewServer(options);
    +

    getCompiler

    获取当前开发服务器的编译器实例, 在实例化 Server 的时候需要传递一个 compiler 参数

    类型:

    -
    getCompiler(): Compiler
    +
    getCompiler(): Compiler

    基本示例:

    -
    import { Server, Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const server = new Server({
    compiler
    });
    const compiler = server.getCompiler();
    -

    close

    +
    import { Server, Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const server = new Server({
    compiler
    });
    const compiler = server.getCompiler();
    +

    close

    关闭当前由 createDevServer 开启的所有 Server 以及 Webscoker 服务

    基本示例:

    -
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    await server.close();
    -

    Compiler

    +
    import { Server } from "@farmfe/core";
    const server = new Server();
    await server.createDevServer(options);
    server.listen()
    await server.close();
    +

    Compiler

    Compiler 提供一系列编译器的 Api,可以通过实例化 Compiler 创建一个编译器实例。

    基本示例

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    -

    compile

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    +

    compile

    编译器异步启动编译过程。返回一个 promise

    -
    备注

    如果设置了特定的环境变量 (procee.env.FARM_PROFILE) , 则执行同步编译。

    +
    备注

    如果设置了特定的环境变量 (procee.env.FARM_PROFILE) , 则执行同步编译。

    类型:

    -
    compile(): promise<void>
    +
    compile(): promise<void>

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    -

    compileSync

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile();
    +

    compileSync

    编译器同步启动编译过程。

    类型:

    -
    compileSync(): void
    +
    compileSync(): void

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.compileSync();
    -

    traceDependencies

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.compileSync();
    +

    traceDependencies

    追踪文件之间的依赖关系, 根据 compiler 传递的 config 参数中的 input 返回当前文件的所有依赖关系, 这对于根据文件依赖关系进行重启编译非常有用。

    类型:

    -
    traceDependencies(): Array[string]
    +
    traceDependencies(): Array[string]

    基本示例:

    -
    import { Compiler } from "@farmfe/core";

    const config = {
    input: "./farm.config.js"
    }
    const compiler = new Compiler(config);
    const dependencies = compiler.traceDependencies();
    +
    import { Compiler } from "@farmfe/core";

    const config = {
    input: "./farm.config.js"
    }
    const compiler = new Compiler(config);
    const dependencies = compiler.traceDependencies();

    返回一个所有依赖关系的路径组成的数组

    -

    update

    +

    update

    根据提供的路径来更新编译, 返回一个解析为 JsUpdateResultPromise。如果编译已经在进行中, 它会等待处理并更新。如果设置了 ignoreCompilingChecktrue, 则不会检查编译状态。

    类型:

    -
    update(paths: Array<string>, sync: boolean, ignoreCompilingCheck: boolean): JsUpdateResult
    +
    update(paths: Array<string>, sync: boolean, ignoreCompilingCheck: boolean): JsUpdateResult

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = await compiler.update(paths, true, true);
    -

    hasModule

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = await compiler.update(paths, true, true);
    +

    hasModule

    传递一个 path 判断当前 path 是否处于 compiler 所编译的模块中。

    类型:

    -
    hasModule(path: string): boolean
    +
    hasModule(path: string): boolean

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.hasModule(path);
    -

    getParentFiles

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.hasModule(path);
    +

    getParentFiles

    检索由 模块导入名 (id) 或已解析路径标识(resolvedPath)的模块导入的当前文件。

    类型:

    -
    getParentFiles(resolvedPath: string): Array<string>
    +
    getParentFiles(resolvedPath: string): Array<string>

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.getParentFiles(resolvedPath);
    -

    resources

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.getParentFiles(resolvedPath);
    +

    resources

    返回所有经过 compiler 编译后的所有产物资源

    类型:

    -
    type Resource = {
    path: string
    buffer: Buffer
    }
    resources(): Array<Resource>
    +
    type Resource = {
    path: string
    buffer: Buffer
    }
    resources(): Array<Resource>

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resources();
    -

    Resource

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resources();
    +

    Resource

    根据传入的文件返回当前产物的 buffer

    类型:

    -
    resource(path: string): Buffer | null
    +
    resource(path: string): Buffer | null

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resource(path);
    -

    writeResourcesToDisk

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resource(path);
    +

    writeResourcesToDisk

    根据配置输出路径将资源写入磁盘

    类型:

    -
    writeResourcesToDisk(): void
    +
    writeResourcesToDisk(): void

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.writeResourcesToDisk();
    -

    removeOutputPathDir

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.writeResourcesToDisk();
    +

    removeOutputPathDir

    删除输出产物路径目录

    类型:

    -
    removeOutputPathDir(): void
    +
    removeOutputPathDir(): void

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.removeOutputPathDir();
    -

    resolvedWatchPaths

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    compiler.removeOutputPathDir();
    +

    resolvedWatchPaths

    返回已解析的监视路径

    类型:

    -
    resolvedWatchPaths(): Array<string>
    +
    resolvedWatchPaths(): Array<string>

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedWatchPaths();
    -

    resolvedModulePaths

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedWatchPaths();
    +

    resolvedModulePaths

    返回相对于提供的根路径已解析的模块路径。

    类型:

    -
    resolvedModulePaths(rootPath: string): Array<string>
    +
    resolvedModulePaths(rootPath: string): Array<string>

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedModulePaths(rootPath);
    -

    onUpdateFinish

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    await compiler.compile()
    const result = compiler.resolvedModulePaths(rootPath);
    +

    onUpdateFinish

    添加一个在更新过程完成后执行的回调。

    类型:

    -
    onUpdateFinish(callback: (...args: any[]) => any): void
    +
    onUpdateFinish(callback: (...args: any[]) => any): void

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.onUpdateFinish(callback);
    -

    outputPath

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.onUpdateFinish(callback);
    +

    outputPath

    返回已解析的输出路径

    类型:

    -
    outputPath(): string
    +
    outputPath(): string

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.outputPath();
    -

    addExtraWatchFile

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.outputPath();
    +

    addExtraWatchFile

    为编译器添加额外的监视文件。

    类型:

    -
    addExtraWatchFile(rootPath: string,. filePath: string[]): void
    +
    addExtraWatchFile(rootPath: string,. filePath: string[]): void

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.addExtraWatchFile(rootPath, filePath);
    -

    modules

    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    compiler.addExtraWatchFile(rootPath, filePath);
    +

    modules

    返回文件模块解析后的对象数组

    类型:

    -
    export interface Module {
    id: string
    moduleType: string
    moduleGroups: Array<string>
    resourcePot?: string
    sideEffects: boolean
    sourceMapChain: Array<string>
    external: boolean
    immutable: boolean
    }
    modules(): Array<Module>
    +
    export interface Module {
    id: string
    moduleType: string
    moduleGroups: Array<string>
    resourcePot?: string
    sideEffects: boolean
    sourceMapChain: Array<string>
    external: boolean
    immutable: boolean
    }
    modules(): Array<Module>

    基本示例:

    -
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.modules();
    +
    import { Compiler } from "@farmfe/core";
    const compiler = new Compiler(config);
    const result = compiler.modules();
    \ No newline at end of file diff --git a/zh/docs/api/js-plugin-api/index.html b/zh/docs/api/js-plugin-api/index.html index 19cf188bb..286742eb0 100644 --- a/zh/docs/api/js-plugin-api/index.html +++ b/zh/docs/api/js-plugin-api/index.html @@ -8,43 +8,43 @@ - - - + + + -
    版本:1.0.0

    Js Plugin Api

    +
    版本:1.0.0

    Js Plugin Api

    Farm Js Plugin 设计了类似 rollup 风格的设计插件系统,可以轻松地从 Rollup/Vite/Webpack 迁移您的插件/项目。

    -

    配置 Js 插件

    +

    配置 Js 插件

    通过 plugins 选项添加 JS 插件:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";
    // import a js plugin
    import farmPluginFoo from "farm-plugin-foo";

    export default defineConfig({
    // configuring it in plugins
    plugins: [farmPluginFoo()],
    });
    -

    编写Js插件

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";
    // import a js plugin
    import farmPluginFoo from "farm-plugin-foo";

    export default defineConfig({
    // configuring it in plugins
    plugins: [farmPluginFoo()],
    });
    +

    编写Js插件

    Farm Js 插件是一个普通的 javascript 对象,它公开了一组 hook 。 例如:

    -
    my-farm-plugin.ts
    // 创建一个插件文件,导出一个返回 `JsPlugin` 对象的插件函数:
    import type { JsPlugin } from '@farmfe/core';

    // 插件选项
    export interface PluginOptions {
    test: boolean;
    }
    // 导出插件函数
    export default function MyPlugin(options: PluginOptions): JsPlugin {
    // 读取插件 options
    const { test } = options;

    // 返回一个暴露钩子的对象
    return {
    name: 'my-farm-plugin',
    // 使用load hook加载自定义模块
    load: {
    filters: {
    resolvedPaths: ['\\.test$'] // 过滤文件以提高性能
    },
    async executor({ resolvedPath }) {
    if (test && resolvedPath.endsWith('.test')) {
    return {
    content: 'test file',
    sourceMap: null
    }
    }
    }
    }
    }
    }
    -
    备注
      +
      my-farm-plugin.ts
      // 创建一个插件文件,导出一个返回 `JsPlugin` 对象的插件函数:
      import type { JsPlugin } from '@farmfe/core';

      // 插件选项
      export interface PluginOptions {
      test: boolean;
      }
      // 导出插件函数
      export default function MyPlugin(options: PluginOptions): JsPlugin {
      // 读取插件 options
      const { test } = options;

      // 返回一个暴露钩子的对象
      return {
      name: 'my-farm-plugin',
      // 使用load hook加载自定义模块
      load: {
      filters: {
      resolvedPaths: ['\\.test$'] // 过滤文件以提高性能
      },
      async executor({ resolvedPath }) {
      if (test && resolvedPath.endsWith('.test')) {
      return {
      content: 'test file',
      sourceMap: null
      }
      }
      }
      }
      }
      }
      +
      备注
      • Farm提供create-farm-plugin工具来帮助您快速创建和开发您的js插件。 有关编写 JS 插件的更多详细信息,请参阅编写 JS 插件
      -

      Plugin Hook Overview

      +

      Plugin Hook Overview

      Js 插件 Hook 与 Rust 插件相同,请参阅 Rust 插件 Hook 概述

      -
      备注

      并非所有钩子都暴露给 Js 插件,只有本文档中列出的钩子可用。

      -

      hooks

      -

      name

      +
      备注

      并非所有钩子都暴露给 Js 插件,只有本文档中列出的钩子可用。

      +

      hooks

      +

      name

      • type: string
      • required: true

      该插件的名称,不能为空。

      -
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      // ...
      }
      }
      -

      priority

      +
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      // ...
      }
      }
      +

      priority

      • type: number
      • required: false
      • default: 100

      该插件的优先级,默认为 100priority 控制插件的执行顺序,值越大,插件越早执行。

      -
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      priority: 1000, // // 使该插件先于所有其他插件执行
      // ...
      }
      }
      -
      备注

      请注意,大多数 Farm 内部插件(如 plugin-scriptplugin-resolve )的优先级是 99 ,这意味着您的插件始终在内部插件之前执行。 如果您想让您的插件在农场内部插件之后执行,请将 priority 设置为小于 99 的值,例如: 98 。 优先级值也可以为负数,您可以将其设置为 -9999 以确保它始终最后执行。

      -

      config

      +
      export default function MyPlugin() {
      return {
      name: 'my-plugin',
      priority: 1000, // // 使该插件先于所有其他插件执行
      // ...
      }
      }
      +
      备注

      请注意,大多数 Farm 内部插件(如 plugin-scriptplugin-resolve )的优先级是 99 ,这意味着您的插件始终在内部插件之前执行。 如果您想让您的插件在农场内部插件之后执行,请将 priority 设置为小于 99 的值,例如: 98 。 优先级值也可以为负数,您可以将其设置为 -9999 以确保它始终最后执行。

      +

      config

      • type: config?: (config: UserConfig) => UserConfig | Promise<UserConfig>;
      • hook type: serial
      • @@ -52,9 +52,9 @@

        configFarm config,返回(部分)修改后的配置,返回的配置将深度合并到从cli和配置文件解析的配置中。 您也可以直接更改配置。

        示例:

        -
        const resolveConfigPlugin = () => ({
        name: 'return-resolve-config-plugin',
        config: (_config) => ({
        compilation: {
        resolve: {
        alias: {
        foo: 'bar'
        }
        }
        }
        })
        });
        -
        备注

        在解析所有 用户插件 后,会调用 config 钩子,因此在 config 钩子中将新插件添加到配置中无效。

        -

        configResolved

        +
        const resolveConfigPlugin = () => ({
        name: 'return-resolve-config-plugin',
        config: (_config) => ({
        compilation: {
        resolve: {
        alias: {
        foo: 'bar'
        }
        }
        }
        })
        });
        +
        备注

        在解析所有 用户插件 后,会调用 config 钩子,因此在 config 钩子中将新插件添加到配置中无效。

        +

        configResolved

        • type: configResolved?: (config: ResolvedUserConfig) => void | Promise<void>;
        • hook type: serial
        • @@ -62,19 +62,19 @@

          configResolve

        当配置解析时调用(在调用所有插件的 config 钩子之后)。 当您想要获得插件的最终解析配置时很有用。

        示例:

        -
        const myPlugin = () => {
        let farmConfig;

        return {
        name: 'my-plugin',
        configResolved(resolvedConfig) {
        // get resolved config
        resolvedConfig = farmConfig;
        },
        transform: {
        filters: {
        moduleTypes: ['js']
        },
        async executor(param) {
        if (farmConfig.xxx) {
        // ...
        }
        }
        }
        }
        }
        -

        configureDevServer

        +
        const myPlugin = () => {
        let farmConfig;

        return {
        name: 'my-plugin',
        configResolved(resolvedConfig) {
        // get resolved config
        resolvedConfig = farmConfig;
        },
        transform: {
        filters: {
        moduleTypes: ['js']
        },
        async executor(param) {
        if (farmConfig.xxx) {
        // ...
        }
        }
        }
        }
        }
        +

        configureDevServer

        • type: configureDevServer?: (server: Server) => void | Promise<void>;
        • hook type: serial
        • required: false
        -
        备注

        请注意,该钩子仅在开发模式下运行。

        +
        备注

        请注意,该钩子仅在开发模式下运行。

        Dev Server 准备就绪时调用,您可以获得开发服务器实例。

        示例:

        -
        const myPlugin = () => {
        let devServer;

        return {
        name: 'my-plugin',
        configureDevServer(server) {
        devServer = server;
        }
        }
        }
        -
        备注

        js pluginconfigconfigResolved 钩子都会在 rust pluginconfig 钩子之前被调用。

        -

        configureCompiler

        +
        const myPlugin = () => {
        let devServer;

        return {
        name: 'my-plugin',
        configureDevServer(server) {
        devServer = server;
        }
        }
        }
        +
        备注

        js pluginconfigconfigResolved 钩子都会在 rust pluginconfig 钩子之前被调用。

        +

        configureCompiler

        • type: configureCompiler?: (compiler: Compiler) => void | Promise<void>;
        • hook type: serial
        • @@ -82,8 +82,8 @@

          configureC

        Rust Compiler 准备好时调用,该钩子在开发和生产中运行。 您可以在此处获取 Compiler 实例

        示例:

        -
        const myPlugin = () => {
        let farmCompiler;

        return {
        name: 'my-plugin',
        configureCompiler(compiler) {
        farmCompiler = compiler;
        }
        }
        }
        -

        buildStart

        +
        const myPlugin = () => {
        let farmCompiler;

        return {
        name: 'my-plugin',
        configureCompiler(compiler) {
        farmCompiler = compiler;
        }
        }
        }
        +

        buildStart

        • type: buildStart?: { executor: Callback<Record<string, never>, void> };
        • hook type: parallel
        • @@ -91,24 +91,24 @@

          buildStart

          在编译开始之前调用。 你可以在这里做一些初始化工作。

          Example:

          -
          const myPlugin = () => {
          // 定义插件操作
          let myPluginContext = createMyPluginContext();

          return {
          name: 'my-plugin',
          buildStart: {
          async executor() {
          // 在编译之前初始化插件上下文
          myPluginContext.setup();
          }
          }
          }
          }
          -
          备注

          buildStart 仅在第一次编译时调用一次。 后期编译如 Lazy CompilationHMR Update 不会触发 buildStart

          -

          resolve

          +
          const myPlugin = () => {
          // 定义插件操作
          let myPluginContext = createMyPluginContext();

          return {
          name: 'my-plugin',
          buildStart: {
          async executor() {
          // 在编译之前初始化插件上下文
          myPluginContext.setup();
          }
          }
          }
          }
          +
          备注

          buildStart 仅在第一次编译时调用一次。 后期编译如 Lazy CompilationHMR Update 不会触发 buildStart

          +

          resolve

          • required: false
          • hook type: first
          • type:
          -
          type ResolveHook = { 
          filters: {
          importers: string[];
          sources: string[];
          };
          executor: Callback<PluginResolveHookParam, PluginResolveHookResult>
          };

          type Callback<P, R> = (
          param: P,
          context?: CompilationContext,
          hookContext?: { caller?: string; meta: Record<string, unknown> }
          ) => Promise<R | null | undefined>;

          /// resolve 钩子的参数
          export interface PluginResolveHookParam {
          /// 解析 `source` 的起始位置,如果 resolve 入口或 resolve hmr 更新,则为 [None]。
          /// 值为父模块的id,例如:`src/index.ts` 或 `src/index.vue?vue&type=xxx`
          importer: string | null;
          /// 例如,[ResolveKind::Import] 用于静态导入 (`import a from './a'`)
          kind: ResolveKind;
          /// 导入来源。 例如在index.ts中(import App from "./App.vue")
          /// 源应该是 './App.vue'
          source: string;
          }
          /// resolve 钩子的解析结果
          export interface PluginResolveHookResult {
          /// 解析路径,通常是绝对路径。 您还可以返回虚拟路径,并使用 [PluginLoadHookResult] 提供虚拟路径的内容
          resolvedPath: string;
          /// 该模块是否应该被 external,如果为 true,则该模块不会出现在最终结果中
          external: boolean;
          /// 该模块是否有副作用,影响tree shake
          sideEffects: boolean;
          /// 从说明符解析的查询,例如,如果说明符是`./a.png?inline`,查询应该是`{ inline: true }`
          query: [string, string][] | null;
          /// 模块的元数据,将传递给 [PluginLoadHookParam] 和 [PluginTransformHookParam]
          meta: Record<string, string> | null;
          }
          -
          备注

          解析钩子的所有过滤器 sourcesimporters 都是 正则字符串

          +
          type ResolveHook = { 
          filters: {
          importers: string[];
          sources: string[];
          };
          executor: Callback<PluginResolveHookParam, PluginResolveHookResult>
          };

          type Callback<P, R> = (
          param: P,
          context?: CompilationContext,
          hookContext?: { caller?: string; meta: Record<string, unknown> }
          ) => Promise<R | null | undefined>;

          /// resolve 钩子的参数
          export interface PluginResolveHookParam {
          /// 解析 `source` 的起始位置,如果 resolve 入口或 resolve hmr 更新,则为 [None]。
          /// 值为父模块的id,例如:`src/index.ts` 或 `src/index.vue?vue&type=xxx`
          importer: string | null;
          /// 例如,[ResolveKind::Import] 用于静态导入 (`import a from './a'`)
          kind: ResolveKind;
          /// 导入来源。 例如在index.ts中(import App from "./App.vue")
          /// 源应该是 './App.vue'
          source: string;
          }
          /// resolve 钩子的解析结果
          export interface PluginResolveHookResult {
          /// 解析路径,通常是绝对路径。 您还可以返回虚拟路径,并使用 [PluginLoadHookResult] 提供虚拟路径的内容
          resolvedPath: string;
          /// 该模块是否应该被 external,如果为 true,则该模块不会出现在最终结果中
          external: boolean;
          /// 该模块是否有副作用,影响tree shake
          sideEffects: boolean;
          /// 从说明符解析的查询,例如,如果说明符是`./a.png?inline`,查询应该是`{ inline: true }`
          query: [string, string][] | null;
          /// 模块的元数据,将传递给 [PluginLoadHookParam] 和 [PluginTransformHookParam]
          meta: Record<string, string> | null;
          }
          +
          备注

          解析钩子的所有过滤器 sourcesimporters 都是 正则字符串

          importer 解析自定义 source ,例如从 a.ts resolve ./b

          -
          a.ts
          import b from './b?raw';
          // ...
          +
          a.ts
          import b from './b?raw';
          // ...

          那么 resolve 参数将是:

          -
          const param = {
          source: "./b",
          importer: { relative_path: "a.ts", query_string: "" },
          kind: 'import'
          }
          +
          const param = {
          source: "./b",
          importer: { relative_path: "a.ts", query_string: "" },
          kind: 'import'
          }

          默认的 resolve 结果为:

          -
          const resolve_result = {
          resolved_path: "/root/b.ts", // 解析后的模块绝对路径
          external: false, // 该模块应该包含在最终编译的资源中,并且不应该被 external
          side_effects: false, // 不包含副作用,可以被 tree shake
          query: [["raw", ""]], // query 参数
          meta: {}
          }
          +
          const resolve_result = {
          resolved_path: "/root/b.ts", // 解析后的模块绝对路径
          external: false, // 该模块应该包含在最终编译的资源中,并且不应该被 external
          side_effects: false, // 不包含副作用,可以被 tree shake
          query: [["raw", ""]], // query 参数
          meta: {}
          }

          HookContext 用于在您可以递归挂钩时传递状态,例如,您的插件在 resolve hook 中调用 context.resolve

          -
          const myPlugin = () => ({
          name: 'my-plugin',
          resolve: {
          filters: {
          sources: ['^.+foo.+$'],
          importers: ['^src/index.ts$']
          },
          executor: async (param, context, hookContext) => {
          console.log(param);
          if (hookContext.caller === 'my-plugin') {
          return null;
          }
          // 替换原来的源并解析新的源
          const newSource = param.source.replace('foo', 'bar');
          return context.resolve({
          ...param,
          source: newSource
          }, {
          caller: 'my-plugin',
          meta: {}
          });
          }
          }
          });
          +
          const myPlugin = () => ({
          name: 'my-plugin',
          resolve: {
          filters: {
          sources: ['^.+foo.+$'],
          importers: ['^src/index.ts$']
          },
          executor: async (param, context, hookContext) => {
          console.log(param);
          if (hookContext.caller === 'my-plugin') {
          return null;
          }
          // 替换原来的源并解析新的源
          const newSource = param.source.replace('foo', 'bar');
          return context.resolve({
          ...param,
          source: newSource
          }, {
          caller: 'my-plugin',
          meta: {}
          });
          }
          }
          });

          在上面的例子中,我们调用 context.resolve 并传递 caller 作为参数,然后我们应该添加一个类似 if (hookContext.caller === 'my-plugin') { 的保护以避免无限循环。

          注意:

            @@ -117,26 +117,26 @@

            resolveload

            +

            load

            • required: false
            • hook type: first
            • type:
            -
            type LoadHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginLoadHookParam, PluginLoadHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginLoadHookParam {
            moduleId: string;
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            }

            export interface PluginLoadHookResult {
            /// 模块的内容
            content: string;
            /// 模块的类型,例如[ModuleType::Js]代表普通的javascript文件,
            /// 通常以 `.js` 扩展名结尾
            moduleType: ModuleType;
            sourceMap?: string | null;
            }
            +
            type LoadHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginLoadHookParam, PluginLoadHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginLoadHookParam {
            moduleId: string;
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            }

            export interface PluginLoadHookResult {
            /// 模块的内容
            content: string;
            /// 模块的类型,例如[ModuleType::Js]代表普通的javascript文件,
            /// 通常以 `.js` 扩展名结尾
            moduleType: ModuleType;
            sourceMap?: string | null;
            }

            自定义如何从已解析的模块路径或模块 ID 加载模块。 例如加载一个虚拟模块:

            -
            const myPlugin = () => ({
            name: 'my-plugin',
            load: {
            filters: {
            resolvedPaths: ['^virtual:my-plugin$'],
            },
            executor: async (param, context, hookContext) => {
            if (param.resolvedPath === 'virutal:my-plugin') {
            return {
            content: 'export default "foo"',
            moduleType: 'js'
            };
            }
            }
            }
            });
            +
            const myPlugin = () => ({
            name: 'my-plugin',
            load: {
            filters: {
            resolvedPaths: ['^virtual:my-plugin$'],
            },
            executor: async (param, context, hookContext) => {
            if (param.resolvedPath === 'virutal:my-plugin') {
            return {
            content: 'export default "foo"',
            moduleType: 'js'
            };
            }
            }
            }
            });

            load 挂钩中加载模块时需要返回 module_typecontentsource_map 是可选的,如果您在 load 钩子中进行转换(不推荐,我们建议在这种情况下使用 transform 钩子)或者从其他位置加载原始源地图,则可以返回源地图。

            load hookfilters.resolvedPathresolvedPath + query,例如:/root/src/index.vue?vue&type=style&lang=css。 如果你想在过滤模块时忽略查询,可以使用 $: src/index\\.vue$; 如果你想通过查询来过滤模块,例如过滤 lang=css,可以使用src/index.vue\\.+\\?vue&.+lang=css

            -

            transform

            +

            transform

            • required: false
            • hook type: serial
            • type:
            -
            type TransformHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginTransformHookParam, PluginTransformHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginTransformHookParam {
            moduleId: string;
            /// 加载后的源内容或上一个插件转换后的结果
            content: string;
            /// 加载后的模块类型
            moduleType: ModuleType; // Module Type is 'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'html'...
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            sourceMapChain: string[];
            }

            export interface PluginTransformHookResult {
            /// 转换后的源内容,将传递给下一个插件。
            content: string;
            /// 您可以在转换后更改模块类型。
            moduleType?: ModuleType;
            /// 转换后的源映射,所有插件转换后的源映射将存储为源映射链。
            sourceMap?: string | null;
            // 忽略之前的 source map。 如果为 true,则source map链将被清除。 这个结果应该返回一个新的source map,它结合了所有以前的 source map。
            ignorePreviousSourceMap?: boolean;
            }
            +
            type TransformHook = { 
            filters: {
            importers: string[];
            sources: string[];
            };
            executor: Callback<PluginTransformHookParam, PluginTransformHookResult>
            };

            type Callback<P, R> = (
            param: P,
            context?: CompilationContext,
            hookContext?: { caller?: string; meta: Record<string, unknown> }
            ) => Promise<R | null | undefined>;

            export interface PluginTransformHookParam {
            moduleId: string;
            /// 加载后的源内容或上一个插件转换后的结果
            content: string;
            /// 加载后的模块类型
            moduleType: ModuleType; // Module Type is 'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'html'...
            resolvedPath: string;
            query: [string, string][];
            meta: Record<string, string> | null;
            sourceMapChain: string[];
            }

            export interface PluginTransformHookResult {
            /// 转换后的源内容,将传递给下一个插件。
            content: string;
            /// 您可以在转换后更改模块类型。
            moduleType?: ModuleType;
            /// 转换后的源映射,所有插件转换后的源映射将存储为源映射链。
            sourceMap?: string | null;
            // 忽略之前的 source map。 如果为 true,则source map链将被清除。 这个结果应该返回一个新的source map,它结合了所有以前的 source map。
            ignorePreviousSourceMap?: boolean;
            }

            根据**模块内容模块类型**进行转换。 将 sass 转换为 css 的示例:

            -
            export default function farmSassPlugin(
            options: SassPluginOptions = {}
            ): JsPlugin {
            return {
            name: pluginName,
            load: {
            filters: { resolvedPaths: ['\\.(scss|sass)$'] },
            async executor(param) {
            if (param.query.length === 0 && existsSync(param.resolvedPath)) {
            const data = await readFile(param.resolvedPath);
            return {
            content: data,
            moduleType: 'sass'
            };
            }

            return null;
            }
            },
            transform: {
            filters: {
            moduleTypes: ['sass']
            },
            async executor(param, ctx) {
            const { css: compiledCss, map } = compileSass(param.content);
            return {
            content: compiledCss,
            moduleType: 'css' // transformed sass to css,
            sourceMap: JSON.stringify(map)
            ignorePreviousSourceMap: false,
            }
            }
            }
            }
            }
            +
            export default function farmSassPlugin(
            options: SassPluginOptions = {}
            ): JsPlugin {
            return {
            name: pluginName,
            load: {
            filters: { resolvedPaths: ['\\.(scss|sass)$'] },
            async executor(param) {
            if (param.query.length === 0 && existsSync(param.resolvedPath)) {
            const data = await readFile(param.resolvedPath);
            return {
            content: data,
            moduleType: 'sass'
            };
            }

            return null;
            }
            },
            transform: {
            filters: {
            moduleTypes: ['sass']
            },
            async executor(param, ctx) {
            const { css: compiledCss, map } = compileSass(param.content);
            return {
            content: compiledCss,
            moduleType: 'css' // transformed sass to css,
            sourceMap: JSON.stringify(map)
            ignorePreviousSourceMap: false,
            }
            }
            }
            }
            }

            编写 transform hook 的正常步骤:

            1. 添加基于 moduleTyperesolvedPathmoduleIdif 保护
            2. @@ -150,8 +150,8 @@

              transformfilters.resolvedPathsresolvedPath + query,例如:/root/src/index.vue?vue&type=style&lang=css。 如果你想在过滤模块时忽略查询,可以使用 $: src/index\\.vue$; 如果你想通过查询来过滤模块,例如过滤 lang=css,可以使用src/index.vue\\.+\\?vue&.+lang=css
            3. filters.moduleTypes 不是 ** regex,它必须与 ModuleType 完全匹配,如 cssjstsx 等。
          - -

          buildEnd

          +
          备注

          transform 钩子是内容到内容。 有一个类似的钩子叫做 process_moduleprocess_moduleast 到 ast。 由于性能问题,Js 插件不支持 process_module 钩子,如果您想要 ast 到 ast 转换,请尝试使用 Rust Plugin

          +

          buildEnd

    -
    备注

    buildEnd 仅在第一次编译时调用一次。 稍后编译如Lazy CompilationHMR Update不会触发buildEnd

    -

    renderStart

    +
    const myPlugin = () => {
    // 定义插件上下文
    let myPluginContext = createMyPluginContext();

    return {
    name: 'my-plugin',
    buildEnd: {
    async executor() {
    // 更新插件状态
    myPluginContext.updateStatus('module-graph-built');
    }
    }
    }
    }
    +
    备注

    buildEnd 仅在第一次编译时调用一次。 稍后编译如Lazy CompilationHMR Update不会触发buildEnd

    +

    renderStart

    • type: renderStart?: { executor: Callback<Config['config'], void>; };
    • hook type: parallel
    • @@ -169,36 +169,36 @@

      renderStart

      在资源渲染开始之前调用。

      示例:

      -
      const myPlugin = () => {
      // 定义插件上下文
      let myPluginContext = createMyPluginContext();

      return {
      name: 'my-plugin',
      renderStart: {
      async executor() {
      // 更新插件状态
      myPluginContext.updateStatus('render-start');
      }
      }
      }
      }
      -
      备注

      renderStart 仅在第一次编译时调用一次。 稍后编译如 Lazy CompilationHMR Update 将不会触发 renderStart

      -

      renderResourcePot

      +
      const myPlugin = () => {
      // 定义插件上下文
      let myPluginContext = createMyPluginContext();

      return {
      name: 'my-plugin',
      renderStart: {
      async executor() {
      // 更新插件状态
      myPluginContext.updateStatus('render-start');
      }
      }
      }
      }
      +
      备注

      renderStart 仅在第一次编译时调用一次。 稍后编译如 Lazy CompilationHMR Update 将不会触发 renderStart

      +

      renderResourcePot

      • required: false
      • hook type: serial
      • type:
      -
      type RenderResourcePotHook = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      RenderResourcePotParams,
      RenderResourcePotResult
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };

      export interface RenderResourcePotParams {
      content: string;
      sourceMapChain: string[];
      resourcePotInfo: {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      };
      }
      export interface RenderResourcePotResult {
      content: string;
      sourceMap?: string;
      }
      +
      type RenderResourcePotHook = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      RenderResourcePotParams,
      RenderResourcePotResult
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };

      export interface RenderResourcePotParams {
      content: string;
      sourceMapChain: string[];
      resourcePotInfo: {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      };
      }
      export interface RenderResourcePotResult {
      content: string;
      sourceMap?: string;
      }

      Resource Pot 是最终输出的打包后的文件的抽象表示,您可以返回转换后的 resourcePot content 来改变最终的包。 例如渲染CSS:

      -
      const myPlugin = () => ({
      name: 'test-render-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return {
      content: param.content.replace(
      '<--layer-->',
      cssCode
      ),
      sourceMap
      };
      }
      }
      })
      +
      const myPlugin = () => ({
      name: 'test-render-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return {
      content: param.content.replace(
      '<--layer-->',
      cssCode
      ),
      sourceMap
      };
      }
      }
      })

      我们将 css 资源罐中的所有 <--layer--> 进行转换,并将其替换为真正的 css 代码

      -
      备注

      当同时指定了 filters.moduleIdsfilters.resourcePotTypes 时,取并集。

      -

      augmentResourceHash

      +
      备注

      当同时指定了 filters.moduleIdsfilters.resourcePotTypes 时,取并集。

      +

      augmentResourceHash

      • required: false
      • hook type: serial
      • type:
      -
      type AugmentResourceHash = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      },
      string
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };
      +
      type AugmentResourceHash = JsPluginHook<
      {
      resourcePotTypes?: ResourcePotType[];
      moduleIds?: string[];
      },
      {
      id: string;
      name: string;
      resourcePotType: ResourcePotType;
      map?: string;
      modules: Record<ModuleId, RenderedModule>;
      moduleIds: ModuleId[];
      data: JsResourcePotInfoData;
      custom: Record<string, string>;
      },
      string
      >;

      type Callback<P, R> = (
      param: P,
      context?: CompilationContext,
      ) => Promise<R | null | undefined>;
      type JsPluginHook<F, P, R> = { filters: F; executor: Callback<P, R> };

      为给定资源罐附加资源哈希。 如果您想在生成资源哈希时添加附加条件,则非常有用。

      -
      const myPlugin = () => ({
      name: 'test-augment-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return 'my-hash-args';
      }
      }
      })
      -
      备注

      当同时指定了 filters.moduleIdsfilters.resourcePotTypes 时,取并集。

      -

      finalizeResources

      +
      const myPlugin = () => ({
      name: 'test-augment-resource-pot',
      renderResourcePot: {
      filters: {
      moduleIds: ['^index.ts\\?foo=bar$'],
      resourcePotTypes: ['css']
      },
      executor: async (param) => {
      return 'my-hash-args';
      }
      }
      })
      +
      备注

      当同时指定了 filters.moduleIdsfilters.resourcePotTypes 时,取并集。

      +

      finalizeResources

      • required: false
      • hook type: serial
      • type:
      -
      type FinalizeResourcesHook = {
      executor: Callback<
      FinalizeResourcesHookParams,
      FinalizeResourcesHookParams['resourcesMap']
      >;
      };

      export type FinalizeResourcesHookParams = {
      resourcesMap: Record<string, Resource>;
      config: Config['config'];
      };

      export interface Resource {
      name: string;
      bytes: number[];
      emitted: boolean;
      resourceType: string;
      origin: { type: 'ResourcePot' | 'Module'; value: string };
      info?: ResourcePotInfo;
      }
      +
      type FinalizeResourcesHook = {
      executor: Callback<
      FinalizeResourcesHookParams,
      FinalizeResourcesHookParams['resourcesMap']
      >;
      };

      export type FinalizeResourcesHookParams = {
      resourcesMap: Record<string, Resource>;
      config: Config['config'];
      };

      export interface Resource {
      name: string;
      bytes: number[];
      emitted: boolean;
      resourceType: string;
      origin: { type: 'ResourcePot' | 'Module'; value: string };
      info?: ResourcePotInfo;
      }

      对所有生成的资源进行一些转换,返回 转换后的resourcesMap 。 您可以在此钩子中 添加删除修改 最终生成的资源。

      注意:

        @@ -206,53 +206,53 @@

        finalizeRe
      • name 是最终的文件名。
      • origin 代表这个 Resource 的来源,ResourcePot 表示它是从 ResourcePot 生成的,而 ResourcePot 是一个模块包; Module 表示它来自 Module ,例如 .png/.jpg 等静态文件来自 Module
      -

      transformHtml

      +

      transformHtml

      • required: false
      • hook type: serial
      • type:
      -
      type TransformHtmlHook = {
      order?: 0 | 1 | 2
      executor: Callback<{ htmlResource: Resource }, Resource>;
      };
      +
      type TransformHtmlHook = {
      order?: 0 | 1 | 2
      executor: Callback<{ htmlResource: Resource }, Resource>;
      };

      order 控制 transformHtml 执行时机:

      • 0: 代表 pre, 在 parse 之前执行,在这里可以转换原始的 html。
      • 1 and 2: 代表 normal and post, 在 parse 和 generate resources 之后执行. 在这个阶段, 所有的 <script>, <link> 标签都已经被注入。

      转换最终生成的html(注入所有<script><link>标签后)。

      -
      const myPlugin = () => ({
      name: 'my-plugin',
      transformHtml: {
      order: 2,
      async executor({ htmlResource }) {
      const htmlCode = Buffer.from(htmlResource).toString();

      const newHtmlCode = htmlCode.replace('my-app-data', data);
      htmlResource.bytes = [...Buffer.from(newHtmlCode)];

      return htmlResource;
      }
      }
      });
      -
      备注

      您应该修改 htmlResourcebytes 字段并返回更新后的 htmlResource ,改变任何其他字段不会产生任何影响

      -

      writeResources

      +
      const myPlugin = () => ({
      name: 'my-plugin',
      transformHtml: {
      order: 2,
      async executor({ htmlResource }) {
      const htmlCode = Buffer.from(htmlResource).toString();

      const newHtmlCode = htmlCode.replace('my-app-data', data);
      htmlResource.bytes = [...Buffer.from(newHtmlCode)];

      return htmlResource;
      }
      }
      });
      +
      备注

      您应该修改 htmlResourcebytes 字段并返回更新后的 htmlResource ,改变任何其他字段不会产生任何影响

      +

      writeResources

      • required: false
      • hook type: serial
      • type:
      -
      type WriteResourcesHook = {
      executor: (param: FinalizeResourcesHookParams) => void | Promise<void>;
      };
      +
      type WriteResourcesHook = {
      executor: (param: FinalizeResourcesHookParams) => void | Promise<void>;
      };

      在所有资源写入磁盘之后调用。

      -

      pluginCacheLoaded

      +

      pluginCacheLoaded

      • required: false
      • hook type: serial
      • type:
      -
      type PluginCacheLoadedHook = {
      executor: Callback<number[], undefined | null | void>;
      };
      +
      type PluginCacheLoadedHook = {
      executor: Callback<number[], undefined | null | void>;
      };

      扩展插件的持久缓存加载。

      当启用 持久缓存 时,在命中缓存时可能会跳过 loadtransform 钩子。 如果您的插件依赖于以前的编译结果(例如,基于现有模块加载虚拟模块),您可能需要实现此钩子来加载插件的缓存信息,以确保缓存按预期工作。

      示例:

      -
      const myPlugin = () => {
      let cachedData;

      return {
      name: 'my-plugin',
      pluginCacheLoaded: {
      async executor(bytes) {
      const str = Buffer.from(bytes).toString();
      cachedData = JSON.parse(str);
      }
      }
      }
      }
      -
      备注

      您必须决定如何在插件中将缓存 序列化/反序列化字节 。 作为一个基本示例,您可以通过 [...Buffer.from(JSON.stringify(data))] 反序列化数据

      -

      writePluginCache

      +
      const myPlugin = () => {
      let cachedData;

      return {
      name: 'my-plugin',
      pluginCacheLoaded: {
      async executor(bytes) {
      const str = Buffer.from(bytes).toString();
      cachedData = JSON.parse(str);
      }
      }
      }
      }
      +
      备注

      您必须决定如何在插件中将缓存 序列化/反序列化字节 。 作为一个基本示例,您可以通过 [...Buffer.from(JSON.stringify(data))] 反序列化数据

      +

      writePluginCache

      • required: false
      • hook type: serial
      • type:
      -
      type WritePluginCacheHook = {
      executor: Callback<undefined, number[]>;
      };
      +
      type WritePluginCacheHook = {
      executor: Callback<undefined, number[]>;
      };

      扩展插件的持久缓存写入。 writePluginCache 通常与 pluginCacheLoaded 一起使用来读写插件的持久缓存。 返回数据的序列化字节。

      示例:

      -
      const myPlugin = () => {
      let cachedData = { foo: 'bar' };

      return {
      name: 'my-plugin',
      writePluginCache: {
      async executor() {
      const bytes = [...Buffer.from(JSON.stringify(data))];
      return bytes;
      }
      }
      }
      }
      -
      备注

      您必须决定如何在插件中将缓存 序列化/反序列化字节 。 作为一个基本示例,您可以通过 [...Buffer.from(JSON.stringify(data))] 反序列化数据

      -

      finish

      +
      const myPlugin = () => {
      let cachedData = { foo: 'bar' };

      return {
      name: 'my-plugin',
      writePluginCache: {
      async executor() {
      const bytes = [...Buffer.from(JSON.stringify(data))];
      return bytes;
      }
      }
      }
      }
      +
      备注

      您必须决定如何在插件中将缓存 序列化/反序列化字节 。 作为一个基本示例,您可以通过 [...Buffer.from(JSON.stringify(data))] 反序列化数据

      +

      finish

    -
    备注

    finish 仅在第一次编译时调用一次。 稍后编译,如 Lazy CompilationHMR Update ,不会触发 finish

    -

    updateModules

    +
    const myPlugin = () => {
    // 设置插件上下文
    let myPluginContext = createMyPluginContext();

    return {
    name: 'my-plugin',
    finish: {
    async executor() {
    // 更新插件的状态
    myPluginContext.updateStatus('finish');
    }
    }
    }
    }
    +
    备注

    finish 仅在第一次编译时调用一次。 稍后编译,如 Lazy CompilationHMR Update ,不会触发 finish

    +

    updateModules

    • required: false
    • hook type: serial
    • type:
    -
    type UpdateModulesHook = {
    executor: Callback<
    { paths: [string, string][] },
    string[] | undefined | null | void
    >;
    };
    +
    type UpdateModulesHook = {
    executor: Callback<
    { paths: [string, string][] },
    string[] | undefined | null | void
    >;
    };

    调用compiler.update(module_paths)时调用。 对于执行 HMR 时执行一些操作(例如清除以前的状态或忽略某些文件)很有用。

    • paths 是将为此更新重新编译的路径
    • 返回新的paths,后续的编译将更新返回的新路径。
    • -
    +
    \ No newline at end of file diff --git a/zh/docs/api/runtime-plugin-api/index.html b/zh/docs/api/runtime-plugin-api/index.html index c16035b83..514570963 100644 --- a/zh/docs/api/runtime-plugin-api/index.html +++ b/zh/docs/api/runtime-plugin-api/index.html @@ -8,64 +8,64 @@ - - - + + + -
    版本:1.0.0

    Runtime Plugin API

    +
    版本:1.0.0

    Runtime Plugin API

    插件钩子定义:

    -
    export interface FarmRuntimePlugin {
    // 插件名称
    name: string;
    // 模块系统启动时调用
    bootstrap?: (moduleSystem: ModuleSystem) => void | Promise<void>;
    // 新模块创建时调用
    moduleCreated?: (module: Module) => void | Promise<void>;
    // 新模块执行后调用
    moduleInitialized?: (module: Module) => void | Promise<void>;
    // 读取缓存时调用
    readModuleCache?: (module: Module) => boolean | Promise<boolean>;
    // 模块未注册时调用
    moduleNotFound?: (moduleId: string) => void | Promise<void>;
    // 加载资源时调用,在此钩子中自定义您的资源加载。
    // return { success: true } 表示该资源已成功加载。
    // return { success: false, retryWithDefaultResourceLoader: true } 表示此资源尚未成功加载,应使用默认资源加载器重试。
    loadResource?: (
    resource: Resource,
    targetEnv: 'browser' | 'node'
    ) => Promise<ResourceLoadResult>;
    }
    -

    编写运行时插件

    +
    export interface FarmRuntimePlugin {
    // 插件名称
    name: string;
    // 模块系统启动时调用
    bootstrap?: (moduleSystem: ModuleSystem) => void | Promise<void>;
    // 新模块创建时调用
    moduleCreated?: (module: Module) => void | Promise<void>;
    // 新模块执行后调用
    moduleInitialized?: (module: Module) => void | Promise<void>;
    // 读取缓存时调用
    readModuleCache?: (module: Module) => boolean | Promise<boolean>;
    // 模块未注册时调用
    moduleNotFound?: (moduleId: string) => void | Promise<void>;
    // 加载资源时调用,在此钩子中自定义您的资源加载。
    // return { success: true } 表示该资源已成功加载。
    // return { success: false, retryWithDefaultResourceLoader: true } 表示此资源尚未成功加载,应使用默认资源加载器重试。
    loadResource?: (
    resource: Resource,
    targetEnv: 'browser' | 'node'
    ) => Promise<ResourceLoadResult>;
    }
    +

    编写运行时插件

    请参阅编写运行时插件

    -

    钩子

    +

    钩子

    那么调用Farm运行时插件钩子时有两种执行顺序:

    • serial: 该钩子按照插件的顺序依次调用ono。 所有插件都会被串行调用。
    • first: 一旦返回truthy值就跳过所有剩下的插件。

    钩子执行顺序:

    -
              for each module                     true                         true                     return false
    bootstrap -----------> module registered? ------> module initialized? ----> readModuleCache -------------------------> done
    | | false |false | return true |
    | | |--------------> moduleCreated ------> moduleInitialized --|
    | |-------------------> moduleNotFound
    |
    | dynamic import
    | ---------------> loadResource
    -

    name

    +
              for each module                     true                         true                     return false
    bootstrap -----------> module registered? ------> module initialized? ----> readModuleCache -------------------------> done
    | | false |false | return true |
    | | |--------------> moduleCreated ------> moduleInitialized --|
    | |-------------------> moduleNotFound
    |
    | dynamic import
    | ---------------> loadResource
    +

    name

    • type: string

    您的运行时插件的名称。

    -

    bootstrap

    +

    bootstrap

    • hook type: serial
    • type: (moduleSystem: ModuleSystem) => void | Promise<void>

    当模块系统引导时调用一次。 在此挂钩中设置您的插件。 例子:

    -
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // define hooks
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    };
    -

    moduleCreated

    +
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // define hooks
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    };
    +

    moduleCreated

    • hook type: serial
    • type: (module: Module) => void | Promise<void>

    创建新模块实例后调用。 您可以读取或更新新创建的模块的属性。

    -
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    moduleCreated(module) {
    // 为每个模块创建一个 hot 上下文
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };
    -
    备注

    moduleCreated 在模块执行之前被调用,因此 module.exports 始终为空,如果要访问 module.exports,请使用 moduleInitialized

    -

    moduleInitialized

    +
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    moduleCreated(module) {
    // 为每个模块创建一个 hot 上下文
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };
    +
    备注

    moduleCreated 在模块执行之前被调用,因此 module.exports 始终为空,如果要访问 module.exports,请使用 moduleInitialized

    +

    moduleInitialized

    • hook type: serial
    • type: (module: Module) => void | Promise<void>

    在调用模块初始化函数后调用。

    -
    备注

    moduleCreated 在模块执行后被调用,因此 module.exports 在此钩子中可用。

    -

    readModuleCache

    +
    备注

    moduleCreated 在模块执行后被调用,因此 module.exports 在此钩子中可用。

    +

    readModuleCache

    • hook type: serial
    • type: (module: Module) => boolean | Promise<boolean>

    读取模块缓存后调用,返回 true 以跳过缓存读取并重新执行模块。

    -

    moduleNotFound

    +

    moduleNotFound

    • hook type: serial
    • type: (module: Module) => void | Promise<void>

    当模块未注册时调用。

    -

    loadResource

    +

    loadResource

    -
    import { Plugin } from '@farmfe/runtime';

    export default <Plugin>{
    name: 'runtime-plugin-example',
    loadResource: (resource, targetEnv) => {
    // 覆盖默认资源加载
    // 从不同位置加载资源
    return import('./replaced.js').then(() => {
    return {
    success: true
    };
    });
    }
    };

    +
    import { Plugin } from '@farmfe/runtime';

    export default <Plugin>{
    name: 'runtime-plugin-example',
    loadResource: (resource, targetEnv) => {
    // 覆盖默认资源加载
    // 从不同位置加载资源
    return import('./replaced.js').then(() => {
    return {
    success: true
    };
    });
    }
    };

    \ No newline at end of file diff --git a/zh/docs/api/rust-api/index.html b/zh/docs/api/rust-api/index.html index aa554eb47..3e28066dd 100644 --- a/zh/docs/api/rust-api/index.html +++ b/zh/docs/api/rust-api/index.html @@ -8,14 +8,14 @@ - - - + + + -
    版本:1.0.0

    Rust Api

    +
    版本:1.0.0

    Rust Api

    您可以在 Rust 代码中创建 Farm Rust 编译器。 例子:

    -
    use farmfe_compiler::Compiler;
    use farmfe_core::config::Config;

    // 创建 farm 编译器
    pub fn create_farm_compiler() {
    let config = Config::default();
    let extra_plugins = vec![];

    let compiler = Compiler::new(config, extra_plugins);

    compiler
    }

    // 编译项目
    pub fn compile() {
    let compiler = create_farm_compiler();
    compiler.compile()
    }

    // 执行热更新
    pub fn update(compiler: Compiler) {
    let update_result = compiler.update(vec![(String::from("/root/index.ts"), UpdateType:Update)], || {
    // 当所有更新(包括资源再生)完成时调用
    }, true);

    // 处理 update_result...
    }
    -

    Farm Rust 编译器由 farmfe_compiler crate 导出。 请参阅 farmfe_compiler 文档。

    +
    use farmfe_compiler::Compiler;
    use farmfe_core::config::Config;

    // 创建 farm 编译器
    pub fn create_farm_compiler() {
    let config = Config::default();
    let extra_plugins = vec![];

    let compiler = Compiler::new(config, extra_plugins);

    compiler
    }

    // 编译项目
    pub fn compile() {
    let compiler = create_farm_compiler();
    compiler.compile()
    }

    // 执行热更新
    pub fn update(compiler: Compiler) {
    let update_result = compiler.update(vec![(String::from("/root/index.ts"), UpdateType:Update)], || {
    // 当所有更新(包括资源再生)完成时调用
    }, true);

    // 处理 update_result...
    }
    +

    Farm Rust 编译器由 farmfe_compiler crate 导出。 请参阅 farmfe_compiler 文档。

    \ No newline at end of file diff --git a/zh/docs/api/rust-plugin-api/index.html b/zh/docs/api/rust-plugin-api/index.html index 89e6829f2..e46d9e243 100644 --- a/zh/docs/api/rust-plugin-api/index.html +++ b/zh/docs/api/rust-plugin-api/index.html @@ -8,22 +8,22 @@ - - - + + + -
    版本:1.0.0

    Rust Plugin Api

    -
    备注

    本文档仅涵盖插件钩子详情。 有关如何创建、构建和发布 rust 插件,请参阅:编写 Rust 插件

    -

    配置 Rust 插件

    +
    版本:1.0.0

    Rust Plugin Api

    +
    备注

    本文档仅涵盖插件钩子详情。 有关如何创建、构建和发布 rust 插件,请参阅:编写 Rust 插件

    +

    配置 Rust 插件

    通过 plugins 选项添加 Rust 插件:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // 在 plugins 中配置
    plugins: [
    ['@farmfe/plugin-sass', { /** 插件选项 */ }]
    ],
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // 在 plugins 中配置
    plugins: [
    ['@farmfe/plugin-sass', { /** 插件选项 */ }]
    ],
    });

    在字符串中配置 Rust 插件包名称(或路径),并在对象中配置其选项。

    -

    编写 Rust 插件

    +

    编写 Rust 插件

    有关详细信息,请参阅编写 Rust 插件

    -

    插件 Hook 概述

    +

    插件 Hook 概述

    Farm 提供了很多 rollup 风格的 hook,这些 hook 分为 build 阶段和 generate 阶段: -Farm 插件 钩子

    +Farm 插件 钩子

    所有插件挂钩都接受一个名为 CompilationContext 的参数。 所有共享的编译信息都存储在 context 中。

    Hook 共有三种(与 Rollup 相同):

      @@ -31,73 +31,73 @@

      插件 Ho
    • serial: 钩子串行执行,每个钩子的结果将传递到下一个钩子,使用最后一个钩子的结果作为最终结果。
    • parallel:钩子在线程池中并行执行,并且应该被隔离。
    -
    备注

    有关完整的 Plugin Hooks 定义,请参阅Plugin Trait

    -

    name

    +
    备注

    有关完整的 Plugin Hooks 定义,请参阅Plugin Trait

    +

    name

    • required: true
    • default:
    -
    fn name(&self) -> &str;
    +
    fn name(&self) -> &str;

    返回此插件的名称。 例子:

    -
    impl Plugin for MyPlugin {
    fn name(&self) -> &str {
    "MyPlugin"
    }
    }
    -

    priority

    +
    impl Plugin for MyPlugin {
    fn name(&self) -> &str {
    "MyPlugin"
    }
    }
    +

    priority

    • required: false
    • default:
    -
    fn priority(&self) -> i32 {
    100
    }
    +
    fn priority(&self) -> i32 {
    100
    }

    定义该插件的优先级,值越大,该插件越早执行。 当插件具有相同优先级时,它们将按照与plugins中注册的顺序相同的顺序执行。

    -
    备注

    默认情况下,所有自定义插件的优先级都是 100。有些内部插件的优先级是 99,比如 plugin-scriptplugin-css,您可以覆盖默认优先级时内部插件的行为。 但是一些内部插件的优先级是101,比如plugin-resolveplugin-html,如果你想覆盖默认行为,你应该设置一个更大的优先级。

    -

    config

    +
    备注

    默认情况下,所有自定义插件的优先级都是 100。有些内部插件的优先级是 99,比如 plugin-scriptplugin-css,您可以覆盖默认优先级时内部插件的行为。 但是一些内部插件的优先级是101,比如plugin-resolveplugin-html,如果你想覆盖默认行为,你应该设置一个更大的优先级。

    +

    config

    • required: false
    • hook type: serial
    • default:
    -
    fn config(&self, _config: &mut Config) -> Result<Option<()>> {
    Ok(None)
    }
    +
    fn config(&self, _config: &mut Config) -> Result<Option<()>> {
    Ok(None)
    }

    在编译开始之前在config钩子中修改配置。 Config 结构体的定义请参考Config。 例子:

    -
    impl Plugin for MyPlugin {
    // 实现 config hook
    fn config(&self, config: &mut Config) -> Result<Option<()>> {
    // 设置 minify 为 false
    config.input.insert("custom-entry", "./custom.html");
    Ok(Some(()))
    }
    }
    +
    impl Plugin for MyPlugin {
    // 实现 config hook
    fn config(&self, config: &mut Config) -> Result<Option<()>> {
    // 设置 minify 为 false
    config.input.insert("custom-entry", "./custom.html");
    Ok(Some(()))
    }
    }

    请注意, Rust Pluginconfig 钩子是在 JS PluginconfigconfigResolved 钩子之后调用的。

    -

    plugin_cache_loaded

    +

    plugin_cache_loaded

    • required: false
    • hook type: serial
    • default:
    -
    fn plugin_cache_loaded(
    &self,
    _cache: &Vec<u8>,
    _context: &Arc<CompilationContext>,
    ) -> Result<Option<()>> {
    Ok(None)
    }
    +
    fn plugin_cache_loaded(
    &self,
    _cache: &Vec<u8>,
    _context: &Arc<CompilationContext>,
    ) -> Result<Option<()>> {
    Ok(None)
    }

    扩展插件的持久缓存加载。

    当启用 持久缓存 时,在命中缓存时可能会跳过 加载转换 挂钩。 如果您的插件依赖于以前的编译结果(例如,基于现有模块加载虚拟模块),您可能需要实现此钩子来加载插件的缓存信息,以确保缓存按预期工作。

    例子:

    -
    #[cache_item]
    struct CachedStaticAssets {
    list: Vec<Resource>,
    }

    impl Plugin for StaticAssetsPlugin {
    fn plugin_cache_loaded(
    &self,
    cache: &Vec<u8>,
    context: &Arc<CompilationContext>,
    ) -> farmfe_core::error::Result<Option<()>> {
    let cached_static_assets: CachedAssets = deserialize!(cache, CachedStaticAssets);

    for asset in cached_static_assets.list {
    if let ResourceOrigin::Module(m) = asset.origin {
    context.emit_file(EmitFileParams {
    resolved_path: m.to_string(),
    name: asset.name,
    content: asset.bytes,
    resource_type: asset.resource_type,
    });
    }
    }

    Ok(Some(()))
    }
    }
    +
    #[cache_item]
    struct CachedStaticAssets {
    list: Vec<Resource>,
    }

    impl Plugin for StaticAssetsPlugin {
    fn plugin_cache_loaded(
    &self,
    cache: &Vec<u8>,
    context: &Arc<CompilationContext>,
    ) -> farmfe_core::error::Result<Option<()>> {
    let cached_static_assets: CachedAssets = deserialize!(cache, CachedStaticAssets);

    for asset in cached_static_assets.list {
    if let ResourceOrigin::Module(m) = asset.origin {
    context.emit_file(EmitFileParams {
    resolved_path: m.to_string(),
    name: asset.name,
    content: asset.bytes,
    resource_type: asset.resource_type,
    });
    }
    }

    Ok(Some(()))
    }
    }

    注意:

    • deserializefarmfe_core 导出,它可以帮助您反序列化 Vec<u8> 中的结构体或枚举。
    • 缓存的结构体或枚举必须是rkyv可序列化的,您可以使用farmfe_core公开的#[cache_item]快速创建可缓存的结构体。
    -

    build_start

    +

    build_start

    • required: false
    • hook type: parallel
    • default:
    -
    fn build_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
    Ok(None)
    }
    +
    fn build_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
    Ok(None)
    }

    在第一次编译开始之前调用。 您可以使用此挂钩来初始化插件的任何初始状态。

    -
    备注

    build_start 仅在第一次编译时调用一次。 如果你想在HMRLazy Compilation中更新ModuleGraph时做一些事情,你应该使用update_modules钩子。

    -

    resolve

    +
    备注

    build_start 仅在第一次编译时调用一次。 如果你想在HMRLazy Compilation中更新ModuleGraph时做一些事情,你应该使用update_modules钩子。

    +

    resolve

    • required: false
    • hook type: first
    • default:
    -
    fn resolve(
    &self,
    _param: &PluginResolveHookParam,
    _context: &Arc<CompilationContext>,
    _hook_context: &PluginHookContext,
    ) -> Result<Option<PluginResolveHookResult>> {
    Ok(None)
    }

    /// 解析钩子的参数
    #[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
    #[serde(rename_all = "camelCase")]
    pub struct PluginResolveHookParam {
    /// 我们想要解析的源,例如'./index'
    pub source: String,
    /// 解析 `specifier` 的起始位置,如果解析入口或解析 hmr 更新,则为 [None]。
    pub importer: Option<ModuleId>,
    /// 例如,[ResolveKind::Import] 用于静态导入 (`import a from './a'`)
    pub kind: ResolveKind,
    }

    #[derive(Debug, Default, Serialize, Deserialize, Clone)]
    #[serde(rename_all = "camelCase", default)]
    pub struct PluginResolveHookResult {
    /// 解析路径,通常是绝对文件路径。
    pub resolved_path: String,
    /// 该模块是否应该被 external,如果为 true,则该模块不会出现在最终结果中
    pub external: bool,
    /// 是否具有副作用,影响 tree shake
    pub side_effects: bool,
    /// 从说明符解析的查询,例如,如果说明符是`./a.png?inline`,查询应该是`{ inline: "" }`
    /// 如果你自定义插件,你的插件应该负责解析查询
    /// 如果您只想像上面的示例一样进行正常的查询解析, [farmfe_toolkit::resolve::parse_query] 应该会有所帮助
    pub query: Vec<(String, String)>,
    /// 插件和钩子之间传递的元数据
    pub meta: HashMap<String, String>,
    }
    +
    fn resolve(
    &self,
    _param: &PluginResolveHookParam,
    _context: &Arc<CompilationContext>,
    _hook_context: &PluginHookContext,
    ) -> Result<Option<PluginResolveHookResult>> {
    Ok(None)
    }

    /// 解析钩子的参数
    #[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
    #[serde(rename_all = "camelCase")]
    pub struct PluginResolveHookParam {
    /// 我们想要解析的源,例如'./index'
    pub source: String,
    /// 解析 `specifier` 的起始位置,如果解析入口或解析 hmr 更新,则为 [None]。
    pub importer: Option<ModuleId>,
    /// 例如,[ResolveKind::Import] 用于静态导入 (`import a from './a'`)
    pub kind: ResolveKind,
    }

    #[derive(Debug, Default, Serialize, Deserialize, Clone)]
    #[serde(rename_all = "camelCase", default)]
    pub struct PluginResolveHookResult {
    /// 解析路径,通常是绝对文件路径。
    pub resolved_path: String,
    /// 该模块是否应该被 external,如果为 true,则该模块不会出现在最终结果中
    pub external: bool,
    /// 是否具有副作用,影响 tree shake
    pub side_effects: bool,
    /// 从说明符解析的查询,例如,如果说明符是`./a.png?inline`,查询应该是`{ inline: "" }`
    /// 如果你自定义插件,你的插件应该负责解析查询
    /// 如果您只想像上面的示例一样进行正常的查询解析, [farmfe_toolkit::resolve::parse_query] 应该会有所帮助
    pub query: Vec<(String, String)>,
    /// 插件和钩子之间传递的元数据
    pub meta: HashMap<String, String>,
    }

    importer 解析自定义 source ,例如从 a.ts 解析 ./b

    -
    a.ts
    import b from './b?raw';
    // ...
    +
    a.ts
    import b from './b?raw';
    // ...

    那么解析参数将是:

    -
    let param = PluginResolveHookParam {
    source: "./b",
    importer: Some(ModuleId { relative_path: "a.ts", query_string: "" }),
    kind: ResolveKind::Import
    }
    +
    let param = PluginResolveHookParam {
    source: "./b",
    importer: Some(ModuleId { relative_path: "a.ts", query_string: "" }),
    kind: ResolveKind::Import
    }

    默认解析器的解析结果为:

    -
    let resolve_result = PluginResolveHookResult {
    resolved_path: "/root/b.ts", // 解析模块的绝对路径
    external: false, // 该模块应该包含在最终编译的资源中,并且不应该是外部的
    side_effects: false, // 无副作用
    query: vec![("raw", "")], // query
    meta: HashMap::new()
    }
    +
    let resolve_result = PluginResolveHookResult {
    resolved_path: "/root/b.ts", // 解析模块的绝对路径
    external: false, // 该模块应该包含在最终编译的资源中,并且不应该是外部的
    side_effects: false, // 无副作用
    query: vec![("raw", "")], // query
    meta: HashMap::new()
    }

    HookContext 用于在您可以递归挂钩时传递状态,例如,您的插件在 resolve hook 中调用 context.plugin_driver.resolve

    -
    impl Plugin for MyPlugin {
    fn resolve(
    &self,
    param: &farmfe_core::plugin::PluginResolveHookParam,
    context: &Arc<CompilationContext>,
    hook_context: &PluginHookContext,
    ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginResolveHookResult>> {
    // 添加一个守卫以避免无限循环
    if let Some(caller) = &hook_context.caller {
    if caller.as_str() == "FarmPluginCss" {
    return Ok(None);
    }
    }

    if matches!(param.kind, ResolveKind::CssAtImport | ResolveKind::CssUrl) {
    // 如果dep以'~'开头,则表示它来自node_modules。
    // 否则它总是相对的
    let source = if let Some(striped_source) = param.source.strip_suffix('~') {
    striped_source.to_string()
    } else if !param.source.starts_with('.') {
    format!("./{}", param.source)
    } else {
    param.source.clone()
    };

    // 递归调用resolve
    return context.plugin_driver.resolve(
    &PluginResolveHookParam {
    source,
    ..param.clone()
    },
    context,
    &PluginHookContext {
    caller: Some("FarmPluginCss".to_string()),
    meta: Default::default(),
    },
    );
    }

    Ok(None)
    }
    }
    +
    impl Plugin for MyPlugin {
    fn resolve(
    &self,
    param: &farmfe_core::plugin::PluginResolveHookParam,
    context: &Arc<CompilationContext>,
    hook_context: &PluginHookContext,
    ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginResolveHookResult>> {
    // 添加一个守卫以避免无限循环
    if let Some(caller) = &hook_context.caller {
    if caller.as_str() == "FarmPluginCss" {
    return Ok(None);
    }
    }

    if matches!(param.kind, ResolveKind::CssAtImport | ResolveKind::CssUrl) {
    // 如果dep以'~'开头,则表示它来自node_modules。
    // 否则它总是相对的
    let source = if let Some(striped_source) = param.source.strip_suffix('~') {
    striped_source.to_string()
    } else if !param.source.starts_with('.') {
    format!("./{}", param.source)
    } else {
    param.source.clone()
    };

    // 递归调用resolve
    return context.plugin_driver.resolve(
    &PluginResolveHookParam {
    source,
    ..param.clone()
    },
    context,
    &PluginHookContext {
    caller: Some("FarmPluginCss".to_string()),
    meta: Default::default(),
    },
    );
    }

    Ok(None)
    }
    }

    在上面的示例中,我们调用 context.plugin_driver.resolve 并将 caller 作为参数传递,然后我们应该添加一个类似 if caller.as_str() == "FarmPluginCss" 的保护以避免无限循环。

    注意:

      @@ -106,25 +106,25 @@

      resolveload

      +

      load

      • required: false
      • hook type: first
      • default:
      -
      fn load(
      &self,
      _param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookParam<'a> {
      /// 模块id字符串
      pub module_id: String,
      /// 来自解析钩子的解析路径
      pub resolved_path: &'a str,
      pub query: Vec<(String, String)>,
      /// 插件和钩子之间传递的元数据
      pub meta: HashMap<String, String>,
      }


      #[derive(Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookResult {
      /// 模块的源内容
      pub content: String,
      /// 模块的类型,例如[ModuleType::Js]代表普通的javascript文件,
      /// 通常以 `.js` 扩展名结尾
      pub module_type: ModuleType,
      pub source_map: Option<String>,
      }
      +
      fn load(
      &self,
      _param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookParam<'a> {
      /// 模块id字符串
      pub module_id: String,
      /// 来自解析钩子的解析路径
      pub resolved_path: &'a str,
      pub query: Vec<(String, String)>,
      /// 插件和钩子之间传递的元数据
      pub meta: HashMap<String, String>,
      }


      #[derive(Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginLoadHookResult {
      /// 模块的源内容
      pub content: String,
      /// 模块的类型,例如[ModuleType::Js]代表普通的javascript文件,
      /// 通常以 `.js` 扩展名结尾
      pub module_type: ModuleType,
      pub source_map: Option<String>,
      }

      自定义如何从已解析的模块路径或模块 ID 加载模块。 例如加载一个虚拟模块:

      -
      impl Plugin for MyPlugin {
      fn load(
      &self,
      param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      // 只处理指定路径
      if param.resolved_path == "virtual:my-plugin" {
      return Ok(Some(
      PluginLoadHookResult {
      content: "import real from './real-path';",
      module_type: ModuleType::Js
      source_map: None,
      }
      ))
      }

      Ok(None)
      }
      }
      +
      impl Plugin for MyPlugin {
      fn load(
      &self,
      param: &PluginLoadHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginLoadHookResult>> {
      // 只处理指定路径
      if param.resolved_path == "virtual:my-plugin" {
      return Ok(Some(
      PluginLoadHookResult {
      content: "import real from './real-path';",
      module_type: ModuleType::Js
      source_map: None,
      }
      ))
      }

      Ok(None)
      }
      }

      load 钩子中加载模块时需要 module_typecontentsource_map 是可选的,如果您在 load 钩子中进行转换(不推荐,我们建议在这种情况下使用 transform 钩子)或者从其他位置加载原始源地图,则可以返回源地图。

      -

      transform

      +

      transform

      • required: false
      • hook type: serial
      • default:
      -
      fn transform(
      &self,
      _param: &PluginTransformHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginTransformHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginTransformHookParam<'a> {
      /// 模块id字符串
      pub module_id: String,
      /// 加载后的源内容或上一个插件转换后的结果
      pub content: String,
      /// 加载后的模块类型或者上一个插件转换后的类型
      pub module_type: ModuleType,
      /// resolve 的绝对路径
      pub resolved_path: &'a str,
      pub query: Vec<(String, String)>,
      pub meta: HashMap<String, String>,
      /// 之前插件的 source map 链
      pub source_map_chain: Vec<Arc<String>>,
      }


      #[derive(Debug, Default, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginTransformHookResult {
      /// 转换后的源内容,将传递给下一个插件。
      pub content: String,
      /// 您可以在转换后更改模块类型。
      pub module_type: Option<ModuleType>,
      /// 转换后的源映射,所有插件转换后的源映射将存储为源映射链。
      pub source_map: Option<String>,
      /// 如果为true,则之前的源映射链将被忽略,并且源映射链将重置为该插件返回的[source_map]。
      pub ignore_previous_source_map: bool,
      }
      +
      fn transform(
      &self,
      _param: &PluginTransformHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginTransformHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginTransformHookParam<'a> {
      /// 模块id字符串
      pub module_id: String,
      /// 加载后的源内容或上一个插件转换后的结果
      pub content: String,
      /// 加载后的模块类型或者上一个插件转换后的类型
      pub module_type: ModuleType,
      /// resolve 的绝对路径
      pub resolved_path: &'a str,
      pub query: Vec<(String, String)>,
      pub meta: HashMap<String, String>,
      /// 之前插件的 source map 链
      pub source_map_chain: Vec<Arc<String>>,
      }


      #[derive(Debug, Default, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginTransformHookResult {
      /// 转换后的源内容,将传递给下一个插件。
      pub content: String,
      /// 您可以在转换后更改模块类型。
      pub module_type: Option<ModuleType>,
      /// 转换后的源映射,所有插件转换后的源映射将存储为源映射链。
      pub source_map: Option<String>,
      /// 如果为true,则之前的源映射链将被忽略,并且源映射链将重置为该插件返回的[source_map]。
      pub ignore_previous_source_map: bool,
      }

      根据**模块内容模块类型**进行转换。 将 sass 转换为 css 的示例:

      -
      impl Plugin for MyPlugin {
      // 忽略其他代码...
      fn transform(
      &self,
      param: &farmfe_core::plugin::PluginTransformHookParam,
      context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
      // 模块类型判断是必要的
      if param.module_type == ModuleType::Custom(String::from("sass")) {
      // parse options
      const options = parse_options(&self.options, param.module_id);
      // compile sass to css
      let compile_result = compileSass(&param.content, options);

      return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
      content: compile_result.css,
      source_map: compile_result.source_map,
      // 告诉 farm 编译器我们已经将此模块转换为 css
      module_type: Some(farmfe_core::module::ModuleType::Css),
      ignore_previous_source_map: false,
      }));
      }

      Ok(None)
      }
      }
      +
      impl Plugin for MyPlugin {
      // 忽略其他代码...
      fn transform(
      &self,
      param: &farmfe_core::plugin::PluginTransformHookParam,
      context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
      ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
      // 模块类型判断是必要的
      if param.module_type == ModuleType::Custom(String::from("sass")) {
      // parse options
      const options = parse_options(&self.options, param.module_id);
      // compile sass to css
      let compile_result = compileSass(&param.content, options);

      return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
      content: compile_result.css,
      source_map: compile_result.source_map,
      // 告诉 farm 编译器我们已经将此模块转换为 css
      module_type: Some(farmfe_core::module::ModuleType::Css),
      ignore_previous_source_map: false,
      }));
      }

      Ok(None)
      }
      }

      编写 transform hook 的正常步骤:

      1. 添加基于 module_typeresolved_pathmodule_idif 保护
      2. @@ -132,86 +132,86 @@

        transformcontent、source_mapmodule_type

      对于 ignore_previous_source_map ,如果您处理了 param.source_map_chain 并折叠了 transform hook 中以前插件的 source map。 您应该将ignore_previous_source_map设置为 true 以确保 source map 正确。 否则,您应该始终将此选项设置为 false 并让 Farm 处理 source map 链。

      -
      备注

      transform 钩子是内容到内容。 有一个类似的钩子叫做 process_moduleprocess_moduleast to ast。 所以如果你想转换加载的内容字符串,你需要使用transform钩子,如果你想转换ast,你应该使用process_module钩子。

      -

      parse

      +
      备注

      transform 钩子是内容到内容。 有一个类似的钩子叫做 process_moduleprocess_moduleast to ast。 所以如果你想转换加载的内容字符串,你需要使用transform钩子,如果你想转换ast,你应该使用process_module钩子。

      +

      parse

      • required: false
      • hook type: first
      • default:
      -
      fn parse(
      &self,
      _param: &PluginParseHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleMetaData>> {
      Ok(None)
      }

      #[derive(Debug)]
      pub struct PluginParseHookParam {
      /// module id
      pub module_id: ModuleId,
      /// resolved path
      pub resolved_path: String,
      /// resolved query
      pub query: Vec<(String, String)>,
      pub module_type: ModuleType,
      /// source content(after transform)
      pub content: Arc<String>,
      }


      /// 核心插件通过编译共享的模块元数据
      /// 核心插件不共享的元数据应存储在 [ModuleMetaData::Custom] 中
      #[cache_item]
      pub enum ModuleMetaData {
      Script(ScriptModuleMetaData),
      Css(CssModuleMetaData),
      Html(HtmlModuleMetaData),
      Custom(Box<dyn SerializeCustomModuleMetaData>),
      }
      +
      fn parse(
      &self,
      _param: &PluginParseHookParam,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleMetaData>> {
      Ok(None)
      }

      #[derive(Debug)]
      pub struct PluginParseHookParam {
      /// module id
      pub module_id: ModuleId,
      /// resolved path
      pub resolved_path: String,
      /// resolved query
      pub query: Vec<(String, String)>,
      pub module_type: ModuleType,
      /// source content(after transform)
      pub content: Arc<String>,
      }


      /// 核心插件通过编译共享的模块元数据
      /// 核心插件不共享的元数据应存储在 [ModuleMetaData::Custom] 中
      #[cache_item]
      pub enum ModuleMetaData {
      Script(ScriptModuleMetaData),
      Css(CssModuleMetaData),
      Html(HtmlModuleMetaData),
      Custom(Box<dyn SerializeCustomModuleMetaData>),
      }

      将**转换后的模块内容**解析为ast。 Farm 原生支持 Js/Jsx/Ts/Tsxcsshtml。 通常你不需要实现这个钩子,除非你想支持除了Js/Jsx/Ts/Tsxcsshtml之外的新的module_type,在这种情况下使用ModuleMetaData::Custom

      -

      process_module

      +

      process_module

      • required: false
      • hook type: serial
      • default:
      -
      fn process_module(
      &self,
      _param: &mut PluginProcessModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginProcessModuleHookParam<'a> {
      pub module_id: &'a ModuleId,
      pub module_type: &'a ModuleType,
      pub content: Arc<String>,
      pub meta: &'a mut ModuleMetaData,
      }
      +
      fn process_module(
      &self,
      _param: &mut PluginProcessModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginProcessModuleHookParam<'a> {
      pub module_id: &'a ModuleId,
      pub module_type: &'a ModuleType,
      pub content: Arc<String>,
      pub meta: &'a mut ModuleMetaData,
      }

      解析结果进行变换,通常做**ast变换**。 例如,Farm 将 ts 转换成 js:

      -
      impl Plugin for MyPlugin {
      fn process_module(
      &self,
      param: &mut PluginProcessModuleHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      if !param.module_type.is_script() {
      return Ok(None);
      }
      // 去除 ts 类型
      if param.module_type.is_typescript() {
      swc_script_transforms::strip_typescript(param, &cm, context)?;
      }
      // ...ignore other code

      Ok(Some(()))
      }

      }
      +
      impl Plugin for MyPlugin {
      fn process_module(
      &self,
      param: &mut PluginProcessModuleHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      if !param.module_type.is_script() {
      return Ok(None);
      }
      // 去除 ts 类型
      if param.module_type.is_typescript() {
      swc_script_transforms::strip_typescript(param, &cm, context)?;
      }
      // ...ignore other code

      Ok(Some(()))
      }

      }

      在上面的示例中,我们忽略非脚本模块,并且去掉 ts/tsx 模块的 ast 中类型信息。

      -

      analyze_deps

      +

      analyze_deps

      • required: false
      • hook type: serial
      • default:
      -
      fn analyze_deps(
      &self,
      _param: &mut PluginAnalyzeDepsHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginAnalyzeDepsHookParam<'a> {
      pub module: &'a Module,
      /// 分析了以前插件的依赖关系,您可以为您的插件推送新条目。
      pub deps: Vec<PluginAnalyzeDepsHookResultEntry>,
      }
      +
      fn analyze_deps(
      &self,
      _param: &mut PluginAnalyzeDepsHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginAnalyzeDepsHookParam<'a> {
      pub module: &'a Module,
      /// 分析了以前插件的依赖关系,您可以为您的插件推送新条目。
      pub deps: Vec<PluginAnalyzeDepsHookResultEntry>,
      }

      分析模块的依赖关系。 例如,我们有 a.ts

      -
      a.ts
      import b from './b';
      const c = require('./c');
      +
      a.ts
      import b from './b';
      const c = require('./c');

      那么通常这个钩子应该将2个条目推送到params.deps

      -
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./b".to_string(),
      kind: ResolveKind::Import
      });
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./c".to_string(),
      kind: ResolveKind::Require
      });
      +
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./b".to_string(),
      kind: ResolveKind::Import
      });
      param.deps.push(PluginAnalyzeDepsHookResultEntry {
      source: "./c".to_string(),
      kind: ResolveKind::Require
      });

      param.deps 稍后将传递给 resolve 钩子。 您还可以根据需要添加与模块的 ast 不相关的新 deps,Farm 将 resolveload 这些不相关的模块并将它们添加到模块图中。

      -

      finalize_modules

      +

      finalize_modules

      • required: false
      • hook type: serial
      • default:
      -
      fn finalize_module(
      &self,
      _param: &mut PluginFinalizeModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeModuleHookParam<'a> {
      pub module: &'a mut Module,
      pub deps: &'a Vec<PluginAnalyzeDepsHookResultEntry>,
      }
      +
      fn finalize_module(
      &self,
      _param: &mut PluginFinalizeModuleHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeModuleHookParam<'a> {
      pub module: &'a mut Module,
      pub deps: &'a Vec<PluginAnalyzeDepsHookResultEntry>,
      }

      在密封模块之前做任何你想做的事情。 请注意,您只能修改 param.module

      -

      build_end

      +

      build_end

      • required: false
      • hook type: parallel
      • default:
      -
      /// The module graph should be constructed and finalized here
      fn build_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// The module graph should be constructed and finalized here
      fn build_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      当从config.input开始的所有依赖都被处理并且ModuleGraph被成功构建时调用,您可以通过context.module_graph在这里获得完整解析的ModuleGraph

      -
      备注

      build_end 仅在第一次编译时调用一次。 如果你想在HMRLazy Compilation中更新ModuleGraph时做一些事情,你应该使用module_graph_updated钩子。

      -

      generate_start

      +
      备注

      build_end 仅在第一次编译时调用一次。 如果你想在HMRLazy Compilation中更新ModuleGraph时做一些事情,你应该使用module_graph_updated钩子。

      +

      generate_start

      • required: false
      • hook type: parallel
      • default:
      -
      fn generate_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn generate_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      在生成阶段开始之前调用。

      -

      optimize_module_graph

      +

      optimize_module_graph

      • required: false
      • hook type: serial
      • default:
      -
      /// 这里应该对模块图进行一些优化,例如tree shake
      fn optimize_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// 这里应该对模块图进行一些优化,例如tree shake
      fn optimize_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      您可以在此处对 module_graph 进行优化。 对于内部插件,Farm 在这个钩子中进行树摇动和缩小。

      -

      analyze_module_graph

      +

      analyze_module_graph

      • required: false
      • hook type: first
      • default:
      -
      /// 根据模块图分析模块组
      fn analyze_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleGroupGraph>> {
      Ok(None)
      }
      +
      /// 根据模块图分析模块组
      fn analyze_module_graph(
      &self,
      _module_graph: &mut ModuleGraph,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ModuleGroupGraph>> {
      Ok(None)
      }

      分析module_graph的**动态导入,并根据动态导入**对模块进行分组,返回分组后的模块。

      -
      注意

      通常你不应该实现这个钩子,除非你想在 Farm 中实现一个全新的打包算法。

      -

      partial_bundling

      +
      注意

      通常你不应该实现这个钩子,除非你想在 Farm 中实现一个全新的打包算法。

      +

      partial_bundling

      • required: false
      • hook type: first
      • default:
      -
      /// 局部打包模块到 [Vec<ResourcePot>]
      fn partial_bundling(
      &self,
      _modules: &Vec<ModuleId>,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<Vec<ResourcePot>>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,
      /// 如果此 [ResourcePot] 不包含入口模块,则 [None]。
      /// [一些(entry_id)] 否则
      pub entry_module: Option<ModuleId>,
      /// 这个[ResourcePot]中生成的资源
      resources: HashSet<String>,

      /// 此 [ResourcePot] 所属的模块组。
      /// 一个[ResourcePot]可以属于多个模块组。
      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      }
      +
      /// 局部打包模块到 [Vec<ResourcePot>]
      fn partial_bundling(
      &self,
      _modules: &Vec<ModuleId>,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<Vec<ResourcePot>>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,
      /// 如果此 [ResourcePot] 不包含入口模块,则 [None]。
      /// [一些(entry_id)] 否则
      pub entry_module: Option<ModuleId>,
      /// 这个[ResourcePot]中生成的资源
      resources: HashSet<String>,

      /// 此 [ResourcePot] 所属的模块组。
      /// 一个[ResourcePot]可以属于多个模块组。
      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      }

      基于 module_group_graphmodule_graphmodules 打包到 Vec<ResourcePot>ResourcePot 是 Farm 用于保存打包模块的结构,它将被生成到 generate_resources 钩子中的最终资源,您可以将 ResourcePot 视为其他工具的 Chunk

      注意:

        @@ -219,141 +219,141 @@

        partial_bun
      • 你应该在这个钩子中设置module.resource_pot

      请参阅 Farm 中部分捆绑的内部实现以获得最佳实践。 请参阅 RFC-003 部分捆绑 了解 Farm 如何设计捆绑。

      -
      注意

      通常你不应该实现这个钩子,除非你想在 Farm 中实现一个全新的打包算法。 如果您覆盖此挂钩,除非您遵循与 Farm 相同的打包规范,否则 config.partial_bundling 可能无法工作。

      -

      process_resource_pots

      +
      注意

      通常你不应该实现这个钩子,除非你想在 Farm 中实现一个全新的打包算法。 如果您覆盖此挂钩,除非您遵循与 Farm 相同的打包规范,否则 config.partial_bundling 可能无法工作。

      +

      process_resource_pots

      • required: false
      • hook type: serial
      • default:
      -
      /// 在渲染和生成每个资源之前处理 resource pot
      fn process_resource_pots(
      &self,
      _resource_pots: &mut Vec<&mut ResourcePot>,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// 在渲染和生成每个资源之前处理 resource pot
      fn process_resource_pots(
      &self,
      _resource_pots: &mut Vec<&mut ResourcePot>,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      ResourcePots 进行一些转换。 注意,此时ResourcePots还没有渲染,这意味着你无法获取ResourcePot的渲染代码,只能添加,删除,改造ResourcePot内部的模块

      -

      render_start

      +

      render_start

      • required: false
      • hook type: serial
      • default:
      -
      fn render_start(
      &self,
      _config: &Config,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn render_start(
      &self,
      _config: &Config,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      在 resource pot 渲染之前调用。 渲染 resource pot 后,将产出可执行的 htmlcssjs 等文件。

      -
      备注

      render_start 仅在第一次编译时调用一次。 HMRLazy Compilation 不会触发 render_start 钩子。

      -

      render_resource_pot_modules

      +
      备注

      render_start 仅在第一次编译时调用一次。 HMRLazy Compilation 不会触发 render_start 钩子。

      +

      render_resource_pot_modules

      • required: false
      • hook type: first
      • default:
      -
      fn render_resource_pot_modules(
      &self,
      _resource_pot: &ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ResourcePotMetaData>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
      pub struct RenderedModule {
      pub id: ModuleId,
      pub rendered_content: Arc<String>,
      pub rendered_map: Option<Arc<String>>,
      pub rendered_length: usize,
      pub original_length: usize,
      }

      #[cache_item]
      #[derive(Clone, Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotMetaData {
      pub rendered_modules: HashMap<ModuleId, RenderedModule>,
      pub rendered_content: Arc<String>,
      pub rendered_map_chain: Vec<Arc<String>>,
      pub custom_data: HashMap<String, String>,
      }
      +
      fn render_resource_pot_modules(
      &self,
      _resource_pot: &ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<ResourcePotMetaData>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
      pub struct RenderedModule {
      pub id: ModuleId,
      pub rendered_content: Arc<String>,
      pub rendered_map: Option<Arc<String>>,
      pub rendered_length: usize,
      pub original_length: usize,
      }

      #[cache_item]
      #[derive(Clone, Debug, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotMetaData {
      pub rendered_modules: HashMap<ModuleId, RenderedModule>,
      pub rendered_content: Arc<String>,
      pub rendered_map_chain: Vec<Arc<String>>,
      pub custom_data: HashMap<String, String>,
      }

      将给定的 ResourcePot 渲染为 rendered_contentrendered_source_map_chain 。 该钩子用于将 模块的 ast 渲染为打包代码。 如果您只想修改打包代码,请改用 render_resource_pot

      如果您确实需要使用此钩子,请参阅 plugin_runtime 以获得最佳实践。

      -
      备注

      通常,您不应该为原生支持的模块类型(如 js/jsx/ts/tsx/css/html )覆盖此钩子,只有当您确保要覆盖 Farm 中内部模块类型的默认行为时,才应该使用此钩子, 或者您想支持自定义模块类型

      -

      render_resource_pot

      +
      备注

      通常,您不应该为原生支持的模块类型(如 js/jsx/ts/tsx/css/html )覆盖此钩子,只有当您确保要覆盖 Farm 中内部模块类型的默认行为时,才应该使用此钩子, 或者您想支持自定义模块类型

      +

      render_resource_pot

      • required: false
      • hook type: serial
      • default:
      -
      fn render_resource_pot(
      &self,
      _param: &PluginRenderResourcePotHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginRenderResourcePotHookParam {
      pub content: Arc<String>,
      pub source_map_chain: Vec<Arc<String>>,
      pub resource_pot_info: ResourcePotInfo,
      }

      #[derive(Debug, Serialize, Deserialize)]
      pub struct PluginRenderResourcePotHookResult {
      pub content: String,
      pub source_map: Option<String>,
      }
      +
      fn render_resource_pot(
      &self,
      _param: &PluginRenderResourcePotHookParam,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginRenderResourcePotHookParam {
      pub content: Arc<String>,
      pub source_map_chain: Vec<Arc<String>>,
      pub resource_pot_info: ResourcePotInfo,
      }

      #[derive(Debug, Serialize, Deserialize)]
      pub struct PluginRenderResourcePotHookResult {
      pub content: String,
      pub source_map: Option<String>,
      }

      转换给定 ResourcePot 的渲染捆绑代码。 返回 渲染内容source map

      -
      impl Plugin for MyPlugin {
      fn render_resource_pot(
      &self,
      param: &PluginRenderResourcePotHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      if (param.resource_pot_info.resource_pot_type == ResourcePotType::Css) {
      return Ok(Some(PluginRenderResourcePotHookResult {
      content: param.content.replaceAll("<--layer-->", replaced_code),
      source_map: replaced_map,
      }))
      }

      Ok(None)
      }
      }
      +
      impl Plugin for MyPlugin {
      fn render_resource_pot(
      &self,
      param: &PluginRenderResourcePotHookParam,
      context: &Arc<CompilationContext>,
      ) -> Result<Option<PluginRenderResourcePotHookResult>> {
      if (param.resource_pot_info.resource_pot_type == ResourcePotType::Css) {
      return Ok(Some(PluginRenderResourcePotHookResult {
      content: param.content.replaceAll("<--layer-->", replaced_code),
      source_map: replaced_map,
      }))
      }

      Ok(None)
      }
      }

      在上面的示例中,我们转换了 css Resource Pot 的内容,将所有 <--layer--> 替换为 replaced_code

      -

      augment_resource_hash

      +

      augment_resource_hash

      • required: false
      • hook type: serial
      • default:
      -
      fn augment_resource_hash(
      &self,
      _render_pot_info: &ResourcePotInfo,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<String>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotInfo {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      pub module_ids: Vec<ModuleId>,
      pub map: Option<Arc<String>>,
      pub modules: HashMap<ModuleId, RenderedModule>,
      pub data: ResourcePotInfoData,
      }
      +
      fn augment_resource_hash(
      &self,
      _render_pot_info: &ResourcePotInfo,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<String>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePotInfo {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      pub module_ids: Vec<ModuleId>,
      pub map: Option<Arc<String>>,
      pub modules: HashMap<ModuleId, RenderedModule>,
      pub data: ResourcePotInfoData,
      }

      从给定 resource pot 生成资源时附加额外哈希。

      -

      optimize_resource_pot

      +

      optimize_resource_pot

      • required: false
      • hook type: serial
      • default:
      -
      /// 优化资源罐,例如压缩
      fn optimize_resource_pot(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,

      pub entry_module: Option<ModuleId>,
      resources: HashSet<String>,

      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      pub info: Box<ResourcePotInfo>,
      }
      +
      /// 优化资源罐,例如压缩
      fn optimize_resource_pot(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct ResourcePot {
      pub id: ResourcePotId,
      pub name: String,
      pub resource_pot_type: ResourcePotType,
      modules: HashSet<ModuleId>,
      pub meta: ResourcePotMetaData,

      pub entry_module: Option<ModuleId>,
      resources: HashSet<String>,

      pub module_groups: HashSet<ModuleGroupId>,
      pub immutable: bool,
      pub info: Box<ResourcePotInfo>,
      }

      对渲染的 resource pot 进行一些优化。 例如,替换、压缩等等。 如果要修改此钩子的渲染内容,只需修改 resource_pot.meta.rendered_content 并将此转换的 source map 附加到 resource_pot.meta.rendered_source_map_chain 中。

      -
      备注

      像压缩这样的优化是由 Farm 内部处理的,请确保您确实需要使用这个钩子。

      -

      generate_resources

      +
      备注

      像压缩这样的优化是由 Farm 内部处理的,请确保您确实需要使用这个钩子。

      +

      generate_resources

      • required: false
      • hook type: first
      • default:
      -
      /// 根据[ResourcePot]生成资源,返回[Vec<Resource>]代表最终生成的文件。
      /// 例如一个.js文件及其对应的source map文件
      fn generate_resources(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginGenerateResourcesHookResult>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginGenerateResourcesHookResult {
      pub resource: Resource,
      pub source_map: Option<Resource>,
      }
      +
      /// 根据[ResourcePot]生成资源,返回[Vec<Resource>]代表最终生成的文件。
      /// 例如一个.js文件及其对应的source map文件
      fn generate_resources(
      &self,
      _resource_pot: &mut ResourcePot,
      _context: &Arc<CompilationContext>,
      _hook_context: &PluginHookContext,
      ) -> Result<Option<PluginGenerateResourcesHookResult>> {
      Ok(None)
      }

      #[cache_item]
      #[derive(Debug, Clone, Deserialize)]
      #[serde(rename_all = "camelCase")]
      pub struct PluginGenerateResourcesHookResult {
      pub resource: Resource,
      pub source_map: Option<Resource>,
      }

      为给定的渲染 resource pot 生成最终资源。 返回 生成的资源可选的 source map

      -
      备注

      对于原生支持的 ModuleTypes ,如 js/ts/jsx/tsx/css/html/static assets ,通常不需要实现此钩子。 当您想要支持 Farm 本身不支持的新型资源时,请使用此钩子。

      -

      finalize_resources

      +
      备注

      对于原生支持的 ModuleTypes ,如 js/ts/jsx/tsx/css/html/static assets ,通常不需要实现此钩子。 当您想要支持 Farm 本身不支持的新型资源时,请使用此钩子。

      +

      finalize_resources

      • required: false
      • hook type: serial
      • default:
      -
      /// 对生成的资源做一些终结工作,例如根据生成的资源转换html
      fn finalize_resources(
      &self,
      _param: &mut PluginFinalizeResourcesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeResourcesHookParams<'a> {
      pub resources_map: &'a mut HashMap<String, Resource>,
      pub config: &'a Config,
      }
      +
      /// 对生成的资源做一些终结工作,例如根据生成的资源转换html
      fn finalize_resources(
      &self,
      _param: &mut PluginFinalizeResourcesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      pub struct PluginFinalizeResourcesHookParams<'a> {
      pub resources_map: &'a mut HashMap<String, Resource>,
      pub config: &'a Config,
      }

      对生成的资源进行一些最终的处理工作,例如根据生成的资源转换html(插入<script><link>标签)。

      您还可以在此处 添加删除 资源。

      -

      generate_end

      +

      generate_end

      • required: false
      • hook type: parallel
      • default:
      -
      fn generate_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn generate_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      当所有生成阶段完成时调用(包括 finalize_resources )。 您可以在这里做一些清理工作。

      -

      finish

      +

      finish

      • required: false
      • hook type: parallel
      • default:
      -
      fn finish(&self, _stat: &Stats, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }
      +
      fn finish(&self, _stat: &Stats, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
      Ok(None)
      }

      当所有编译工作完成时调用(包括 构建阶段生成阶段 )。 您可以在这里做一些清理工作。

      -
      备注

      finish 仅在第一次编译时调用一次。 HMRLazy Compilation 不会触发 finish 钩子。 您应该使用 update_finished 钩子代替。

      -

      write_plugin_cache

      +
      备注

      finish 仅在第一次编译时调用一次。 HMRLazy Compilation 不会触发 finish 钩子。 您应该使用 update_finished 钩子代替。

      +

      write_plugin_cache

      • required: false
      • hook type: serial
      • default:
      -
      fn write_plugin_cache(&self, _context: &Arc<CompilationContext>) -> Result<Option<Vec<u8>>> {
      Ok(None)
      }
      +
      fn write_plugin_cache(&self, _context: &Arc<CompilationContext>) -> Result<Option<Vec<u8>>> {
      Ok(None)
      }

      扩展插件的持久缓存写入。 write_plugin_cache 通常与 plugin_cache_loaded 一起使用来读写插件的持久缓存。 返回数据的序列化字节。

      例如,为静态资源写入缓存:

      -
      impl Plugin for MyPlugin {
      fn write_plugin_cache(
      &self,
      context: &Arc<CompilationContext>,
      ) -> farmfe_core::error::Result<Option<Vec<u8>>> {
      let mut list = vec![];
      let resources_map = context.resources_map.lock();

      for (_, resource) in resources_map.iter() {
      if let ResourceOrigin::Module(m) = &resource.origin {
      if context.module_graph.read().has_module(m) {
      list.push(resource.clone());
      }
      }
      }

      if !list.is_empty() {
      let cached_static_assets = CachedStaticAssets { list };

      Ok(Some(serialize!(&cached_static_assets)))
      } else {
      Ok(None)
      }
      }
      }

      #[cache_item]
      struct CachedStaticAssets {
      list: Vec<Resource>,
      }
      -

      update_modules

      +
      impl Plugin for MyPlugin {
      fn write_plugin_cache(
      &self,
      context: &Arc<CompilationContext>,
      ) -> farmfe_core::error::Result<Option<Vec<u8>>> {
      let mut list = vec![];
      let resources_map = context.resources_map.lock();

      for (_, resource) in resources_map.iter() {
      if let ResourceOrigin::Module(m) = &resource.origin {
      if context.module_graph.read().has_module(m) {
      list.push(resource.clone());
      }
      }
      }

      if !list.is_empty() {
      let cached_static_assets = CachedStaticAssets { list };

      Ok(Some(serialize!(&cached_static_assets)))
      } else {
      Ok(None)
      }
      }
      }

      #[cache_item]
      struct CachedStaticAssets {
      list: Vec<Resource>,
      }
      +

      update_modules

      • required: false
      • hook type: serial
      • default:
      -
      /// 调用compiler.update(module_paths)时调用。
      /// 在执行 HMR 时可用于执行一些操作,例如清除以前的状态或忽略某些文件
      fn update_modules(
      &self,
      _params: &mut PluginUpdateModulesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginUpdateModulesHookParams {
      pub paths: Vec<(String, UpdateType)>,
      }
      +
      /// 调用compiler.update(module_paths)时调用。
      /// 在执行 HMR 时可用于执行一些操作,例如清除以前的状态或忽略某些文件
      fn update_modules(
      &self,
      _params: &mut PluginUpdateModulesHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginUpdateModulesHookParams {
      pub paths: Vec<(String, UpdateType)>,
      }

      调用compiler.update(module_paths)时调用。 在执行 HMR 时可用于执行一些操作,例如清除以前的状态或忽略某些文件

      • paths 是将为此更新重新编译的路径
      • 返回新的paths,后续编译将更新返回的新路径。
      -

      module_graph_updated

      +

      module_graph_updated

      • required: false
      • hook type: serial
      • default:
      -
      /// 调用compiler.update(module_paths)时调用。
      /// 用于执行一些操作,例如修改模块图
      fn module_graph_updated(
      &self,
      _param: &PluginModuleGraphUpdatedHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginModuleGraphUpdatedHookParams {
      pub added_modules_ids: Vec<ModuleId>,
      pub removed_modules_ids: Vec<ModuleId>,
      pub updated_modules_ids: Vec<ModuleId>,
      }
      +
      /// 调用compiler.update(module_paths)时调用。
      /// 用于执行一些操作,例如修改模块图
      fn module_graph_updated(
      &self,
      _param: &PluginModuleGraphUpdatedHookParams,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      #[derive(Debug, Clone, Serialize, Deserialize)]
      #[serde(rename_all = "camelCase", default)]
      pub struct PluginModuleGraphUpdatedHookParams {
      pub added_modules_ids: Vec<ModuleId>,
      pub removed_modules_ids: Vec<ModuleId>,
      pub updated_modules_ids: Vec<ModuleId>,
      }

      调用compiler.update(module_paths)时调用。 对于执行一些操作(例如修改模块图)很有用。

      -

      update_finished

      +

      update_finished

      • required: false
      • hook type: serial
      • default:
      -
      /// 调用compiler.update(module_paths)时调用。
      /// 该钩子在所有编译工作完成后调用,包括资源重新生成和终结。
      fn update_finished(
      &self,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }
      +
      /// 调用compiler.update(module_paths)时调用。
      /// 该钩子在所有编译工作完成后调用,包括资源重新生成和终结。
      fn update_finished(
      &self,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<()>> {
      Ok(None)
      }

      调用compiler.update(module_paths)时调用。 该钩子在所有编译工作完成后调用,包括资源重新生成和最终处理。

      -

      handle_persistent_cached_module

      +

      handle_persistent_cached_module

      • required: false
      • hook type: serial
      • default:
      -
      fn handle_persistent_cached_module(
      &self,
      _module: &farmfe_core::module::Module,
      _context: &Arc<CompilationContext>,
      ) -> Result<Option<bool>> {
      Ok(None)
      }
      -

      当启用持久缓存并且模块的缓存命中时调用。 返回 true跳过加载此模块的缓存

    +
    fn handle_persistent_cached_module(
    &self,
    _module: &farmfe_core::module::Module,
    _context: &Arc<CompilationContext>,
    ) -> Result<Option<bool>> {
    Ok(None)
    }
    +

    当启用持久缓存并且模块的缓存命中时调用。 返回 true跳过加载此模块的缓存

    \ No newline at end of file diff --git a/zh/docs/benchmark/index.html b/zh/docs/benchmark/index.html index 87305bf8d..4fbf3dbbd 100644 --- a/zh/docs/benchmark/index.html +++ b/zh/docs/benchmark/index.html @@ -8,27 +8,27 @@ - - - + + + -
    版本:1.0.0

    Benchmarks

    -

    Introduction

    +
    版本:1.0.0

    Benchmarks

    +

    Introduction

    Using Turbopack's bench cases (1000 React components), see https://turbo.build/pack/docs/benchmarks.

    -

    Run this benchmark yourself

    +

    Run this benchmark yourself

    Test Repo:https://github.com/farm-fe/performance-compare

    Test Machine(Linux Mint 21.1 Cinnamon, 11th Gen Intel© Core™ i5-11400 @ 2.60GHz × 6, 15.5 GiB)

    -

    Install dependencies

    -
    npm
    yarn
    pnpm
    bun
    npm install
    -

    run benchmark

    -
    npm
    yarn
    pnpm
    bun
    npm benchmark
    -

    Data

    +

    Install dependencies

    +
    npm
    yarn
    pnpm
    bun
    npm install
    +

    run benchmark

    +
    npm
    yarn
    pnpm
    bun
    npm benchmark
    +

    Data

    StartupHMR (Root)HMR (Leaf)Production Build
    Webpack8035ms345ms265ms11321ms
    Vite3078ms35ms18ms2266ms
    Rspack831ms104ms96ms724ms
    Farm403ms11ms10ms288ms

    -

    metrics

    +

    metrics

    • Cold StartUp Time: The time it takes to develop a build without caching

      @@ -54,13 +54,13 @@

      metricsBenchmark for all metrics

      +

      Benchmark for all metrics

      -

      Benchmark of HMR

      +

      Benchmark of HMR

      -

      Benchmark of Startup

      +

      Benchmark of Startup

      -

      Benchmark of Production Build

      -
    +

    Benchmark of Production Build

    +
    \ No newline at end of file diff --git a/zh/docs/cli/cli-api/index.html b/zh/docs/cli/cli-api/index.html index 49d52322b..5e3a6f13e 100644 --- a/zh/docs/cli/cli-api/index.html +++ b/zh/docs/cli/cli-api/index.html @@ -8,31 +8,31 @@ - - - + + + -
    版本:1.0.0

    Farm 命令行

    +
    版本:1.0.0

    Farm 命令行

    Farm Cli 允许您启动、构建、预览和监听您的应用程序。

    如果需要查看 Farm Cli 的可用命令, 您可以在终端中执行以下命令

    -
    Terminal
    npx farm -h
    +
    Terminal
    npx farm -h

    The output look like this:

    -
    Terminal
    farm/0.5.11

    Usage:
    $ farm [root]

    Commands:
    [root]
    start 启动开发服务器
    build 在生产环境下构建项目
    watch 监听文件变化并且重新构建
    preview 在本地可以直接预览您的生产环境构建出的产物
    clean [path] 清理`farm`增量构建的缓存文件
    plugin [command] 管理插件的命令

    For more info, run any command with the `--help` flag:
    $ farm --help
    $ farm build --help
    $ farm watch --help
    $ farm preview --help
    $ farm clean --help
    $ farm plugin --help

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -v, --version 查看当前版本
    -

    Start

    +
    Terminal
    farm/0.5.11

    Usage:
    $ farm [root]

    Commands:
    [root]
    start 启动开发服务器
    build 在生产环境下构建项目
    watch 监听文件变化并且重新构建
    preview 在本地可以直接预览您的生产环境构建出的产物
    clean [path] 清理`farm`增量构建的缓存文件
    plugin [command] 管理插件的命令

    For more info, run any command with the `--help` flag:
    $ farm --help
    $ farm build --help
    $ farm watch --help
    $ farm preview --help
    $ farm clean --help
    $ farm plugin --help

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -v, --version 查看当前版本
    +

    Start

    farm start 命令用于启动开发服务器, 将代码进行开发环境的编译

    -
    Terminal
    Usage:
    $ farm [root]

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -

    Build

    +
    Terminal
    Usage:
    $ farm [root]

    Options:
    -l, --lazy 默认情况下,Farm 会在开发中延迟编译动态导入的模块,只有在模块真正执行时才会编译它们。懒惰编译确实可以加快大型项目的编译速度。
    --host <host> host(主机)选项。它允许你指定服务器的主机地址。你可以将其设置为特定的IP地址或域名。
    --port <port> 端口)选项。它允许你指定服务器的端口号。你可以将其设置为任何未被占用的端口号。
    --open 打开)选项。它在服务器启动时自动打开浏览器。这对于快速预览你的应用程序或网站非常方便。
    --hmr 热模块替换)选项。它启用热模块替换功能,允许在运行时替换模块,而无需刷新整个页面。这对于开发过程中的实时更新非常有用。
    --cors (跨域资源共享)选项。它启用跨域资源共享,允许从不同域的服务器请求资源。这对于开发涉及跨域请求的应用程序非常有用。
    --strictPort (严格端口)选项。如果指定的端口已经被占用,它会导致服务器退出并显示错误消息。
    -c, --config <file> (配置文件)选项。它允许你指定一个特定的配置文件来配置你的项目。你可以将其设置为文件的路径。
    -m, --mode <mode> (环境模式)选项。它允许你设置项目的环境变量。环境模式可以是开发模式、生产模式或其他自定义模式。
    --base <path> (基础路径)选项。它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen (清除屏幕)选项。它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    +

    Build

    farm build 命令会在默认的 dist 目录下构建出可用于生产环境的产物。

    -
    Terminal
    Usage:
    $ farm build

    Options:
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -w, --watch 是否监听文件并且重新构建
    --targetEnv <target> 构建环境 node, browser
    --format <format> 构建产物格式 esm, commonjs
    --sourcemap 是否输出 sourcemap
    --treeShaking 消除无用代码而不会产生副作用
    --minify 构建时的代码压缩
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -

    Preview

    +
    Terminal
    Usage:
    $ farm build

    Options:
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -w, --watch 是否监听文件并且重新构建
    --targetEnv <target> 构建环境 node, browser
    --format <format> 构建产物格式 esm, commonjs
    --sourcemap 是否输出 sourcemap
    --treeShaking 消除无用代码而不会产生副作用
    --minify 构建时的代码压缩
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    +

    Preview

    farm preview 用于在本地可以直接预览您的生产环境构建出的产物, 您需要提前执行 farm build 来构建出生产环境的产物

    -
    Terminal
    Usage:
    $ farm preview

    Options:
    --open [url] 启动时是否在浏览器中打开页面
    --port <port> 设置 Server 监听的端口号
    --host <host> 指定 Server 启动时监听的 host
    -c --config <config> 指定配置文件路径
    -h, --help 显示命令帮助
    -

    Watch

    +
    Terminal
    Usage:
    $ farm preview

    Options:
    --open [url] 启动时是否在浏览器中打开页面
    --port <port> 设置 Server 监听的端口号
    --host <host> 指定 Server 启动时监听的 host
    -c --config <config> 指定配置文件路径
    -h, --help 显示命令帮助
    +

    Watch

    farm watch 一般作用于 node 环境下监听文件变化并且重新构建

    -
    Terminal

    Usage:
    $ farm watch

    Options:
    --format <format> 构建产物格式 esm, commonjs
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    -

    Clean

    +
    Terminal

    Usage:
    $ farm watch

    Options:
    --format <format> 构建产物格式 esm, commonjs
    -o, --outDir <dir> 输出构建产物
    -i, --input <file> 入口文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    +

    Clean

    farm clean 由于 farm 提供的增量构建会在本地生成缓存文件, 如果在特定情况下(不可预知的编译错误)可能您需要清理缓存文件

    -
    Terminal
    Usage:
    $ farm clean [path]

    Options:
    --recursive 递归搜索 `node_modules` 目录并清除缓存文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    +
    Terminal
    Usage:
    $ farm clean [path]

    Options:
    --recursive 递归搜索 `node_modules` 目录并清除缓存文件
    -c, --config <file> 使用指定的配置文件
    -m, --mode <mode> 设置环境模式
    --base <path> 它允许你指定公共基础路径,用于解析静态资源的相对路径。
    --clearScreen 它允许你在记录日志时启用或禁用清除屏幕的功能。这对于在终端中保持日志清晰可见非常有用。
    -h, --help 显示命令帮助信息
    \ No newline at end of file diff --git a/zh/docs/community/index.html b/zh/docs/community/index.html index acd5a5d1b..ef282482f 100644 --- a/zh/docs/community/index.html +++ b/zh/docs/community/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/docs/comparisons/index.html b/zh/docs/comparisons/index.html index 1d1b56c08..9151223be 100644 --- a/zh/docs/comparisons/index.html +++ b/zh/docs/comparisons/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/docs/config/cli/index.html b/zh/docs/config/cli/index.html index ed6d0c0a1..3d2fa80bc 100644 --- a/zh/docs/config/cli/index.html +++ b/zh/docs/config/cli/index.html @@ -8,27 +8,27 @@ - - - + + + -
    版本:1.0.0

    CLI 选项

    -

    create

    +
    版本:1.0.0

    CLI 选项

    +

    create

    创建一个新的Farm项目。

    -
    pnpm create farm
    # 或 npm create farm
    # 或 yarn create farm
    # choose your favorite package manager
    +
    pnpm create farm
    # 或 npm create farm
    # 或 yarn create farm
    # choose your favorite package manager

    其他命令由包 @farmfe/cli 提供:

    -

    start

    +

    start

    启动开发服务器,在开发模式下编译 Farm 项目并监视文件更改。

    -
    farm start
    -

    build

    +
    farm start
    +

    build

    以生产模式构建 Farm 项目

    -
    farm build
    -

    preview

    +
    farm build
    +

    preview

    预览 build 命令的结果。

    -
    farm build && farm preview
    -

    watch

    +
    farm build && farm preview
    +

    watch

    Watch 通常用于编译库项目,它的工作方式类似于 start 命令,但它不会启动开发服务器。

    -
    farm watch
    +
    farm watch
    \ No newline at end of file diff --git a/zh/docs/config/compilation-options/index.html b/zh/docs/config/compilation-options/index.html index 2a67dd3fe..eb9c20474 100644 --- a/zh/docs/config/compilation-options/index.html +++ b/zh/docs/config/compilation-options/index.html @@ -8,30 +8,30 @@ - - - + + + -
    版本:1.0.0

    编译配置 - compilation

    +
    版本:1.0.0

    编译配置 - compilation

    Farm 默认从项目根目录的 farm.config.ts|js|mjs 文件中读取配置,配置文件示例:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // 编译的根目录
    // 编译选项
    compilation: {
    // ...
    },
    // Dev Server 选项
    server: {
    hmr: true,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // 编译的根目录
    // 编译选项
    compilation: {
    // ...
    },
    // Dev Server 选项
    server: {
    hmr: true,
    // ...
    },
    // 插件配置
    plugins: [],
    });

    本文档仅介绍 编译 选项的详细信息。 对于 servershared 选项,请参阅 servershared

    -

    编译选项 - compilation

    +

    编译选项 - compilation

    所有与编译相关的配置都在 compilation 字段下。

    -

    input

    +

    input

    • type: Record<string, string>

    项目的入口点。 Input 的文件可以是htmlts/js/tsx/jsxcss 或通过插件支持的其他文件。

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    -

    output

    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    input: {
    index: "./index.html",
    about: "./about.html",
    },
    },
    // ..
    };
    +

    output

    • type: OutputOptions
    -
    interface OutputOptions {
    // 局部打包后,入口文件所在资源的文件名配置
    entryFilename?: string;
    // 局部打包后,除入口资源外的其他资源输入文件名配置
    filename?: string;
    // 输入目录
    path?: string;
    // public path:资源加载前缀
    publicPath?: string;
    // 静态资源文件名配置
    assetsFilename?: string;
    // 目标执行环境,浏览器或者 Node
    targetEnv?: "browser" | "node";
    // 输出模块格式
    format?: "cjs" | "esm";
    }
    -
    备注

    我们称编译结果为 资源(resource)

    -

    output.entryFilename

    +
    interface OutputOptions {
    // 局部打包后,入口文件所在资源的文件名配置
    entryFilename?: string;
    // 局部打包后,除入口资源外的其他资源输入文件名配置
    filename?: string;
    // 输入目录
    path?: string;
    // public path:资源加载前缀
    publicPath?: string;
    // 静态资源文件名配置
    assetsFilename?: string;
    // 目标执行环境,浏览器或者 Node
    targetEnv?: "browser" | "node";
    // 输出模块格式
    format?: "cjs" | "esm";
    }
    +
    备注

    我们称编译结果为 资源(resource)

    +

    output.entryFilename

    • 默认值: "[entryName].[ext]"
    @@ -42,7 +42,7 @@

    ou
  • [contentHash]:该资源的内容哈希。
  • [ext]:该资源的扩展名,对于 js/jsx/ts/tsxjs,对于 css/scss/lesscss
  • -

    output.filename

    +

    output.filename

    • 默认值: "[resourceName].[ext]"
    @@ -52,26 +52,26 @@

    output.
  • [contentHash]:该资源的内容哈希。
  • [ext]:该资源的扩展名,对于 js/jsx/ts/tsxjs,对于 css/scss/lesscss
  • -

    output.path

    +

    output.path

    • 默认值: "dist"

    输出资源的目录

    -

    output.publicPath

    +

    output.publicPath

    • 默认值: "/"

    资源 url 加载前缀。 例如 URL https://xxxx 或绝对路径 /xxx/。 例如配置:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    output: {
    publicPath: process.env.NODE_ENV === 'production' ? 'https://cdn.com' : '/'
    }
    }
    // ...
    });
    +
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    output: {
    publicPath: process.env.NODE_ENV === 'production' ? 'https://cdn.com' : '/'
    }
    }
    // ...
    });

    在构建时,注入的资源 URL 将为 https://cdn.com/index-s2f3.s14dqwa.js 。 例如,在输出 html 中,所有 <script><link> 将为:

    -
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>
    +
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>

    当加载动态脚本和CSS时,动态获取的资源url也将是:https://cdn.com/<asset-path>

    -

    output.assetsFileName

    +

    output.assetsFileName

    • 默认值: "[resourceName].[ext]"

    静态资源输出的文件名配置,占位符和 output.filename 相同。

    -

    output.targetEnv

    +

    output.targetEnv

    • 默认"browser-es2017"
    @@ -91,124 +91,124 @@

    output
  • node-next:将项目编译到最新的 Node 版本,不会注入任何 polyfill。
  • nodenode16的别名
  • -

    output.format

    +

    output.format

    • 默认值: "esm"

    配置产物的格式,可以是 "esm" 或者 "cjs".

    -
    备注

    该选项只对 Js 产物有效

    -

    resolve

    +
    备注

    该选项只对 Js 产物有效

    +

    resolve

    • type: ResolveOptions
    -
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    -

    resolve.extensions

    +
    interface ResolveOptions {
    extensions?: string[];
    alias?: Record<string, string>;
    mainFields?: string[];
    conditions?: string[];
    symlinks?: boolean;
    strictExports?: boolean;
    }
    +

    resolve.extensions

    • 默认值: ["tsx", "ts", "jsx", "js", "mjs", "json", "html", "css"]

    配置解析依赖时的后缀,例如解析 ./index 时,如果没有解析到,则会自动加上后缀解析,如尝试 ./index.tsx, ./index.css 等。

    -

    resolve.alias

    +

    resolve.alias

    • 默认值: {}

    配置解析别名,示例:

    -
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });
    +
    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    "/@": path.join(process.cwd(), "src"),
    stream$: "readable-stream",
    "$__farm_regex:^/(utils)$": path.join(process.cwd(), "src/$1"),
    },
    },
    },
    });

    alias 为前缀替换,对于上述例子 /@/pages 将会被替换为,/root/src/pages

    如果希望精确匹配,可以加上 $,例如 stream$ 只会替换 stream,而不会替换 stream/xxx

    当然也支持使用正则表达式,例如 $__farm_regex:^/(utils)$,将会匹配 /utils,并替换为 /root/src/utils

    -

    resolve.mainFields

    +

    resolve.mainFields

    • 默认值: ["exports", "browser", "module", "main"]

    解析 node_modules 下依赖时,从 package.json 中将会按照 mainFields 中配置的字段和顺序进行解析。对于 package.json

    -
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }
    +
    {
    "name": "package-a",
    "module": "es/index.js",
    "main": "lib/index.js"
    }

    将会优先使用 es/index.js(如果路径存在),不存在则会继续向后搜索。

    -

    resolve.conditions

    +

    resolve.conditions

    暂不支持配置。

    - +
    • 默认值: true

    解析文件时,是否追踪 symlink 对应的真实目录,并从真实目录开始解析下一个依赖。如果使用 pnpm 管理依赖,该选项必须配置为 true。

    -

    resolve.strictExports

    +

    resolve.strictExports

    • 默认值: false

    是否严格遵循 package.jsonexports 中定义的导出。如果设置为 true,当 package.json 中定义了 exports,但是 exports 没有定义对应导出时,会直接报错。如果设置为 true,会按照 mainFields 继续尝试其他入口。

    -

    define

    +

    define

    • 默认值: {}

    全局变量注入,配置的变量名和值将会在编译时注入到产物中。Farm 默认注入 process.env.NODE_ENV 以及部分 Farm 自身使用的变量比如 FARM_HMR_PORT

    -
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123,
    },
    },
    });
    -

    external

    +
    export default defineConfig({
    compilation: {
    define: {
    MY_VAR: 123,
    },
    },
    });
    +

    external

    • 默认值: []
    • 类型: (string | Record<string, string>)[]

    配置被 external 的导入,被 external 的导入不会出现在编译产物中。但是对应 import 语句不会删除,需要自定义 external 后如何处理,否则运行时会报错,对于 targetEnv 是 node 下的 external 模块,会自动尝试 require 该模块。

    需要使用正则方式配置,例如:

    -
    export default defineConfig({
    compilation: {
    external: ["^stream$", { jquery: "Jquery" }],
    },
    });
    -

    externalNodeBuiltins

    +
    export default defineConfig({
    compilation: {
    external: ["^stream$", { jquery: "Jquery" }],
    },
    });
    +

    externalNodeBuiltins

    • 默认true

    无论是否外部 module.builtinModules,默认情况下,所有内置模块(如 fs)都将是外部的。 您还可以将 externalNodeBuiltins 设置为 array 以手动将模块指定为外部:

    -
    export default defineConfig({
    compilation: {
    externalNodeBuiltins: ["^stream$"],
    },
    });
    -

    mode

    +
    export default defineConfig({
    compilation: {
    externalNodeBuiltins: ["^stream$"],
    },
    });
    +

    mode

    • 默认值: 对于 start、watch 命令是 development,对于 build 命令是 production

    配置编译模式,为了优化开发时性能,在没有手动配置生产优化相关选项(minify,tree shake 等)时,默认在 development 下会禁用生产环境优化比如压缩和 tree shake,在 production 模式下启用。

    -

    root

    +

    root

    • 默认值: process.cwd()

    配置项目编译的 root 目录,该选项会影响默认配置文件的查找路径,编译模块依赖的查找等。

    -

    runtime

    +

    runtime

    配置 Farm 运行时能力。类型如下:

    -
    interface FarmRuntimeOptions {
    runtime?: {
    path: string;
    plugins?: string[];
    namespace?: string;
    isolate?: boolean;
    };
    }
    -

    runtime.path

    +
    interface FarmRuntimeOptions {
    runtime?: {
    path: string;
    plugins?: string[];
    namespace?: string;
    isolate?: boolean;
    };
    }
    +

    runtime.path

    • 默认值: Farm 内置 runtime 的路径

    自定义一个 Runtime 替换 Farm 内置的 Runtime。

    -
    注意

    正常情况下不建议配置该选项,因为一旦配置了该选项,指向的 runtime 需要所有实现 Farm Runtime 已有的能力,例如模块系统、HMR、动态资源加载等。

    -

    runtime.plugins

    +
    注意

    正常情况下不建议配置该选项,因为一旦配置了该选项,指向的 runtime 需要所有实现 Farm Runtime 已有的能力,例如模块系统、HMR、动态资源加载等。

    +

    runtime.plugins

    • 默认值: Farm 内置 runtime-plugin-hmr 的路径

    配置 Runtime 插件,通过 Runtime 插件,可以干预 Runtime 行为,如模块加载,资源加载等。具体可以参考:WIP。

    -

    runtime.namespace

    +

    runtime.namespace

    • 默认值: 项目 package.json 的 name 字段

    配置 Farm Runtime 的命名空间,保证在同一个 window 或者 global 下不同产物的执行能够相互隔离。默认使用项目 package.json 的 name 字段作为 namespace。

    -

    runtime.isolate

    +

    runtime.isolate

    • 默认值: false

    默认情况下,html 中的运行时文件是内联写入的。如果您想以单独文件的形式弹出,从而减小 html 文件的大小,那么可以将此属性设为 true。 如果设置为 true,农场入口脚本将以单独文件的形式发布。

    -

    assets

    -

    assets.include

    +

    assets

    +

    assets.include

    • 默认值: []

    额外视为静态资源的文件后缀,例如下述示例,txt 将会被视为姿态资源,引入 txt 文件时当作静态资源处理:

    -
    export default defineConfig({
    compilation: {
    assets: {
    include: ["txt"],
    },
    },
    });
    -

    script

    -

    script.target

    +
    export default defineConfig({
    compilation: {
    assets: {
    include: ["txt"],
    },
    },
    });
    +

    script

    +

    script.target

    • 默认值: esnext(根据 Farm 的迭代动态调整)

    配置 Farm 解析 js/jsx/ts/tsx 的 AST 以及生成代码时支持的 ES 语法版本。 可选值:es5, es6, es2015 - es2023, esnext

    -

    script.parser

    +

    script.parser

    • 默认值: 与 SWC 相同

    配置 SWC 解析 AST 时的行为,配置项参考:https://swc.rs/docs/configuration/compilation#jscparser

    -

    script.plugins

    +

    script.plugins

    • 默认值: []
    @@ -219,9 +219,9 @@

    script.p
  • filters: 对哪些模块执行该插件,必须配置,支持 resolvedPathsmoduleTypes 这两个过滤项,两者如果同时指定,取并集。
  • 对于 Vue 项目支持 JSX 的配置示例如下:

    -
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };
    -

    script.decorators

    -
    export interface DecoratorsConfig {
    legacyDecorator: boolean;
    decoratorMetadata: boolean;
    /**
    * 装饰器版本: 2021-12 或者 2022-03
    * @default 2021-12
    */
    decoratorVersion: "2021-12" | "2022-03" | null;
    /**
    * @default []
    */
    includes: string[];
    /**
    * @default ["node_modules/"]
    */
    excludes: string[];
    }
    +
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };
    +

    script.decorators

    +
    export interface DecoratorsConfig {
    legacyDecorator: boolean;
    decoratorMetadata: boolean;
    /**
    * 装饰器版本: 2021-12 或者 2022-03
    * @default 2021-12
    */
    decoratorVersion: "2021-12" | "2022-03" | null;
    /**
    * @default []
    */
    includes: string[];
    /**
    * @default ["node_modules/"]
    */
    excludes: string[];
    }

    建议使用 Farm 默认的装饰器配置,除非你想提高性能,可以设置includesexcludes

    选项:

      @@ -231,36 +231,36 @@

      scrip
    • 包括:默认为[]。如果要包含排除的模块,可以设置此选项。支持正则表达式。
    • 排除:默认为['node_modules/']。变换装饰器时,这些路径下的模块将被忽略。支持正则表达式
    -

    css

    -

    css.modules

    +

    css

    +

    css.modules

    配置 Farm CSS Modules。

    -
    interface FarmCssModulesConfig {
    // 配置哪些路径会被处理为 css modules,使用正则字符串
    // 默认为 `.module.css` 或者 `.module.scss` 或者 `.module.less`
    paths?: string[];
    // 配置生成的 css 类名,默认为 `[name]-[hash]`
    indentName?: string;
    }
    -
    css.modules.paths
    +
    interface FarmCssModulesConfig {
    // 配置哪些路径会被处理为 css modules,使用正则字符串
    // 默认为 `.module.css` 或者 `.module.scss` 或者 `.module.less`
    paths?: string[];
    // 配置生成的 css 类名,默认为 `[name]-[hash]`
    indentName?: string;
    }
    +
    css.modules.paths
    • 默认值: ["\\.module\\.(css|scss|sass|less)"]

    配置哪些路径对应的模块会被视为 CSS Modules。需要配置正则字符串。默认是以 .module.(css|scss|sass|less) 结尾的文件。

    -
    css.modules.identName
    +
    css.modules.identName
    • 默认值: [name]-[hash]

    配置生成的 CSS Modules 类名,默认是 [name]-[hash][name], [hash] 为占位符(也是目前支持的所有占位符)。[name] 表示原始类名,[hash] 表示改 css 文件 id 的 hash。

    -

    css.prefixer

    +

    css.prefixer

    配置 CSS 的兼容性前缀,例如 -webkit-

    -
    interface FarmCssPrefixer {
    targets?: string[] | string | BrowserTargetsRecord;
    }

    type BrowserTargetsRecord = Partial<
    Record<
    | "chrome"
    | "opera"
    | "edge"
    | "firefox"
    | "safari"
    | "ie"
    | "ios"
    | "android"
    | "node"
    | "electron",
    string
    >
    > & { [key: string]: string };
    -
    css.prefixer.targets
    +
    interface FarmCssPrefixer {
    targets?: string[] | string | BrowserTargetsRecord;
    }

    type BrowserTargetsRecord = Partial<
    Record<
    | "chrome"
    | "opera"
    | "edge"
    | "firefox"
    | "safari"
    | "ie"
    | "ios"
    | "android"
    | "node"
    | "electron",
    string
    >
    > & { [key: string]: string };
    +
    css.prefixer.targets
    • 默认值: undefined

    配置对于哪些目标浏览器或者浏览器版本开启,示例:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    css: {
    prefixer: {
    targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
    },
    },
    },
    });
    -

    html

    -

    html.base

    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    css: {
    prefixer: {
    targets: ["last 2 versions", "Firefox ESR", "> 1%", "ie >= 11"],
    },
    },
    },
    });
    +

    html

    +

    html.base

    • 默认值: undefined

    所有的 HTML 入口会继承 html.base,详情参考 指南 - HTML

    -

    sourcemap

    +

    sourcemap

    • 默认值: true
    @@ -272,25 +272,25 @@

    sourcemapall:对所有文件生成 sourcemap,并且生成单独的 sourcemap 文件
  • all-inline: 对所有的文件生成 sourcemap,并且内联 sourcemap 到产物中,不生成单独的文件
  • -

    partialBundling

    +

    partialBundling

    配置 Farm 局部打包的行为,详情可以参考 局部打包

    -
    export interface FarmPartialBundlingConfig {
    targetConcurrentRequests?: number;
    targetMinSize?: number;
    targetMaxSize?: number;
    groups?: {
    name: string;
    test: string[];
    groupType?: "mutable" | "immutable";
    resourceType?: "all" | "initial" | "async";
    }[];
    enforceResources?: {
    name: string;
    test: string[];
    }[];
    enforceTargetConcurrentRequests?: boolean;
    enforceTargetMinSize?: boolean;
    immutableModules?: string[];
    }
    -

    partialBundling.targetConcurrentRequests

    +
    export interface FarmPartialBundlingConfig {
    targetConcurrentRequests?: number;
    targetMinSize?: number;
    targetMaxSize?: number;
    groups?: {
    name: string;
    test: string[];
    groupType?: "mutable" | "immutable";
    resourceType?: "all" | "initial" | "async";
    }[];
    enforceResources?: {
    name: string;
    test: string[];
    }[];
    enforceTargetConcurrentRequests?: boolean;
    enforceTargetMinSize?: boolean;
    immutableModules?: string[];
    }
    +

    partialBundling.targetConcurrentRequests

    • default: 25

    Farm 尝试生成尽可能接近此配置值的资源数量,控制初始资源加载或动态资源加载的并发请求数量。

    -

    partialBundling.targetMinSize

    +

    partialBundling.targetMinSize

    • default: 20 * 1024 bytes, 20 KB

    minify 和 gzip 之前生成的资源的最小大小。 请注意,targetMinSize 并不一定保证满足,可以配置enforceTargetMinSize可用于强制限制最小的大小。

    -

    partialBundling.targetMaxSize

    +

    partialBundling.targetMaxSize

    • default: 1500 * 1024 bytes, 1500 KB

    minify 和 gzip 之前生成的资源的最大大小。

    -

    partialBundling.groups

    +

    partialBundling.groups

    • default: []
    @@ -302,8 +302,8 @@

  • groupType: mutableimmutable,限制该组仅适用于指定类型的模块。
  • resourceType: allinitialasync,限制该组仅适用于指定类型的资源。
  • -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    groups: [
    {
    name: "vendor-react",
    test: ["node_modules/"],
    },
    ],
    },
    },
    });
    -

    partialBundling.enforceResources

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    groups: [
    {
    name: "vendor-react",
    test: ["node_modules/"],
    },
    ],
    },
    },
    });
    +

    partialBundling.enforceResources

    • default: []
    @@ -313,122 +313,122 @@

    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: "index",
    test: [".+"],
    },
    ],
    },
    },
    });

    -
    注意

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    -

    partialBundling.enforceTargetConcurrentRequests

    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    enforceResources: [
    {
    name: "index",
    test: [".+"],
    },
    ],
    },
    },
    });
    +
    注意

    enforceResources will ignore all Farm's internal optimization, be careful when you use it.

    +

    partialBundling.enforceTargetConcurrentRequests

    • default: false

    对每个资源加载强制执行目标并发请求数量,当为 true 时,较小的资源将合并为较大的资源以满足目标并发请求。 这可能会导致 css 资源出现问题,请小心使用此选项

    -

    partialBundling.enforceTargetMinSize

    +

    partialBundling.enforceTargetMinSize

    • default: false

    为每个资源强制执行目标最小大小限制,如果为真,较小的资源将合并为较大的资源以满足目标并发请求。 这可能会导致 css 资源出现问题,请小心使用此选项

    -

    partialBundling.immutableModules

    +

    partialBundling.immutableModules

    • default: ['node_modules']

    匹配不可变模块的正则表达式数组

    -
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });
    +
    farm.config.ts
    export default defineConfig({
    compilation: {
    partialBundling: {
    immutableModules: ["node_modules/", "/global-constants"],
    },
    },
    });

    不可变模块会影响打包和持久缓存,如果要更改它,请小心。

    -

    partialBundling.immutableModulesWeight

    +

    partialBundling.immutableModulesWeight

    • default: 0.8

    Default to 0.8, immutable module will have 80% request numbers. For example, if targetConcurrentRequest is 25, then immutable resources will take 25 * 80% = 20 by default. This option is to make sure that mutable and immutable modules are isolate, if change your business code, code under node_modules won't be affected.

    -

    lazyCompilation

    +

    lazyCompilation

    • 默认值: 在开发模式是 true,构建模式是 false

    是否启用懒编译,配置为 false 关闭。参考 懒编译

    -

    treeShaking

    +

    treeShaking

    • 默认值: 在开发模式是 false,构建模式是 true

    是否启用 tree shake,配置为 false 关闭。参考 Tree Shake

    -

    minify

    +

    minify

    • 默认值: 在开发模式是 false,构建模式是 true
    • 类型: bool | JsMinifyOptions

    是否启用压缩,开启后将会对产物进行压缩和混淆。参考 压缩

    -

    minify.compress

    +

    minify.compress

    压缩参数

    -

    minify.mangle

    +

    minify.mangle

    压缩变量参数

    -

    minify.include

    +

    minify.include

    • 默认值: []
    • 类型: string[]

    包含需要压缩的模块,默认全部,仅在 minify.modeminify-module 生效

    -

    minify.exclude

    +

    minify.exclude

    • 默认值: ["*.min.(js|css|html)"]
    • 类型: string[]

    排除不需要压缩模块,仅在 minify.modeminify-module 生效

    -

    minify.mode

    +

    minify.mode

    • 默认值: 'minify-module'
    • 类型: 'minify-module' | 'minify-resource-pot'

    minify-module 模块级别 minify,可以通过参数控制需要 minify 哪些模块,压缩的更为精细,效率更好

    minify-resource-pot ResourcePot 级别 minify,无法通过参数控制具体的模块

    -

    presetEnv

    +

    presetEnv

    • 默认值: 在开发模式是 false,构建模式是 true
    -
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };
    +
    type FarmPresetEnvConfig =
    | boolean
    | {
    include?: string[];
    exclude?: string[];
    // TODO using swc's config
    options?: any;
    assumptions?: any;
    };

    默认不会对 node_modules 下的模块注入 polyfill,如果需要,请使用 include 添加 polyfill。

    -

    presetEnv.include

    +

    presetEnv.include

    • 默认值: []

    额外包含哪些需要 polyfill 的模块,配置正则字符串,例如 include: ['node_modules/(es6-package|my-package)/']

    -

    presetEnv.exclude

    +

    presetEnv.exclude

    • 默认值: ['node_modules/']

    配置哪些不需要 polyfill 的模块,配置正则字符串,例如 exclude: ['custom-path/(es5-package|my-package)/']。默认 node_modules 被排除,如果需要包含被排除的模块,建议使用 include

    -

    presetEnv.options

    +

    presetEnv.options

    • 默认值: 降级到 ES5

    传递给 swc preset env 的选项,参考 https://swc.rs/docs/configuration/compilation#env。

    -

    persistentCache

    +

    persistentCache

    • default: true

    增量构建 的缓存配置选项. 配置成 false 来禁用缓存.

    -
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    -

    persistentCache.namespace

    +
    export type PersistentCache =
    | boolean
    | {
    namespace?: string;
    cacheDir?: string;
    buildDependencies?: string[];
    moduleCacheKeyStrategy?: {
    timestamp?: boolean;
    hash?: boolean;
    };
    };
    +

    persistentCache.namespace

    • default: farm-cache

    缓存的命名空间,不同空间下的缓存会相互隔离,不会复用。

    -

    persistentCache.cacheDir

    +

    persistentCache.cacheDir

    • default: node_modules/.farm/cache

    缓存文件的存放目录。

    -

    persistentCache.buildDependencies

    +

    persistentCache.buildDependencies

    • default: farm.config.ts and all its deep dependencies

    所有配置文件、插件等构建依赖的路径,默认包含 farm.config.ts/js/mjs 的所有依赖以及配置的所有 rust 和 js 插件。如果任意一个构建依赖变更了,所有缓存将会失效。

    配置项可以是一个路径或者一个包名, 例如:

    -
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    -

    persistentCache.moduleCacheKeyStrategy

    +
    import { defineConfig } from "@farmfe/core";
    import path from "node:path";

    export default defineConfig({
    persistentCache: {
    buildDependencies: [
    // a file path
    path.resolve(process.cwd(), "./plugins/my-plugin.js"),
    // a package name, note that this package must expose package.json
    "farm-plugin-custom-xxx",
    ],
    },
    });
    +

    persistentCache.moduleCacheKeyStrategy

    • default: { timestamp: true, hash: true }
    @@ -437,17 +437,17 @@

    注意事项.
  • hash: 是否检查 load 和 transform 后的内容。
  • -

    persistentCache.envs

    +

    persistentCache.envs

    可能影响构建过程的环境变量,如果任意一个环境变化了,缓存将会过期。

    -

    progress

    +

    progress

    • default: true

    是否启动进度条

    -

    comments

    +

    comments

    • default: license
    @@ -456,6 +456,6 @@

    comments

    +
    \ No newline at end of file diff --git a/zh/docs/config/configuring-farm/index.html b/zh/docs/config/configuring-farm/index.html index 3ffdf5ff0..486803b91 100644 --- a/zh/docs/config/configuring-farm/index.html +++ b/zh/docs/config/configuring-farm/index.html @@ -8,33 +8,33 @@ - - - + + + -
    版本:1.0.0

    配置 Farm

    -

    配置文件规范

    +
    版本:1.0.0

    配置 Farm

    +

    配置文件规范

    默认情况下,Farm 从项目根目录下的“farm.config.ts|js|mjs”文件中读取配置,示例配置文件:

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // // 编译的根目录
    // 编译选项
    compilation: {
    //...
    },
    // 开发服务器选项
    server: {
    hmr: true,
    //...
    },
    // 插件配置
    plugins: [],
    });
    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    root: process.cwd(), // // 编译的根目录
    // 编译选项
    compilation: {
    //...
    },
    // 开发服务器选项
    server: {
    hmr: true,
    //...
    },
    // 插件配置
    plugins: [],
    });

    有关配置选项的详细信息,请参阅:

    • 编译器选项: 配置编译器选项(compilation字段),如inputoutputcss 编译打包配置等。
    • 开发服务器选项: 配置开发服务器选项(server字段),如porthostprotocol等。
    • 共享选项: 配置共享选项,如 rootenv 等。
    -
    备注

    您还可以使用“farm start/build -c my-config.ts”将自定义文件用作配置文件。

    -

    加载Ts配置文件

    +
    备注

    您还可以使用“farm start/build -c my-config.ts”将自定义文件用作配置文件。

    +

    加载Ts配置文件

    Farm 支持开箱即用加载 ts 配置文件,如“farm.config.ts”。 Farm 将首先将“farm.config.ts”及其本地 ts 依赖项打包到“farm-config.xxx.mjs”文件中,然后从磁盘加载它。 由于 Farm 将 farm.config.ts 编译为 mjs 文件,因此您 不能farm.config.ts 中使用 __dirname__filename,请使用 import.meta.url 作为替代。

    或者您可以使用“farm.config.mjs”或“farm.config.cjs”与“@type”来支持类型,避免打包“farm.config.ts”:

    -
    farm.config.mjs
    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    // ...
    }
    -

    示例

    -

    输入和输出

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    input: {
    index: './src/index.html',
    about: './src/about.html',
    },
    output: {
    path: 'build',
    publicPath: process.env.NODE_ENV === 'production' ? 'https://my-cdn.com' : '/'
    }
    },
    });
    +
    farm.config.mjs
    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    // ...
    }
    +

    示例

    +

    输入和输出

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    input: {
    index: './src/index.html',
    about: './src/about.html',
    },
    output: {
    path: 'build',
    publicPath: process.env.NODE_ENV === 'production' ? 'https://my-cdn.com' : '/'
    }
    },
    });

    In above example, we configured ./src/index.html and ./src/about.html as input, then output the compiled resources to build dir.

    -

    开发服务器端口

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    port: 9801
    }
    });
    -

    仅用默认优化策略

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    lazyCompilation: false,
    persistentCache: false,
    minify: false,
    treeShake: false
    },
    });
    +

    开发服务器端口

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    server: {
    port: 9801
    }
    });
    +

    仅用默认优化策略

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // compile options
    compilation: {
    lazyCompilation: false,
    persistentCache: false,
    minify: false,
    treeShake: false
    },
    });
    \ No newline at end of file diff --git a/zh/docs/config/dev-server/index.html b/zh/docs/config/dev-server/index.html index 9abd4a4e1..e4e127f88 100644 --- a/zh/docs/config/dev-server/index.html +++ b/zh/docs/config/dev-server/index.html @@ -8,59 +8,59 @@ - - - + + + -
    版本:1.0.0

    DevServer 配置 - server

    +
    版本:1.0.0

    DevServer 配置 - server

    配置 Farm Dev Server 的行为。示例:

    -
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    port: 9000,
    // ...
    },
    });
    +
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    port: 9000,
    // ...
    },
    });

    类型:

    -
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: "http" | "https";
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    -

    port

    +
    export interface UserServerConfig {
    port?: number;
    // https?: boolean;
    protocol?: "http" | "https";
    hostname?: string;
    // http2?: boolean;
    hmr?: boolean | UserHmrConfig;
    proxy?: Record<string, ProxiesOptions>;
    strictPort?: boolean;
    open?: boolean;
    host?: string;
    cors?: boolean | cors.Options;
    // whether to serve static assets in spa mode, default to true
    spa?: boolean;
    plugins?: DevServerPlugin[];
    writeToDisk?: boolean;
    }
    +

    port

    • 默认值: 9000

    DevServer 监听的端口。

    -

    hmr

    +

    hmr

    • 默认值: 对于 start 命令是 true,其他命令是 false

    启用 HMR,开启后启用 HMR 能力,将会监听编译过程中涉及到的模块的变动,当模块变化时,自动触发重编译并将结果推送给 Farm Runtime 进行更新。也可以通过一个对象来配置 HMR,例如:

    -
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    hmr: {
    // 配置 web socket 监听的端口
    port: 9802
    // 配置 web socket 监听的 host
    host: 'localhost',
    // 配置文件监听时,忽略的文件
    ignores: ['auto_generated/*']
    }
    // ...
    }
    });
    -

    hmr.port

    +
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // 所有 dev server 选项都在 server 下面
    server: {
    hmr: {
    // 配置 web socket 监听的端口
    port: 9802
    // 配置 web socket 监听的 host
    host: 'localhost',
    // 配置文件监听时,忽略的文件
    ignores: ['auto_generated/*']
    }
    // ...
    }
    });
    +

    hmr.port

    • 默认值: 9801

    Web Socket 服务器监听的端口

    -

    hmr.host

    +

    hmr.host

    • 默认值: localhost

    Web Socket 服务器监听的 Host

    -

    proxy

    +

    proxy

    • 默认值: undefined

    配置服务器代理。基于 http-proxy 实现,具体选项参考其文档,示例:

    -
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    -

    open

    +
    import type { UserConfig } from "@farmfe/core";

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    server: {
    proxy: {
    "/api": {
    target: "https://music-erkelost.vercel.app/banner",
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ""),
    },
    },
    },
    });
    +

    open

    • 默认值: false

    编译完成后自动打开浏览器到对应的页面。

    -

    host

    +

    host

    • 默认值: localhost

    Dev Server 监听的 host。

    -

    plugins

    +

    plugins

    • 默认值: []

    配置 Farm 的 Dev Server 插件,通过 Dev Server 插件可以扩展 DevServer 的上下文,添加 middleware 等。插件就是一个函数,插件示例如下:

    -
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host,
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(
    devServer.getCompiler(),
    devServer,
    logger
    );
    }
    }
    -

    然后将该插件配置到 server.plugins 中。

    +
    export function hmrPlugin(devServer: DevServer) {
    const { config, logger } = devServer;
    if (config.hmr) {
    devServer.ws = new WebSocketServer({
    port: config.hmr.port,
    host: config.hmr.host,
    });
    devServer.app().use(hmr(devServer));
    devServer.hmrEngine = new HmrEngine(
    devServer.getCompiler(),
    devServer,
    logger
    );
    }
    }
    +

    然后将该插件配置到 server.plugins 中。

    \ No newline at end of file diff --git a/zh/docs/config/shared/index.html b/zh/docs/config/shared/index.html index 779098c0a..394a1c908 100644 --- a/zh/docs/config/shared/index.html +++ b/zh/docs/config/shared/index.html @@ -8,53 +8,53 @@ - - - + + + -
    版本:1.0.0

    通用配置

    +
    版本:1.0.0

    通用配置

    为 Farm 的 DevServer 和编译器配置共享选项。 例如:

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    root: process.cwd(),
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // All dev server options are under server
    root: process.cwd(),
    });

    类型:

    -
    export interface UserConfig {
    /** 该项目的当前根目录,默认为当前工作目录 */
    root?: string;
    clearScreen?: boolean;
    envDir?: string;
    envPrefix?: string | string[];
    /** 该目录下的文件将始终被视为静态资产。 在dev中提供它,并在构建时将其复制到output.path */
    publicDir?: string;
    /** js 插件(这是一个 javascript 对象)和 rust 插件(这是引用 .farm 文件或包的字符串) */
    plugins?: (RustPlugin | JsPlugin | JsPlugin[])[];
    /** vite 插件 */
    vitePlugins?: (object | (() => { vitePlugin: any; filters: string[] }))[];
    // compilation?: Pick<InternalConfig, AvailableUserConfigKeys>;
    // server?: UserServerConfig;
    }
    -

    root

    +
    export interface UserConfig {
    /** 该项目的当前根目录,默认为当前工作目录 */
    root?: string;
    clearScreen?: boolean;
    envDir?: string;
    envPrefix?: string | string[];
    /** 该目录下的文件将始终被视为静态资产。 在dev中提供它,并在构建时将其复制到output.path */
    publicDir?: string;
    /** js 插件(这是一个 javascript 对象)和 rust 插件(这是引用 .farm 文件或包的字符串) */
    plugins?: (RustPlugin | JsPlugin | JsPlugin[])[];
    /** vite 插件 */
    vitePlugins?: (object | (() => { vitePlugin: any; filters: string[] }))[];
    // compilation?: Pick<InternalConfig, AvailableUserConfigKeys>;
    // server?: UserServerConfig;
    }
    +

    root

    • default: process.cwd()

    配置项目编译的根目录。 所有相对路径在编译期间都是相对于 root 的。

    -

    clearScreen

    +

    clearScreen

    • default: true

    开始编译时是否清屏。

    -

    envDir

    +

    envDir

    • default: <root>

    配置目录以加载 .env.env.development.env.Production 文件。 默认情况下它与 root 相同。

    -
    import { defineConfig } from '@farmfe/core';
    import { resolve } from 'path';
    export default defineConfig({
    envPrefix: ['FARM_', 'CUSTOM_PREFIX_', 'NEW_'],
    envDir: resolve(process.cwd(), './env'),
    });
    +
    import { defineConfig } from '@farmfe/core';
    import { resolve } from 'path';
    export default defineConfig({
    envPrefix: ['FARM_', 'CUSTOM_PREFIX_', 'NEW_'],
    envDir: resolve(process.cwd(), './env'),
    });

    在上面的示例中,将从 <root>/env 目录加载 .env.env.development.env.Production 文件。

    -

    envPrefix

    +

    envPrefix

    • default: ['FARM_', 'VITE_']

    envPrefix 开头的环境变量将自动注入 define

    -

    publicDir

    +

    publicDir

    • default: public

    publicDir 下的文件将始终被视为静态资源。 在 dev 时可以通过 dev server 直接访问,在构建时会将其复制到 output.path

    例如,您可以将字体等静态资源添加到 public 目录,并将它们用作 /xxx.ttf

    -

    plugins

    +

    plugins

    • default: []

    配置 Farm 插件。 参考使用 Farm 插件

    -

    vitePlugins

    +

    vitePlugins

    • default: []
    -

    配置 Vite/Rollup/Unplugin 插件。 参见 使用Vite插件

    +

    配置 Vite/Rollup/Unplugin 插件。 参见 使用Vite插件

    \ No newline at end of file diff --git a/zh/docs/contribution/index.html b/zh/docs/contribution/index.html index 8af271e43..7a37938a4 100644 --- a/zh/docs/contribution/index.html +++ b/zh/docs/contribution/index.html @@ -8,22 +8,22 @@ - - - + + + -
    版本:1.0.0

    Contribution Guide

    +
    版本:1.0.0

    Contribution Guide

    Thank you for your interest in contributing to Farm!. Before submitting your contribution, please make sure to take a moment and read through the following guidelines.

    -

    Code of Conduct

    +

    Code of Conduct

    All contributors are expected to follow our Code of Conduct.

    -

    Bug reports

    +

    Bug reports

    As farm is currently in the process of rapid development iteration, some unexpected problems may be encountered in the process of development.

    We can't fix what we don't know about, so please report problems and unexpected behavior.

    You can open a new issue by following new-issues and choosing one of the issue templates.

    -

    Feature requests

    +

    Feature requests

    Please feel free to open an issue using the feature request template.

    -

    Pull Request Guidelines

    +

    Pull Request Guidelines

    • Please adhere to the code style that you see around the location you are working on.

      @@ -44,7 +44,7 @@

      Pull

      When you are done with your work, verify that it works locally with pnpm run ready

    -

    Setup

    +

    Setup

    -

    Development Environment Setup

    -

    Dependencies

    +
      git remote add upstream https://github.com/farm-fe/farm.git
    git fetch upstream
    git branch --set-upstream-to=upstream/main main
    +

    Development Environment Setup

    +

    Dependencies

    • Install Rust using rustup.

      @@ -70,21 +70,21 @@

      DependenciesPnpm version 8+

    -

    IDE

    +

    IDE

    We recommend that you use vscode for development and recommend two necessary plugins that you need to install

    • rust-analyzer support rust language
    • biome farm use biome to detect and format the code

    You can install them in the extension

    -

    Setup Other Dependencies

    +

    Setup Other Dependencies

    • Install protoc for building sass-embedded.

    TIP: When you run pnpm bootstrap and you use mac or linux systems, farm will automatically install protoc for you system

    -

    Start running

    +

    Start running

    Farm development is very simple. You only need to execute pnpm bootstrap in the root directory for development.

    -
    npm
    yarn
    pnpm
    bun
    npm bootstrap
    +
    npm
    yarn
    pnpm
    bun
    npm bootstrap
    • use pnpm bootstrap to install dependencies and build core packages with series of initialization operations.

      @@ -100,26 +100,26 @@

      Start running<

    When you are developing node side code, the root directory executes pnpm start to debug the code in real time, and when you are developing rust side code, the root directory executes pnpm start:rs to debug the code in real time.

    -
    npm
    yarn
    pnpm
    bun
    npm start   // node side
    -
    npm
    yarn
    pnpm
    bun
    npm start:rs   // rust side
    -

    Testing

    +
    npm
    yarn
    pnpm
    bun
    npm start   // node side
    +
    npm
    yarn
    pnpm
    bun
    npm start:rs   // rust side
    +

    Testing

    We also need to test two parts, a set of Rust tests and a set of Node tests. Make sure all the tests pass before you submit the code.

    -

    Rust Testing

    +

    Rust Testing

    • Input cargo test in the root directory will run all the test cases.
    -
    # root path or crates path
    cargo test
    -

    Node Testing

    +
    # root path or crates path
    cargo test
    +

    Node Testing

    • Input pnpm test in the root directory to run all test cases based on vitest.
    -
    # root path
    pnpm test
    -

    Quickly create plugins through scaffold

    +
    # root path
    pnpm test
    +

    Quickly create plugins through scaffold

    If you want to develop a plugin for farm, farm provides a scaffolding to help you quickly create a plugin, which you can create with the following command. You can go to the cd packages/ cli directory, run npm link or global installation @ farmfe/ cli to use this CLI, after the installation is complete, You can create a plugin through farm plugin create. Farm supports the creation of rust and js plugins.

    -
    $ farm plugin create <plugin-name> # create a plugin support js or rust
    -

    Pull Request Preface Tip

    +
    $ farm plugin create <plugin-name> # create a plugin support js or rust
    +

    Pull Request Preface Tip

    Farm is divided into two parts: the JavaScript side and the Rust side:

    • @@ -130,6 +130,6 @@

      Pul

      the Rust side: see code in the crates and rust-plugins directory. contains core (compilation context, plugin drivers, etc.), compiler (compile process, HMR update, etc.), and plugins.

    • -
    +
    \ No newline at end of file diff --git a/zh/docs/features/css/index.html b/zh/docs/features/css/index.html index f93a98bd4..cef219e64 100644 --- a/zh/docs/features/css/index.html +++ b/zh/docs/features/css/index.html @@ -8,75 +8,75 @@ - - - + + + -
    版本:1.0.0

    Css/Sass/Less

    +
    版本:1.0.0

    Css/Sass/Less

    Farm 支持开箱即用的 CSS 编译,例如:

    -
    import './index.css';
    +
    import './index.css';

    然后 Farm 会自动为 css 模块启用 HMR,并自动打包 Css。

    -

    CSS Modules

    +

    CSS Modules

    Farm 默认支持 css modules,以 .module.css|less|scss|sass 结尾的模块默认将被视为 Css Modules

    -
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    -
    index.module.css
    .main {
    color: red;
    }
    +
    comp.tsx
    // ...
    import styles from './index.module.css'

    export function Comp() {
    return <div className={styles.main}>Main</div>
    }
    +
    index.module.css
    .main {
    color: red;
    }

    您可以通过css.modules配置CSS模块。 例如,您可以将 css.modules.paths 设置为 ['.css|sass|less|scss'] 那么所有 css 文件将被视为 css 模块。

    -

    CSS 预处理器

    +

    CSS 预处理器

    Farm 官方提供了 sass、less、postcss 插件。

    -

    Sass

    +

    Sass

    Farm Sass 插件是一个 Rust 插件,使用 sass-embeded(后面我们可能会迁移到纯 Rust 编写的 grass)。

    在 Farm 中编译 sass/scss 模块的步骤如下:

    1. 安装依赖
    -
    # npm 或者 yarn 或者 pnpm,使用任意你喜欢的包管理器 
    npm install @farmfe/plugin-sass
    +
    # npm 或者 yarn 或者 pnpm,使用任意你喜欢的包管理器 
    npm install @farmfe/plugin-sass
    1. 配置插件
    -
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: ['@farmfe/plugin-sass'] // 配置 Rust 插件的包名即可引入和使用该插件
    // 如果你希望配置 plugin-sass 的参数,可以使用如下形式的配置
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    };
    +
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    // ...
    plugins: ['@farmfe/plugin-sass'] // 配置 Rust 插件的包名即可引入和使用该插件
    // 如果你希望配置 plugin-sass 的参数,可以使用如下形式的配置
    // plugins: [
    // ['@farmfe/plugin-sass', { sourceMap: false }]
    // ]
    };
    1. 导入sass模块
    -
    import './index.scss';
    +
    import './index.scss';

    如果要将 sasscss modules 一起使用,请将文件名从 index.scss 更改为 index.module.scss,请参阅 css modules

    @farmfe/plugin-sass 支持很多选项,使用 plugins 的数组配置指定插件 sass 的选项:

    -
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    plugins: [
    // 通过数组语法指定插件以及配置
    [
    '@farmfe/plugin-sass',
    // 所有支持的选项如下
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    };
    -

    Less

    +
    import type { UserConfig } from '@farmfe/core';

    export default <UserConfig> {
    plugins: [
    // 通过数组语法指定插件以及配置
    [
    '@farmfe/plugin-sass',
    // 所有支持的选项如下
    {
    sourceMap: true // bool
    sourceMapIncludeSources: true, // bool
    alertAscii: true, // bool
    alertColor: true, // bool
    charset: true, // bool
    quietDeps: true, // bool
    verbose: false, // bool
    style: 'expanded' | 'compressed' // output code style
    }
    ]
    ]
    };
    +

    Less

    Farm less 插件是一个 Js 插件。 在 Farm 中编译 less 模块的步骤如下:

    1. 安装依赖
    -
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-less
    +
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-less
    1. 配置插件
    -
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default <UserConfig> {
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    +
    import type { UserConfig } from '@farmfe/core';
    import less from '@farmfe/js-plugin-less';

    export default <UserConfig> {
    // ...
    plugins: [less()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    1. 导入 Less 模块
    -
    import './index.less';
    +
    import './index.less';

    要将 lesscss modules 一起使用,请将文件名从 index.less 更改为 index.module.less,参考 css modules

    -

    Postcss

    +

    Postcss

    Farm postcss 插件是一个 JS 插件,在 Farm 中引入 postcss 的步骤如下:

    1. 安装依赖
    -
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-postcss
    +
    # npm or yarn or pnpm, choose your favorite package manager
    npm install @farmfe/js-plugin-postcss
    1. 配置插件
    -
    import type { UserConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default <UserConfig> {
    // ...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    +
    import type { UserConfig } from '@farmfe/core';
    import postcss from '@farmfe/js-plugin-postcss';

    export default <UserConfig> {
    // ...
    plugins: [postcss()] // pass argument to the less function like `less({ /* your options */ })` to specify less options
    };
    1. 配置 postcss.config.js,引入需要的 postcss 插件
    -
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    -

    Css Prefixer

    +
    module.exports = {
    plugins: [
    require('postcss-pxtorem')({
    rootValue: 16,
    propList: ['*'],
    }),
    require('tailwindcss'),
    ]
    }
    +

    Css Prefixer

    Farm 支持开箱即用的 css prefixer,您可以使用compilation.css.prefixer对其进行配置。

    -
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });
    +
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    compilation: {
    css: {
    prefix: {
    targets: ['ie >= 10']
    }
    },
    },
    });

    对于输入代码

    -
    div {
    display: flex;
    }
    +
    div {
    display: flex;
    }

    输出

    -
    div{display:-ms-flexbox;display:flex}
    +
    div{display:-ms-flexbox;display:flex}
    \ No newline at end of file diff --git a/zh/docs/features/dev-server/index.html b/zh/docs/features/dev-server/index.html index 180f64d81..179048ddd 100644 --- a/zh/docs/features/dev-server/index.html +++ b/zh/docs/features/dev-server/index.html @@ -8,23 +8,23 @@ - - - + + + -
    版本:1.0.0

    DevServer 和 HMR

    +
    版本:1.0.0

    DevServer 和 HMR

    Farm默认在 development 环境中提供 DevServer 并启用了 HMR

    -

    配置 Dev Server

    +

    配置 Dev Server

    Farm提供了许多有用的选项来配置开发服务器。所有的DevServer选项都是通过server配置的。

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    server: {
    port: 9801,
    cors: true,
    proxy: {
    // ...
    },
    open: true,
    }
    })
    -
    备注

    如果你正在为Farm开发工具,请参考Javascript API然后以编程方式创建开发服务器。

    -

    Dev Server 中间件

    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    server: {
    port: 9801,
    cors: true,
    proxy: {
    // ...
    },
    open: true,
    }
    })
    +
    备注

    如果你正在为Farm开发工具,请参考Javascript API然后以编程方式创建开发服务器。

    +

    Dev Server 中间件

    你可以使用 middlewares 来处理开发服务器的请求。例如:

    -
    farm.config.ts
    import { Middleware } from 'koa';
    import { Server, defineConfig } from '@farmfe/core';

    export function headers(devSeverContext: Server): Middleware {
    const { config } = devSeverContext;
    if (!config.headers) return;

    return async (ctx, next) => {
    if (config.headers) {
    for (const name in config.headers) {
    ctx.set(name, config.headers[name] as string | string[]);
    }
    }
    await next();
    };
    }

    export default defineConfig({
    server: {
    middlewares: [
    headers
    ]
    }
    })
    +
    farm.config.ts
    import { Middleware } from 'koa';
    import { Server, defineConfig } from '@farmfe/core';

    export function headers(devSeverContext: Server): Middleware {
    const { config } = devSeverContext;
    if (!config.headers) return;

    return async (ctx, next) => {
    if (config.headers) {
    for (const name in config.headers) {
    ctx.set(name, config.headers[name] as string | string[]);
    }
    }
    await next();
    };
    }

    export default defineConfig({
    server: {
    middlewares: [
    headers
    ]
    }
    })

    在上述示例中,Farm中间件是一个暴露 Koa Middleware 的函数。常见的Koa中间件可以直接使用,例如:

    -
    import { defineConfig } from "@farmfe/core";
    import compression from 'koa-compress';

    export default defineConfig({
    server: {
    middlewares: [
    compression
    ]
    },
    });
    -

    Hot Module Replacement(HMR)

    +
    import { defineConfig } from "@farmfe/core";
    import compression from 'koa-compress';

    export default defineConfig({
    server: {
    middlewares: [
    compression
    ]
    },
    });
    +

    Hot Module Replacement(HMR)

    Farm提供了一个与 兼容 Vite 的HMR API。如果你是框架作者,可以利用这个 API 来更新你的应用实例,而无需重新加载页面。

    HMR API允许你在应用运行时接收模块的更新,并应用这些更新,而无需重新加载整个页面。这可以极大地提高开发效率,因为它允许你在不丢失应用状态的情况下看到代码更改的效果。

      @@ -32,9 +32,9 @@

      Ho
    • 对于Vue、Solid等框架,它们的插件如 @vitejs/plugin-vuevite-plugin-solid 等都支持HMR。

    Farm提供了官方模板,这些模板已经设置好了所有这些能力,你可以通过create-farm创建应用,然后所有的HMR能力就可用了。

    -
    备注
      +
      备注
      • 对于应用用户,HMR通常是开箱即用的,如果你需要自定义HMR行为,可以参考 兼容 Vite 的 HMR API
      • 如果你是框架作者,可以参考 HMR选项 来配置HMR。
      • -
    +
    \ No newline at end of file diff --git a/zh/docs/features/env/index.html b/zh/docs/features/env/index.html index f7f7205b1..4aaa94be7 100644 --- a/zh/docs/features/env/index.html +++ b/zh/docs/features/env/index.html @@ -8,39 +8,39 @@ - - - + + + -
    版本:1.0.0

    环境变量和模式

    +
    版本:1.0.0

    环境变量和模式

    Farm 通过 process.env.NODE_ENV 来区分 development 环境和 production 环境。

    在不同的环境中,环境变量会被静态替换,因此使用静态常量来表示环境变量,而不是使用动态表达式。

    -

    .env 文件

    +

    .env 文件

    Farm 使用 dotenv 来加载你的额外环境变量,例如 .env 文件。默认情况下, .env 文件从 root 加载,你可以使用 envDir 来自定义。

    -
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0
    +
    // .env
    FARM_APP_SECRET=secret
    Farm_APP_PASSWORD=password
    APP_VERSION=1.0.0

    Farm 通过dotenv加载 .env 文件,将其加载到 process.env 中,并最终将其注入到define中。

    -
    危险

    为了确保客户端的安全,防止当前系统中的环境变量被暴露给客户端, Farm 只会识别以 FARM_VITE_ 开头的重要环境变量,以便更好地兼容vite及其生态系统。前缀可以通过 envPrefix 前缀配置

    +
    危险

    为了确保客户端的安全,防止当前系统中的环境变量被暴露给客户端, Farm 只会识别以 FARM_VITE_ 开头的重要环境变量,以便更好地兼容vite及其生态系统。前缀可以通过 envPrefix 前缀配置

    Farm 通过dotenv-expand扩展环境变量。对于仅用于开发的环境变量,使用 .env.development 文件,对于仅用于生产的环境变量,使用 .env.production 文件,对于通过 --mode <stage> 传递的自定义模式,从 .env.<stage> 文件加载。

    • 如果你想自定义加载 .env 文件的目录,你可以配置 envDir
    • 如果你想自定义注入到 define 的环境变量的前缀,你可以配置 envPrefix
    -

    envPrefix

    +

    envPrefix

    • 默认值: FARM_VITE_

    通过配置 envPrefix 来自定义环境变量的前缀。以 envPrefix 开头的环境变量将自动注入到define中。例如,在 .env 文件中:

    -
    // .env
    FARM_CUSTOM_VERSION=1.0.0
    APP_VERSION=0.1.0
    +
    // .env
    FARM_CUSTOM_VERSION=1.0.0
    APP_VERSION=0.1.0

    那么 FARM_CUSTOM_VERSION 将被注入到你的业务代码中,但 APP_VERSION 不会被注入。在你的业务代码中:

    -
    export function MyComp() {
    const farmCustomVersion = FARM_CUSTOM_VERSION;
    return <div>Farm Custom Version: {farmCustomVersion}</div>
    }
    +
    export function MyComp() {
    const farmCustomVersion = FARM_CUSTOM_VERSION;
    return <div>Farm Custom Version: {farmCustomVersion}</div>
    }

    FARM_CUSTOM_VERSION 将自动被替换为 '1.0.0'

    -

    envDir

    +

    envDir

    • 默认值: <root>

    加载env文件的目录。默认情况下,Farm从根目录加载 env 文件

    -
    export defineConfig({
    envDir: './env'
    })
    -

    对于上述配置示例,Farm将从 <root>/env 目录加载.env.env.development等环境变量文件。

    +
    export defineConfig({
    envDir: './env'
    })
    +

    对于上述配置示例,Farm将从 <root>/env 目录加载.env.env.development等环境变量文件。

    \ No newline at end of file diff --git a/zh/docs/features/html/index.html b/zh/docs/features/html/index.html index 4668bb89b..e98d186b7 100644 --- a/zh/docs/features/html/index.html +++ b/zh/docs/features/html/index.html @@ -8,31 +8,31 @@ - - - + + + -
    版本:1.0.0

    Html

    -

    基本用法

    +
    版本:1.0.0

    Html

    +

    基本用法

    Farm 支持开箱即用地编译 Html,并且在构建 Web 项目时应该使用 Html 作为入口,例如:

    -
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    -
    备注

    如果未指定 input,则默认为 {index: './index.html'}

    +
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export default defineConfig({
    input: {
    index: "./index.html", // using ./index.html as entry
    },
    });
    +
    备注

    如果未指定 input,则默认为 {index: './index.html'}

    ./index.html中,应该使用<script src="./xxx">来引用您的入口 Js/Ts/Jsx/Tsx 文件。

    -
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>
    +
    ./index.html
    <html>
    <!-- ... -->
    <body>
    <div id="root"></div>
    <!-- index.ts is the script entry -->
    <script src="./index.ts"></script>
    </body>
    </html>

    你也可以使用<link href="./xxx">来引用你的全局 CSS。

    Farm 在编译时会将这些 scriptlink 转化为最终的生产可用的产物。请注意,当您想引用本地模块时,必须使用 相对路径,例如 <script src="./index.tsx"></script> 将引用本地模块并编译它, 但 <script src="/index.tsx"></script><script src="https://xxx.com/index.tsx"></script> 则不会。

    -
    备注

    scriptlink 可以引用 farm 支持的任何模块类型,例如,jsjsxtstsx 或插件支持的其他模块类型。 您可以根据需要使用任意数量的 scriptlink

    -

    多页面应用程序 - MPA

    +
    备注

    scriptlink 可以引用 farm 支持的任何模块类型,例如,jsjsxtstsx 或插件支持的其他模块类型。 您可以根据需要使用任意数量的 scriptlink

    +

    多页面应用程序 - MPA

    如果您正在构建多页面应用程序,只需配置多个 html,例如:

    -
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    export default defineConfig({
    input: {
    home: './index.html', // Home Page
    about: './about.html', // About Page
    // ... more pages
    }
    })
    +
    farm.config.ts
    import type { UserConfig } from '@farmfe/core';

    export default defineConfig({
    input: {
    home: './index.html', // Home Page
    about: './about.html', // About Page
    // ... more pages
    }
    })

    Farm 将并行编译这些页面。

    -

    继承 html 模板

    +

    继承 html 模板

    Farm 支持通过使用 html.base 配置继承 html 模板,这在构建共享 html 的多页面应用程序时很有帮助。

    -
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });
    +
    farm.config.ts
    import type { UserConfig } from "@farmfe/core";

    export function defineConfig(config: UserConfig) {
    return config;
    }

    export default defineConfig({
    // ...
    compilation: {
    input: {
    home: "./index.html", // Home Page
    about: "./about.html", // About Page
    // ... more pages
    },
    html: {
    base: "./base.html",
    },
    },
    });

    然后添加一个base.html,占位符{{children}}将被替换为子 html 的内容。

    -
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- 占位符将会在编译时替换成对应的子 html 的内容 -->
    {{children}}
    </body>
    </html>
    +
    ./base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- 占位符将会在编译时替换成对应的子 html 的内容 -->
    {{children}}
    </body>
    </html>

    继承./base.html

    -
    ./src/home.html
    <!-- 其他字段继承自../base.html -->
    <script src="./index.tsx"></script>
    +
    ./src/home.html
    <!-- 其他字段继承自../base.html -->
    <script src="./index.tsx"></script>
    \ No newline at end of file diff --git a/zh/docs/features/lazy-compilation/index.html b/zh/docs/features/lazy-compilation/index.html index 1ef571397..19255b234 100644 --- a/zh/docs/features/lazy-compilation/index.html +++ b/zh/docs/features/lazy-compilation/index.html @@ -8,25 +8,25 @@ - - - + + + -
    版本:1.0.0

    懒编译

    +
    版本:1.0.0

    懒编译

    当涉及到一个大项目时,您可能希望将它们分成小块并按需加载。 这可以通过动态导入来实现。

    -
    const page = React.lazy(() => import('./page')); // 延迟加载页面
    +
    const page = React.lazy(() => import('./page')); // 延迟加载页面

    默认情况下,Farm 会在开发时延迟编译这些动态导入,仅在模块真正执行时才编译它们。 延迟编译可以极大提速大型项目的编译。

    -
    备注

    对于生产构建,延迟编译始终被禁用。

    +
    备注

    对于生产构建,延迟编译始终被禁用。

    请注意,正确使用动态导入对于使懒编译更好地工作非常重要。 例如,如果你的一个页面有一个很大的依赖项,但是这个依赖项在这个页面渲染之前不会被使用,那么有必要确保这个大的依赖项是动态导入的,所以它不会被编译,直到页面执行。

    -

    配置延迟编译

    +

    配置延迟编译

    使用compilation.lazyCompilation来启用或禁用它:

    -
    farm.config.ts
    export default {
    compilation: {
    lazyCompilation: true,
    },
    };
    -

    懒编译如何工作

    +
    farm.config.ts
    export default {
    compilation: {
    lazyCompilation: true,
    },
    };
    +

    懒编译如何工作

    当启用延迟编译时,Farm 将首先分析您的所有动态导入,例如:

    -
    const page = React.lazy(() => import('./page'));
    +
    const page = React.lazy(() => import('./page'));

    Farm 会将 ./page 视为应该延迟编译的模块,并且不会编译它,相反,Farm 将为 ./page 返回一个虚拟占位符模块,如下所示:

    -
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // 返回一个promise,这个promise将在延迟编译完成后 resolve。
    let promise = Promise.resolve();

    // 模块已经在懒编译中
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // 请求开发服务器进行延迟编译
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    -

    上面的例子说明了虚拟占位符模块的基本结构。 当占位符执行时,它将请求开发服务器编译该模块及其依赖项。 从开发服务器获取延迟编译结果后,占位符模块会将这些更改修补到 Farm 的运行时模块系统。

    +
    // ... other actions
    const compilingModules = FarmModuleSystem.compilingModules;
    // 返回一个promise,这个promise将在延迟编译完成后 resolve。
    let promise = Promise.resolve();

    // 模块已经在懒编译中
    if (compilingModules.has(modulePath)) {
    promise = promise.then(() => compilingModules.get(modulePath));
    } else {
    // 请求开发服务器进行延迟编译
    const url = '/__lazy_compile?paths=' + paths.join(',') + `&t=${Date.now()}`;
    promise = import(url).then((module: any) => {
    const result: LazyCompileResult = module.default;
    // ...
    });
    // ... more actions
    }

    export const __farm_async = true;
    export default promise;
    +

    上面的例子说明了虚拟占位符模块的基本结构。 当占位符执行时,它将请求开发服务器编译该模块及其依赖项。 从开发服务器获取延迟编译结果后,占位符模块会将这些更改修补到 Farm 的运行时模块系统。

    \ No newline at end of file diff --git a/zh/docs/features/script/index.html b/zh/docs/features/script/index.html index 594b63786..812130ffb 100644 --- a/zh/docs/features/script/index.html +++ b/zh/docs/features/script/index.html @@ -8,56 +8,56 @@ - - - + + + -
    版本:1.0.0

    TS/TSX

    +
    版本:1.0.0

    TS/TSX

    Farm 支持开箱即用地编译Js/Jsx/Ts/Tsx,并默认将Jsx/Tsx编译为 React。

    -
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }
    +
    ./button.tsx
    import Button from "./Button";

    function ButtonGroup(props: ButtonProps) {
    return (
    <div>
    {props.buttons.map((b) => (
    <Button>{b}</Button>
    ))}
    </div>
    );
    }

    Farm 使用 SWC 来编译脚本,Farm 为脚本编译设置了合理的默认配置。 另外,您可以使用compilation.script来配置如何编译脚本文件。 有关详细信息,请参阅 compilation.script

    -

    配置 Swc 解析器

    +

    配置 Swc 解析器

    您可以通过compilation.script.parser配置 SWC 解析器。 请参阅 https://swc.rs/docs/configuration/compilation#jscparser。

    例如,如果你想启用装饰器,你可以设置compilation.script.parser.esConfig.decorators(如果模块是 TS,则设置 tsConfig.decorators):

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    // for .js/.jsx files
    esConfig: {
    decorators: true,
    },
    // for .ts/.tsx files
    tsConfig: {
    decorators: true,
    },
    },
    },
    };

    默认情况下,Farm 为.jsx|.tsx文件设置jsx: true。 其他字段默认为 SWC 的默认值。

    -

    配置目标执行环境

    +

    配置目标执行环境

    运行项目时使用compilation.script.target配置目标环境,Farm 将其默认设置为ESNext

    此选项可以与compilation.presetEnv一起使用,以针对旧浏览器优雅地降级您的项目。 例如,您可以将 target 设置为 ES5 并启用 presetEnv,那么您的项目将完全降级到 ES5。

    -
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    script: {
    target: "ES5",
    },
    presetEnv: true,
    },
    };

    有关presetEnv的更多信息,请参阅 Polyfill

    -

    装饰器

    +

    装饰器

    装饰器默认不启用, 可以通过设置 compilation.script.parser.tsConfig.decoratorstrue 来启用装饰器。

    -
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // 启用装饰器
    decorators: true,
    },
    },
    // 配置装饰器
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });
    +
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    compilation: {
    script: {
    parser: {
    tsConfig: {
    // 启用装饰器
    decorators: true,
    },
    },
    // 配置装饰器
    decorators: {
    legacyDecorator: true,
    decoratorMetadata: false,
    decoratorVersion: '2021-12',
    includes: ["src/broken.ts"],
    excludes: ['node_modules/'],
    }
    },
    },
    });

    Farm 提供了一个装饰器的示例,可以看 https://github.com/farm-fe/farm/tree/main/examples/decorators

    默认情况下, Farm 不会转译 node_modules 下的装饰器, 参考 compilation.script.decorators.excludes.

    -

    使用 SWC 插件

    +

    使用 SWC 插件

    SWC Plugins 可以直接在 Farm 中使用,例如我们在 Farm 中使用 swc-plugin-vue-jsx 来编译 vue jsx:

    -
    farm.config.ts
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };
    +
    farm.config.ts
    import jsPluginVue from "@farmfe/js-plugin-vue";

    /**
    * @type {import('@farmfe/core').UserConfig}
    */
    export default {
    compilation: {
    script: {
    plugins: [
    {
    name: "swc-plugin-vue-jsx",
    options: {
    transformOn: true,
    optimize: true,
    },
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ["tsx", "jsx"],
    },
    },
    ],
    },
    },
    plugins: [jsPluginVue()],
    };

    有关更多详细信息,请参阅使用插件

    -

    Vite 风格的 import.meta.glob

    +

    Vite 风格的 import.meta.glob

    Farm 完整支持 Vite 风格的 import.meta.glob, 参考 glob import.

    例如:

    -
    const modules = import.meta.glob("./dir/*.js");
    +
    const modules = import.meta.glob("./dir/*.js");

    将会被编译成以下结果

    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };
    +
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    "./dir/bar.js": () => import("./dir/bar.js"),
    };

    使用 { eager: true } 后:

    -
    const modules = import.meta.glob("./dir/*.js", { eager: true });
    +
    const modules = import.meta.glob("./dir/*.js", { eager: true });

    将会被编译成以下结果:

    -
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };
    +
    // code produced by Farm
    import * as __glob__0_0 from "./dir/foo.js";
    import * as __glob__0_1 from "./dir/bar.js";
    const modules = {
    "./dir/foo.js": __glob__0_0,
    "./dir/bar.js": __glob__0_1,
    };

    支持数组形式:

    -
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);
    +
    const modules = import.meta.glob(["./dir/*.js", "./another/*.js"]);

    支持通过 ! 排除某些匹配:

    -
    const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
    -
    // code produced by Farm
    const modules = {
    "./dir/foo.js": () => import("./dir/foo.js"),
    };
    -
    备注
      +
      const modules = import.meta.glob(["./dir/*.js", "!**/bar.js"]);
      +
      // code produced by Farm
      const modules = {
      "./dir/foo.js": () => import("./dir/foo.js"),
      };
      +
      备注
      • import.meta.glob 参数必须全部是字面量,不能使用表达式。
      • import.meta.glob 在编译时处理和转换,在运行时不存在。
      • -
    +
    \ No newline at end of file diff --git a/zh/docs/features/sourcemap/index.html b/zh/docs/features/sourcemap/index.html index 1134a628c..7275266a3 100644 --- a/zh/docs/features/sourcemap/index.html +++ b/zh/docs/features/sourcemap/index.html @@ -8,16 +8,16 @@ - - - + + + -
    版本:1.0.0

    Source Map

    +
    版本:1.0.0

    Source Map

    Farm 支持 Source Map,默认情况下自动启用。 可以通过选项启用或禁用 sourcemap。

    -
    备注

    Farm 默认不会为 node_modules 下的文件生成 sourcemap,如果你想为 node_modules 下的文件生成 sourcemap,请将 compilation.sourcemap 配置为all

    +
    备注

    Farm 默认不会为 node_modules 下的文件生成 sourcemap,如果你想为 node_modules 下的文件生成 sourcemap,请将 compilation.sourcemap 配置为all

    使用compilation.sourcemap配置 sourcemap 生成:

    -
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };
    +
    farm.config.ts
    export default {
    compilation: {
    sourcemap: 'all', // generate sourcemap for modules under node_modules
    },
    };

    所有选项如下:

    • true:只为不在node_modules下的文件生成 sourcemap,并生成单独的 sourcemap 文件
    • @@ -25,6 +25,6 @@
    • inline:只为不在node_modules下的文件生成 sourcemap,并将 sourcemap 内联到产物中,不生成单独的文件
    • all:为所有文件生成 sourcemap,并生成单独的 sourcemap 文件
    • all-inline:为所有文件生成 sourcemap,并将 sourcemap 内联到产品中,不生成单独的文件
    • -
    +
    \ No newline at end of file diff --git a/zh/docs/features/static/index.html b/zh/docs/features/static/index.html index 135017fea..2f5671e39 100644 --- a/zh/docs/features/static/index.html +++ b/zh/docs/features/static/index.html @@ -8,33 +8,33 @@ - - - + + + -
    版本:1.0.0

    静态资源

    +
    版本:1.0.0

    静态资源

    v0.4 及以上支持 Farm 支持三种资源加载方式: url , inline , raw

    -

    以 URL 形式使用

    +

    以 URL 形式使用

    导入图片:

    -
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }
    +
    import rocketUrl from './assets/rocket.svg'; // return the url of this image

    export function Main() {
    return <img src={rocketUrl} /> // using the url
    }

    导入图片时默认以 URL 的形式。 当使用 URL 形式导入图像时,图像将直接复制到输出目录,并且图像模块本身将被编译为 js 模块,如下所示:

    -
    export default '/rocket.<content hash>.svg'
    +
    export default '/rocket.<content hash>.svg'

    使用 compilation.output.assetsFilename 来配置你的资源名称。

    -

    内联

    +

    内联

    使用查询 ?inline 告诉 Farm 你想要内联你的资源,然后资源将被转换为 base64,例如:

    -
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    -

    原始字符串

    +
    // importer
    import logo from './assets/logo.png?inline'; // logo is a base 64 str

    // the image module will be compiled to:
    export default 'data:image/png,base64,xxxxx==';
    +

    原始字符串

    例如,使用查询?raw告诉 Farm 您要读取资产的原始字符串

    -
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    -

    相关配置

    +
    // import 
    import logo from './assets/license.txt?raw'; // return the content string of the assets

    // the txt file will be compiled to:
    export default 'MIT xxxx';
    +

    相关配置

    • 使用 compilation.output.assetFileName 来控制产物文件名
    • 使用 compilation.assets.include 将更多类型的文件视为静态资源。
    -
    export default {
    compilation: {
    output: {
    assetsFilename: 'assets/[resourceName].[hash].[ext]', // [] 里面的是 Farm 支持的全部占位符
    },
    assets: {
    include: ['txt'] // 额外静态资源类型
    }
    }
    }
    +
    export default {
    compilation: {
    output: {
    assetsFilename: 'assets/[resourceName].[hash].[ext]', // [] 里面的是 Farm 支持的全部占位符
    },
    assets: {
    include: ['txt'] // 额外静态资源类型
    }
    }
    }
    \ No newline at end of file diff --git a/zh/docs/frameworks/electron/index.html b/zh/docs/frameworks/electron/index.html index 213514121..085432f7d 100644 --- a/zh/docs/frameworks/electron/index.html +++ b/zh/docs/frameworks/electron/index.html @@ -8,27 +8,27 @@ - - - + + + -
    版本:1.0.0

    Electron

    +
    版本:1.0.0

    Electron

    基于 Farm 创建一个 Electron 项目。

    Farm 提供两种方案来支持创建 Electron 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Electron 项目
    -

    创建 Electron 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Electron 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Electron 模版

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Electron 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Electron 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/lit/index.html b/zh/docs/frameworks/lit/index.html index 4b1771587..877bb9283 100644 --- a/zh/docs/frameworks/lit/index.html +++ b/zh/docs/frameworks/lit/index.html @@ -8,29 +8,29 @@ - - - + + + -
    版本:1.0.0

    Lit

    +
    版本:1.0.0

    Lit

    基于 Farm 创建一个 Lit 项目。

    Farm 提供两种方案来支持创建 Lit 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Lit 项目
    -

    创建 Lit 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Lit 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Lit 模版

    在使用 lit 的情况下我们需要配置装饰器

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    presetEnv: false,
    script: {
    plugins: [],
    target: 'es2022',
    parser: {
    tsConfig: {
    decorators: true,
    dts: false,
    noEarlyErrors: false,
    tsx: false
    }
    }
    }
    }
    });

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    presetEnv: false,
    script: {
    plugins: [],
    target: 'es2022',
    parser: {
    tsConfig: {
    decorators: true,
    dts: false,
    noEarlyErrors: false,
    tsx: false
    }
    }
    }
    }
    });

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Lit 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Lit 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/nestjs/index.html b/zh/docs/frameworks/nestjs/index.html index 9e04f872f..5103bdd87 100644 --- a/zh/docs/frameworks/nestjs/index.html +++ b/zh/docs/frameworks/nestjs/index.html @@ -8,27 +8,27 @@ - - - + + + -
    版本:1.0.0

    NestJs

    +
    版本:1.0.0

    NestJs

    基于 Farm 创建一个 NestJs 项目。

    Farm 提供两种方案来支持创建 NestJs 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 NestJs 项目
    -

    创建 NestJs 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 NestJs 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 NestJs 模版

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Nestjs 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Nestjs 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/preact/index.html b/zh/docs/frameworks/preact/index.html index 35075b84a..cf597b9e6 100644 --- a/zh/docs/frameworks/preact/index.html +++ b/zh/docs/frameworks/preact/index.html @@ -8,29 +8,29 @@ - - - + + + -
    版本:1.0.0

    Preact

    +
    版本:1.0.0

    Preact

    基于 Farm 创建一个 Preact 项目。

    Farm 提供两种方案来支持创建 Preact 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Preact 项目
    -

    创建 Preact 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Preact 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Preact 模版

    -
    Preact

    对于 Preact 的支持, Farm 使用 vitepreact 插件

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Preact from "vite-plugin-preact";

    export default defineConfig({
    plugins: [Preact()],
    });
    +
    Preact

    对于 Preact 的支持, Farm 使用 vitepreact 插件

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Preact from "vite-plugin-preact";

    export default defineConfig({
    plugins: [Preact()],
    });

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Preact 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Preact 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/react/index.html b/zh/docs/frameworks/react/index.html index f7570ff3d..9070652af 100644 --- a/zh/docs/frameworks/react/index.html +++ b/zh/docs/frameworks/react/index.html @@ -8,30 +8,30 @@ - - - + + + -
    版本:1.0.0

    React

    +
    版本:1.0.0

    React

    基于 Farm 创建一个 React 项目。

    Farm 提供两种方案来支持创建 React 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 React 项目
    -

    创建 React 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 React 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 React 模版

    Farm 需要通过注册 @farmfe/plugin-react 插件来对 React 项目进行支持。

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: ['@farmfe/plugin-react'],
    });
    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: ['@farmfe/plugin-react'],
    });

    @farmfe/plugin-react 插件由 Rust 编写, 因此你不需要显式引入, 通过传递一个字符串包名即可注册。

    -

    集成 emotion

    +

    集成 emotion

    你可以通过注册 @swc/plugin-emotion 插件来对 emotion 进行支持。

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    plugins: [
    {
    name: '@swc/plugin-emotion',
    options: {},
    filters: {
    moduleTypes: ['tsx'],
    },
    },
    ],
    },
    },
    plugins: [['@farmfe/plugin-react', { "runtime": "automatic", "importSource": "@emotion/react" }]],
    });

    -
    src/index.tsx
    import { css } from '@emotion/react';

    const color = 'white';

    export function Main() {
    return (
    <div
    onClick={() => setCount((c) => c + 1)}
    css={css`
    padding: 32px;
    background-color: hotpink;
    font-size: 24px;
    border-radius: 4px;
    &:hover {
    color: ${color};
    }
    `}
    >
    {a}: {count}
    </div>
    );
    }
    -

    集成 svgr

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    script: {
    plugins: [
    {
    name: '@swc/plugin-emotion',
    options: {},
    filters: {
    moduleTypes: ['tsx'],
    },
    },
    ],
    },
    },
    plugins: [['@farmfe/plugin-react', { "runtime": "automatic", "importSource": "@emotion/react" }]],
    });

    +
    src/index.tsx
    import { css } from '@emotion/react';

    const color = 'white';

    export function Main() {
    return (
    <div
    onClick={() => setCount((c) => c + 1)}
    css={css`
    padding: 32px;
    background-color: hotpink;
    font-size: 24px;
    border-radius: 4px;
    &:hover {
    color: ${color};
    }
    `}
    >
    {a}: {count}
    </div>
    );
    }
    +

    集成 svgr

    SVGR 是一个用于将 SVG 转换为 React 组件的工具,Farm 提供了 Js 插件来支持 SVGR。

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    export default defineConfig(async (env) => {
    return {
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: process.env.NODE_ENV === 'development',
    development: process.env.NODE_ENV === 'development'
    }
    ],
    farmJsPluginSvgr()
    ]
    };
    });

    开发环境时运行

    <PackageManagerTabs command="npm run dev" />

    在生产环境下进行打包

    <PackageManagerTabs command="npm run build" />

    预览生产环境打包之后构建的产物

    <PackageManagerTabs command="npm run preview" />


    如若想查看示例详情: [React 示例](https://github.com/farm-fe/farm/tree/main/examples/react)
    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    export default defineConfig(async (env) => {
    return {
    plugins: [
    [
    '@farmfe/plugin-react',
    {
    refresh: process.env.NODE_ENV === 'development',
    development: process.env.NODE_ENV === 'development'
    }
    ],
    farmJsPluginSvgr()
    ]
    };
    });

    开发环境时运行

    <PackageManagerTabs command="npm run dev" />

    在生产环境下进行打包

    <PackageManagerTabs command="npm run build" />

    预览生产环境打包之后构建的产物

    <PackageManagerTabs command="npm run preview" />


    如若想查看示例详情: [React 示例](https://github.com/farm-fe/farm/tree/main/examples/react)
    \ No newline at end of file diff --git a/zh/docs/frameworks/solid/index.html b/zh/docs/frameworks/solid/index.html index 325372f87..f4ae12706 100644 --- a/zh/docs/frameworks/solid/index.html +++ b/zh/docs/frameworks/solid/index.html @@ -8,29 +8,29 @@ - - - + + + -
    版本:1.0.0

    Solid

    +
    版本:1.0.0

    Solid

    基于 Farm 创建一个 Solid 项目。

    Farm 提供两种方案来支持创建 Solid 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Solid 项目
    -

    创建 Solid 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Solid 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Solid 模版

    -
    Solid

    对于 Solid 的支持, Farm 推荐使用 Vite 插件。

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Solid from "vite-plugin-solid";

    export default defineConfig({
    plugins: [Solid()],
    });
    +
    Solid

    对于 Solid 的支持, Farm 推荐使用 Vite 插件。

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Solid from "vite-plugin-solid";

    export default defineConfig({
    plugins: [Solid()],
    });

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Solid 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Solid 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/svelte/index.html b/zh/docs/frameworks/svelte/index.html index 9c032e874..3a5a9a3d3 100644 --- a/zh/docs/frameworks/svelte/index.html +++ b/zh/docs/frameworks/svelte/index.html @@ -8,30 +8,30 @@ - - - + + + -
    版本:1.0.0

    Svelte

    +
    版本:1.0.0

    Svelte

    基于 Farm 创建一个 Svelte 项目。

    Farm 提供两种方案来支持创建 Svelte 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Svelte 项目
    -

    创建 Svelte 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Svelte 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Svelte 模版

    -
    Svelte

    对于 Svelte 的支持, Farm 推荐使用 Vite 插件。

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core'
    import { svelte } from '@sveltejs/vite-plugin-svelte'

    export default defineConfig({
    vitePlugins: [svelte()],
    })

    -
    svelte.config.ts
    import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'

    export default {
    preprocess: vitePreprocess(),
    }
    +
    Svelte

    对于 Svelte 的支持, Farm 推荐使用 Vite 插件。

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core'
    import { svelte } from '@sveltejs/vite-plugin-svelte'

    export default defineConfig({
    vitePlugins: [svelte()],
    })

    +
    svelte.config.ts
    import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'

    export default {
    preprocess: vitePreprocess(),
    }

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Svelte 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Svelte 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/tauri/index.html b/zh/docs/frameworks/tauri/index.html index e294c9dd1..3acb1af3a 100644 --- a/zh/docs/frameworks/tauri/index.html +++ b/zh/docs/frameworks/tauri/index.html @@ -8,27 +8,27 @@ - - - + + + -
    版本:1.0.0

    Tauri

    +
    版本:1.0.0

    Tauri

    基于 Farm 创建一个 Tauri 项目。

    Farm 提供两种方案来支持创建 Tauri 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Tauri 项目
    -

    创建 Tauri 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Tauri 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Tauri 模版

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Tauri 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Tauri 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/vanilla/index.html b/zh/docs/frameworks/vanilla/index.html index bcdb91dfc..b4f692c49 100644 --- a/zh/docs/frameworks/vanilla/index.html +++ b/zh/docs/frameworks/vanilla/index.html @@ -8,28 +8,28 @@ - - - + + + -
    版本:1.0.0

    Vanilla

    +
    版本:1.0.0

    Vanilla

    基于 Farm 创建一个 Vanilla 项目。

    Farm 提供两种方案来支持创建 Vanilla 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Vanilla 项目
    -

    创建 Vanilla 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Vanilla 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Vanilla 模版

    运行 vanilla 模版项目不需要安装任何其他依赖,直接启动开发服务器即可

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Vanilla 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Vanilla 示例

    \ No newline at end of file diff --git a/zh/docs/frameworks/vue/index.html b/zh/docs/frameworks/vue/index.html index 9cab8069d..09d6c5cfa 100644 --- a/zh/docs/frameworks/vue/index.html +++ b/zh/docs/frameworks/vue/index.html @@ -8,32 +8,32 @@ - - - + + + -
    版本:1.0.0

    Vue

    +
    版本:1.0.0

    Vue

    基于 Farm 创建一个 Vue 项目。

    Farm 提供两种方案来支持创建 Vue 项目:

    • 使用 create-farm 脚手架创建脚手架项目
    • 你可以根据当前文档手动创建一个 Vue 项目
    -

    创建 Vue 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +

    创建 Vue 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest

    Select Framework 中选择 Vue 模版

    -
    Vue

    目前 Farm 支持 vue3, vue2, vue2.7 +

    Vue

    目前 Farm 支持 vue3, vue2, vue2.7 对于 Vue 插件 Farm 推荐使用 Vite 插件, 支持的三种 vue 版本需要安装对应的 vite 插件, 目前也正在进行原生插件 fervid的开发。

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Vue from '@vite/plugin-vue'

    export default defineConfig({
    plugins: [Vue()], // vue3 plugin
    });
    -

    集成 jsx

    -
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Vue from '@vite/plugin-vue-jsx'

    export default defineConfig({
    plugins: [Vue()],
    });
    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Vue from '@vite/plugin-vue'

    export default defineConfig({
    plugins: [Vue()], // vue3 plugin
    });
    +

    集成 jsx

    +
    farm.config.ts
    import { defineConfig } from '@farmfe/core';
    import Vue from '@vite/plugin-vue-jsx'

    export default defineConfig({
    plugins: [Vue()],
    });

    开发环境时运行

    -
    npm
    yarn
    pnpm
    bun
    npm run dev
    +
    npm
    yarn
    pnpm
    bun
    npm run dev

    在生产环境下进行打包

    -
    npm
    yarn
    pnpm
    bun
    npm run build
    +
    npm
    yarn
    pnpm
    bun
    npm run build

    预览生产环境打包之后构建的产物

    -
    npm
    yarn
    pnpm
    bun
    npm run preview
    -

    如若想查看示例详情: Vue 示例

    +
    npm
    yarn
    pnpm
    bun
    npm run preview
    +

    如若想查看示例详情: Vue 示例

    \ No newline at end of file diff --git a/zh/docs/migration/from-vite/index.html b/zh/docs/migration/from-vite/index.html index bc23acf73..80ff4a0a6 100644 --- a/zh/docs/migration/from-vite/index.html +++ b/zh/docs/migration/from-vite/index.html @@ -8,13 +8,13 @@ - - - + + + -
    版本:1.0.0

    从 Vite 迁移

    -
    备注

    Vite 插件如 unocssVite 深度集成,由于内部设计的差异,这些插件可能与 Farm 不兼容。您可以尝试其他方法,如 unocss postcss 插件。

    +
    版本:1.0.0

    从 Vite 迁移

    +
    备注

    Vite 插件如 unocssVite 深度集成,由于内部设计的差异,这些插件可能与 Farm 不兼容。您可以尝试其他方法,如 unocss postcss 插件。

    从 Vite 迁移非常简单,因为 Farm 与 Vite 兼容。您需要做的就是将 vite.config.ts 转换为 farm.config.ts

    • 参考Configuring Farm 将 farm 配置选项映射到 vite 配置
    • @@ -25,6 +25,6 @@
    • 一些 Vite 配置选项在 Farm 中是不需要的,例如 optimizeDeps,您可以在迁移到 Farm 时忽略这些选项
    • 对于 SSR,您需要将其重构为Farm SSR
    -

    我们已将 Real Vite Admin Project 迁移到 Farm。有关详细信息,请查看此迁移示例

    +

    我们已将 Real Vite Admin Project 迁移到 Farm。有关详细信息,请查看此迁移示例

    \ No newline at end of file diff --git a/zh/docs/plugins/community-plugins/index.html b/zh/docs/plugins/community-plugins/index.html index 15f9ef9fa..84deeb11c 100644 --- a/zh/docs/plugins/community-plugins/index.html +++ b/zh/docs/plugins/community-plugins/index.html @@ -8,21 +8,21 @@ - - - + + + -
    版本:1.0.0

    社区插件

    -

    Farm Plugins

    +
    版本:1.0.0

    社区插件

    +

    Farm Plugins

    • farm-pulgin-strip: 一个 Farm Rust 插件,用于从代码中删除 debugger 语句和函数,例如 assert.equal 和 console.log 。
    -

    Vite/Rollup Plugins

    +

    Vite/Rollup Plugins

    Farm支持 Vite/Rollup 插件开箱即用。所以Vite/Rollupunplugin插件可以直接在Farm中使用。

    -
    提示

    如果您开发了兼容 Farm 的插件并且想在此处列出,欢迎 PR。

    +
    提示

    如果您开发了兼容 Farm 的插件并且想在此处列出,欢迎 PR。

    使用 farm.config.ts 中的 vitePlugins 来配置 Vite/Rollup 插件。

    -
    import { UserConfig } from '@farmfe/core';
    import vue from '@vitejs/plugin-vue';
    import vueJsx from '@vitejs/plugin-vue-jsx';

    const config: UserConfig = {
    vitePlugins: [
    vue(),
    vueJsx(),
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import vue from '@vitejs/plugin-vue';
    import vueJsx from '@vitejs/plugin-vue-jsx';

    const config: UserConfig = {
    vitePlugins: [
    vue(),
    vueJsx(),
    ]
    }
    -

    unplugin

    -
    备注

    目前,您可以在 Farm 中使用“unplugin/vite”进行“unplugin/rollup”。 当此 PR 合并到 unplugin 时,unplugin/farm 将可用。

    -
    import Icons from 'unplugin-icons/vite';
    import IconsResolver from 'unplugin-icons/resolver';
    import Components from 'unplugin-vue-components/rollup';
    import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
    import { FileSystemIconLoader } from 'unplugin-icons/loaders';

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: 'vue3',
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, svg =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    )
    },
    scale: 1,
    defaultClass: 'inline-block'
    }),
    Components({
    dts: 'src/typings/components.d.ts',
    types: [{ from: 'vue-router', names: ['RouterLink', 'RouterView'] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFIX })
    ]
    })
    ]
    }
    +

    unplugin

    +
    备注

    目前,您可以在 Farm 中使用“unplugin/vite”进行“unplugin/rollup”。 当此 PR 合并到 unplugin 时,unplugin/farm 将可用。

    +
    import Icons from 'unplugin-icons/vite';
    import IconsResolver from 'unplugin-icons/resolver';
    import Components from 'unplugin-vue-components/rollup';
    import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
    import { FileSystemIconLoader } from 'unplugin-icons/loaders';

    const config: UserConfig = {
    vitePlugins: [
    Icons({
    compiler: 'vue3',
    customCollections: {
    [collectionName]: FileSystemIconLoader(localIconPath, svg =>
    svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
    )
    },
    scale: 1,
    defaultClass: 'inline-block'
    }),
    Components({
    dts: 'src/typings/components.d.ts',
    types: [{ from: 'vue-router', names: ['RouterLink', 'RouterView'] }],
    resolvers: [
    NaiveUiResolver(),
    IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFIX })
    ]
    })
    ]
    }

    Farm 支持所有 unplugin 插件:

    +
    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/dsv/index.html b/zh/docs/plugins/official-plugins/dsv/index.html index f4bd44ad0..f9cba3ad5 100644 --- a/zh/docs/plugins/official-plugins/dsv/index.html +++ b/zh/docs/plugins/official-plugins/dsv/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:1.0.0

    @farmfe/plugin-dsv

    +
    版本:1.0.0

    @farmfe/plugin-dsv

    🍣 一个Farm插件,用于将.csv.tsv文件转换为JavaScript模块。

    -

    要求

    +

    要求

    这个插件需要一个LTS版本的Node(v18.0.0+)和Farm v1.0.0+。

    -

    安装

    -
    npm install @farmfe/plugin-dsv
    -

    使用

    +

    安装

    +
    npm install @farmfe/plugin-dsv
    +

    使用

    创建一个farm.config.js配置文件并导入插件:

    -
    import { defineConfig } from '@farmfe/core';
    import dsv from '@farmfe/plugin-dsv';

    export default defineConfig({
    plugins: [
    [
    dsv()
    ]
    ],
    });
    -

    实际示例

    +
    import { defineConfig } from '@farmfe/core';
    import dsv from '@farmfe/plugin-dsv';

    export default defineConfig({
    plugins: [
    [
    dsv()
    ]
    ],
    });
    +

    实际示例

    假设你有一个包含一些关于美味水果信息的CSV(或TSV)文件:

    -
    type,count
    apples,7
    pears,4
    bananas,5
    +
    type,count
    apples,7
    pears,4
    bananas,5

    并且假设你想在代码的某个部分将该CSV文件作为Array导入。添加插件之后(如上所示),你可以直接import(或require)CSV文件。导入将提供一个Array,包含代表CSV文件行的Objects

    -
    import fruit from './fruit.csv';

    console.log(fruit);
    // [
    // { type: 'apples', count: '7' },
    // { type: 'pears', count: '4' },
    // { type: 'bananas', count: '5' }
    // ]
    +
    import fruit from './fruit.csv';

    console.log(fruit);
    // [
    // { type: 'apples', count: '7' },
    // { type: 'pears', count: '4' },
    // { type: 'bananas', count: '5' }
    // ]
    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/js-dts/index.html b/zh/docs/plugins/official-plugins/js-dts/index.html index b2c72ee42..3ad3522c1 100644 --- a/zh/docs/plugins/official-plugins/js-dts/index.html +++ b/zh/docs/plugins/official-plugins/js-dts/index.html @@ -8,18 +8,18 @@ - - - + + + -
    版本:1.0.0

    @farmfe/js-plugin-dts

    +
    版本:1.0.0

    @farmfe/js-plugin-dts

    支持 .d.ts 文件。 该插件用于构建的工具库,为您的 ts 代码生成“.d.ts”

    -

    Installation

    -
    npm install @farmfe/js-plugin-dts
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    -

    Options

    -
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    +

    Installation

    +
    npm install @farmfe/js-plugin-dts
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginDts from '@farmfe/js-plugin-dts';

    const config: UserConfig = {
    plugins: [
    farmJsPluginDts({ /* options */ })
    ]
    }
    +

    Options

    +
    import type { ts, Diagnostic } from 'ts-morph';

    export interface DtsPluginOptions {
    /**
    * Depends on the root directory
    */
    root?: string;

    /**
    * Declaration files output directory
    */
    outputDir?: string | string[];

    /**
    * set the root path of the entry files
    */
    entryRoot?: string;

    /**
    * Project init compilerOptions using by ts-morph
    */
    compilerOptions?: ts.CompilerOptions | null;

    /**
    * Project init tsconfig.json file path by ts-morph
    */
    tsConfigPath?: string;

    /**
    * set include glob
    */
    include?: string | string[];

    /**
    * set exclude glob
    */
    exclude?: string | string[];

    /**
    * Whether copy .d.ts source files into outputDir
    *
    * @default false
    */
    copyDtsFiles?: boolean;

    /**
    * Whether emit nothing when has any diagnostic
    *
    * @default false
    */
    noEmitOnError?: boolean;

    /**
    * Whether skip typescript diagnostics
    *
    * @default true
    */
    skipDiagnostics?: boolean;

    /**
    * Customize typescript lib folder path
    *
    * @default undefined
    */
    libFolderPath?: string;

    /**
    * According to the length to judge whether there is any type error
    */
    afterDiagnostic?: (diagnostics: Diagnostic[]) => void | Promise<void>;
    }

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/js-less/index.html b/zh/docs/plugins/official-plugins/js-less/index.html index 1d2ef0358..6c323146c 100644 --- a/zh/docs/plugins/official-plugins/js-less/index.html +++ b/zh/docs/plugins/official-plugins/js-less/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:1.0.0

    @farmfe/js-plugin-less

    +
    版本:1.0.0

    @farmfe/js-plugin-less

    支持 Less 编译

    -

    Installation

    -
    npm install @farmfe/js-plugin-less less
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    -

    Options

    -
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    lessOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-less less
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({ /* options */ })
    ]
    }
    +

    Options

    +
    export type LessPluginOptions = {
    lessOptions?: Less.Options;
    implementation?: string;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    additionalData?:
    | string
    | ((context?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    lessOptions

    请参阅Less 选项

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    lessOptions: {
    paths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由 less 处理。 默认为“ {resolvedPaths: ['\\.less$'] }”用于加载,“{ moduleTypes: ['less'] }”用于转换。

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-less$'],
    moduleTypes: ['less']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    lessimplementation 包名称。 默认为 less

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    要添加到每个 less 文件的附加数据。示例:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: `
    @import "./src/styles/variables.less";
    `
    })
    ]
    }

    Less 文件:

    -
    index.less
    .foo {
    color: @primary-color;
    }
    +
    index.less
    .foo {
    color: @primary-color;
    }

    additionalData 将会被添加到这个文件的头部:

    -
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }
    +
    index.less
    @import "./src/styles/variables.less";

    .foo {
    color: @primary-color;
    }

    函数形式用法:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginLess from '@farmfe/js-plugin-less';

    const config: UserConfig = {
    plugins: [
    farmJsPluginLess({
    // add variables.less to every less file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.less') {
    return `
    @import "./src/styles/variables.less";
    `;
    }
    }
    })
    ]
    }
    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/js-postcss/index.html b/zh/docs/plugins/official-plugins/js-postcss/index.html index ebb08bb97..e30e83a06 100644 --- a/zh/docs/plugins/official-plugins/js-postcss/index.html +++ b/zh/docs/plugins/official-plugins/js-postcss/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:1.0.0

    @farmfe/js-plugin-postcss

    +
    版本:1.0.0

    @farmfe/js-plugin-postcss

    支持 postcss 的前置编译工作

    -

    Installation

    -
    npm install @farmfe/js-plugin-postcss postcss
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    -

    Options

    -
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    -

    postcssLoadConfig

    +

    Installation

    +
    npm install @farmfe/js-plugin-postcss postcss
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({ /* options */ })
    ]
    }
    +

    Options

    +
    export type PostcssPluginOptions = {
    /**
    * @default undefined
    * postcss-load-config options. path default to farm.config.js root.
    */
    postcssLoadConfig?: {
    ctx?: postcssLoadConfig.ConfigContext;
    path?: string;
    options?: Parameters<typeof postcssLoadConfig>[2];
    };
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };
    implementation?: string;
    };

    +

    postcssLoadConfig

    Farm 使用 postcss-load-config 来加载 postcss 配置,因此您可以使用 postcss-load-config 的选项。 参考postcss-load-config

    示例:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    postcssLoadConfig: {
    // load config from client/postcss.config.js
    path: path.join(process.cwd(), 'client')
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由postcss处理。 默认为 { moduleTypes: ['css'] }

    -

    implementation

    -

    postcssimplementation 包名称。 默认为 postcss

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginPostcss from '@farmfe/js-plugin-postcss';

    const config: UserConfig = {
    plugins: [
    farmJsPluginPostcss({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-css$'],
    moduleTypes: ['css']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    +

    postcssimplementation 包名称。 默认为 postcss

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/js-sass/index.html b/zh/docs/plugins/official-plugins/js-sass/index.html index 21dac4a6a..944b5040f 100644 --- a/zh/docs/plugins/official-plugins/js-sass/index.html +++ b/zh/docs/plugins/official-plugins/js-sass/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:1.0.0

    @farmfe/js-plugin-sass

    +
    版本:1.0.0

    @farmfe/js-plugin-sass

    支持 sass 编译

    -

    Installation

    -
    npm install @farmfe/js-plugin-sass sass
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    -

    Options

    -
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    -

    sassOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-sass sass
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({ /* options */ })
    ]
    }
    +

    Options

    +
    export type SassPluginOptions = {
    sassOptions?: StringOptions<'async'>;
    filters?: {
    resolvedPaths?: string[];
    moduleTypes?: string[];
    };

    /**
    * - relative or absolute path
    * - globals file will be added to the top of the sass file
    * - when file changed, the file can't be hot-reloaded
    *
    * relative to project root or cwd
    */
    implementation?: string | undefined;
    globals?: string[];
    additionalData?:
    | string
    | ((content?: string, resolvePath?: string) => string | Promise<string>);
    };
    +

    sassOptions

    请参阅 sass 选项

    Example:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    sassOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由 sass 处理。 对于 load 钩子默认为 {resolvedPaths: ['\\.(s[ac]ss)$'] }, 对于 transform 钩子默认为 { moduleTypes: ['sass'] }

    -

    implementation

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    filters: {
    // all files end with .custom-css will be processed
    resolvedPaths: ['\\.custom-sass$'],
    moduleTypes: ['sass']
    }
    })
    ]
    }

    export default config;
    +

    implementation

    sassimplementation 包名称。 默认为 sass。 如果你想使用sass-embedded,可以将其设置为sass-embedded

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    -
    备注

    您应该手动安装 sass-embedded

    -

    additionalData

    -
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    implementation: 'sass-embedded'
    })
    ]
    }
    +
    备注

    您应该手动安装 sass-embedded

    +

    additionalData

    +
    type AdditionalDataOption = string | ((content?: string, resolvePath?: string) => string | Promise<string>);

    要添加到每个 sass 文件的附加数据。 例子:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: `
    @import "./src/styles/variables.scss";
    `
    })
    ]
    }

    Sass 文件

    -
    index.scss
    .foo {
    color: @primary-color;
    }
    +
    index.scss
    .foo {
    color: @primary-color;
    }

    additionalData 将会被添加到这个文件的头部:

    -
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }
    +
    index.scss
    @import "./src/styles/variables.scss";

    .foo {
    color: @primary-color;
    }

    函数形式用法:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    -

    globals

    -

    全局 sass 文件。 这些文件将添加到每个 sass 文件的顶部。 它与 additionalData 相同,但更方便。

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSass from '@farmfe/js-plugin-sass';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSass({
    // add variables.sass to every sass file
    additionalData: (content, resolvePath) => {
    if (resolvePath === '/path/to/index.sass') {
    return `
    @import "./src/styles/variables.sass";
    `;
    }
    }
    })
    ]
    }
    +

    globals

    +

    全局 sass 文件。 这些文件将添加到每个 sass 文件的顶部。 它与 additionalData 相同,但更方便。

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/js-svgr/index.html b/zh/docs/plugins/official-plugins/js-svgr/index.html index 4f89e53af..50a000d3a 100644 --- a/zh/docs/plugins/official-plugins/js-svgr/index.html +++ b/zh/docs/plugins/official-plugins/js-svgr/index.html @@ -8,29 +8,29 @@ - - - + + + -
    版本:1.0.0

    @farmfe/js-plugin-svgr

    +
    版本:1.0.0

    @farmfe/js-plugin-svgr

    支持将 SVG 编译成 React 组建

    -

    Installation

    -
    npm install @farmfe/js-plugin-svgr
    -

    Usage

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    -

    Options

    -
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    -

    svgrOptions

    +

    Installation

    +
    npm install @farmfe/js-plugin-svgr
    +

    Usage

    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({ /* options */ })
    ]
    }
    +

    Options

    +
    export interface FarmSvgrPluginOptions {
    svgrOptions?: SvgrOptions;
    filters?: {
    resolvedPaths?: string[];
    };
    }
    +

    svgrOptions

    请参阅 svgr 选项

    示例:

    -
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    -

    filters

    +
    import path from 'node:path';
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    svgrOptions: {
    loadPaths: [path.resolve(process.cwd(), 'styles')]
    }
    })
    ]
    }

    export default config;
    +

    filters

    哪些文件应该由 svgr 处理。 默认为 {resolvedPaths: ['\\.svg$'] }

    • resolvedPaths: 仅处理这些路径下的文件。 支持正则表达式。

    示例:

    -
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    +
    import { UserConfig } from '@farmfe/core';
    import farmJsPluginSvgr from '@farmfe/js-plugin-svgr';

    const config: UserConfig = {
    plugins: [
    farmJsPluginSvgr({
    filters: {
    // all files end with .custom-svg will be processed
    resolvedPaths: ['\\.custom-svg$'],
    }
    })
    ]
    }

    export default config;
    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/overview/index.html b/zh/docs/plugins/official-plugins/overview/index.html index b2ba26585..5d3c1d7cb 100644 --- a/zh/docs/plugins/official-plugins/overview/index.html +++ b/zh/docs/plugins/official-plugins/overview/index.html @@ -8,15 +8,15 @@ - - - + + + -
    版本:1.0.0

    插件概览

    +
    版本:1.0.0

    插件概览

    Farm官方提供了很多有用的插件,包括Rust插件和JS插件。 Rust 插件比 Js 插件快得多,我们建议尽可能使用 Rust 插件。

    -
    提示

    关于如何在 Farm 中使用插件,请参阅使用插件

    -

    Rust 插件

    +
    提示

    关于如何在 Farm 中使用插件,请参阅使用插件

    +

    Rust 插件

    -

    Js 插件

    +

    Js 插件

    -

    社区插件

    +

    社区插件

    如果官方插件不能满足您的需求,您可以尝试社区插件

    -

    当然也可以前往查看 awesome-farm - 您也可以提交 PR,在那里列出您的插件。

    +

    当然也可以前往查看 awesome-farm - 您也可以提交 PR,在那里列出您的插件。

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/react-components/index.html b/zh/docs/plugins/official-plugins/react-components/index.html index b606dd1ea..cba3fa827 100644 --- a/zh/docs/plugins/official-plugins/react-components/index.html +++ b/zh/docs/plugins/official-plugins/react-components/index.html @@ -8,19 +8,19 @@ - - - + + + -
    版本:1.0.0

    @farmfe/plugin-react-components

    +
    版本:1.0.0

    @farmfe/plugin-react-components

    按需自动导入React组件。

    -

    安装

    -
    npm install @farmfe/plugin-react-components
    -

    使用

    +

    安装

    +
    npm install @farmfe/plugin-react-components
    +

    使用

    @farmfe/plugin-react-components 是一个Rust插件,你只需要在 farm.config.tsplugins 字段中配置其包名即可。

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', { /** 选项在此 */}]
    }
    -

    功能

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', { /** 选项在此 */}]
    }
    +

    功能

    • 💚 支持React开箱即用。
    • ✨ 支持组件和指令。
    • @@ -29,24 +29,24 @@

      功能内置解析器

    -

    使用

    +

    使用

    像往常一样在模板中使用组件,它将按需导入组件,不再需要importcomponent registration!如果你异步注册父组件(或懒加载路由),自动导入的组件会与其父组件一起进行代码拆分。

    它会自动将这个

    -
    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }
    +
    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }

    转换成这个

    -
    import HelloWorld from './src/components/HelloWorld'

    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }
    +
    import HelloWorld from './src/components/HelloWorld'

    export function Main() {
    return <HelloWorld msg="Hello React + Farm" />
    }

    注意 默认情况下,此插件会导入src/components路径中的组件。你可以使用dirs选项进行自定义。

    -

    TypeScript

    +

    TypeScript

    为自动导入的组件获得TypeScript支持。

    -
    Components({
    dts: true, // 如果安装了`typescript`默认启用
    })
    +
    Components({
    dts: true, // 如果安装了`typescript`默认启用
    })

    完成设置后,将自动生成一个components.d.ts文件,并自动更新类型定义。你可以选择是否将其提交到git。

    确保你也将components.d.ts添加到tsconfig.jsoninclude中。

    -

    从UI库中导入

    +

    从UI库中导入

    我们为几个流行的UI库(如Ant DesignArco DesignMaterial UI)提供了几个内置解析器,你可以通过以下方式启用它们:

    支持的解析器:

    -
    // farm.config.js

    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', {
    local: true,
    resolvers:[
    {
    module: "antd",
    prefix: "Ant"
    },
    {
    module:"@arco-design/web-react",
    prefix: "Arco",
    import_style: true // style/index.js
    }
    ]
    }]
    }
    -

    配置

    +
    // farm.config.js

    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react-components', {
    local: true,
    resolvers:[
    {
    module: "antd",
    prefix: "Ant"
    },
    {
    module:"@arco-design/web-react",
    prefix: "Arco",
    import_style: true // style/index.js
    }
    ]
    }]
    }
    +

    配置

    以下显示了配置的默认值 component

    -
    {
    // 相对路径到搜索组件的目录。
    dirs: ['src/components'],

    // 自定义组件的解析器。
    resolvers: [],

    /**
    * 组件以绝对或相对路径引入。
    *
    * @default 绝对
    */
    import_mode: "Absolute"

    /**
    * 是否对本地组件有效
    *
    * @default true
    */
    local: true,

    /**
    * 导入样式`style/index.js`,也接受路径用于自定义路径(<Component>/**)与组件
    *
    * @default false
    */
    importStyle?: boolean | string

    // 生成全局声明的`components.d.ts`,
    // 也接受自定义文件名的路径
    // 默认:如果安装了typescript包则为`true`
    dts: true,

    // 转换目标(要插入自动导入的组件)的过滤器
    // 注意,这不是关于包含/排除注册组件 - 使用`Regex`来做那个
    include: ["src/components"],
    exclude: ["node_modules"],
    }
    +
    {
    // 相对路径到搜索组件的目录。
    dirs: ['src/components'],

    // 自定义组件的解析器。
    resolvers: [],

    /**
    * 组件以绝对或相对路径引入。
    *
    * @default 绝对
    */
    import_mode: "Absolute"

    /**
    * 是否对本地组件有效
    *
    * @default true
    */
    local: true,

    /**
    * 导入样式`style/index.js`,也接受路径用于自定义路径(<Component>/**)与组件
    *
    * @default false
    */
    importStyle?: boolean | string

    // 生成全局声明的`components.d.ts`,
    // 也接受自定义文件名的路径
    // 默认:如果安装了typescript包则为`true`
    dts: true,

    // 转换目标(要插入自动导入的组件)的过滤器
    // 注意,这不是关于包含/排除注册组件 - 使用`Regex`来做那个
    include: ["src/components"],
    exclude: ["node_modules"],
    }
    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/react/index.html b/zh/docs/plugins/official-plugins/react/index.html index ffd14c8bf..e86a061c1 100644 --- a/zh/docs/plugins/official-plugins/react/index.html +++ b/zh/docs/plugins/official-plugins/react/index.html @@ -8,19 +8,19 @@ - - - + + + -
    版本:1.0.0

    @farmfe/plugin-react

    +
    版本:1.0.0

    @farmfe/plugin-react

    支持 React JsxReact Refresh

    -

    Installation

    -
    npm
    yarn
    pnpm
    bun
    npm add @farmfe/plugin-react
    -

    Usage

    +

    Installation

    +
    npm
    yarn
    pnpm
    bun
    npm add @farmfe/plugin-react
    +

    Usage

    @farmfe/plugin-react 是一个 Rust 插件,你只需要在 farm.config.tsplugins 字段中配置它的包名。

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    -

    Options

    -

    请参阅SWC 转换 React 选项

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-react', { /** options here */}]
    }
    +

    Options

    +

    请参阅SWC 转换 React 选项

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/sass/index.html b/zh/docs/plugins/official-plugins/sass/index.html index 6b6e10c1a..4b9414edc 100644 --- a/zh/docs/plugins/official-plugins/sass/index.html +++ b/zh/docs/plugins/official-plugins/sass/index.html @@ -8,23 +8,23 @@ - - - + + + -
    版本:1.0.0

    @farmfe/plugin-sass

    +
    版本:1.0.0

    @farmfe/plugin-sass

    支持 sass 编译

    -

    Installation

    -
    npm install @farmfe/plugin-sass
    -

    Usage

    +

    Installation

    +
    npm install @farmfe/plugin-sass
    +

    Usage

    @farmfe/plugin-sass 是一个 Rust 插件,你只需要在 farm.config.tsplugins 字段中配置它的包名。

    -
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    -

    Options

    -

    additionalData

    +
    import { UserConfig } from '@farmfe/core';

    const config: UserConfig = {
    plugins: ['@farmfe/plugin-sass', { /** options here */}]
    }
    +

    Options

    +

    additionalData

    • 类型: string
    -

    在每个 sass 文件头部添加额外内容,例如 @import '@/styles/variables.scss'; 语句。

    +

    在每个 sass 文件头部添加额外内容,例如 @import '@/styles/variables.scss'; 语句。

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/strip/index.html b/zh/docs/plugins/official-plugins/strip/index.html index 83bfcd4ce..bc1ae1194 100644 --- a/zh/docs/plugins/official-plugins/strip/index.html +++ b/zh/docs/plugins/official-plugins/strip/index.html @@ -8,52 +8,52 @@ - - - + + + -
    版本:1.0.0

    @farmfe/plugin-strip

    +
    版本:1.0.0

    @farmfe/plugin-strip

    🍣 一个Farm Rust插件,用于从你的代码中移除debugger语句和如assert.equalconsole.log这样的函数。

    -

    要求

    +

    要求

    这个插件需要一个LTS Node版本(v18.0.0+)和Farm v1.0.0+。

    -

    安装

    -
    npm install @farmfe/plugin-strip
    -

    使用

    +

    安装

    +
    npm install @farmfe/plugin-strip
    +

    使用

    创建一个farm.config.js配置文件并导入插件:

    -
    import { defineConfig } from '@farmfe/core';
    import strip from '@farmfe/plugin-strip';

    export default defineConfig({
    // ...
    plugins: [
    [
    strip({
    // 插件选项
    functions:[ 'console.*', 'assert.*' ],
    labels: ['unittest']
    })
    ]
    ],
    // ...
    });
    -

    选项

    -

    include

    +
    import { defineConfig } from '@farmfe/core';
    import strip from '@farmfe/plugin-strip';

    export default defineConfig({
    // ...
    plugins: [
    [
    strip({
    // 插件选项
    functions:[ 'console.*', 'assert.*' ],
    labels: ['unittest']
    })
    ]
    ],
    // ...
    });
    +

    选项

    +

    include

    类型: String | RegExp | Array[...String|RegExp]
    默认值: ['**/*.js']
    示例: include: '**/*.(mjs|js)',

    指定插件应操作的构建中的文件的模式或模式数组。

    -

    exclude

    +

    exclude

    类型: String | RegExp | Array[...String|RegExp]
    默认值: []
    示例: exlude: 'tests/**/*',

    指定插件应_忽略_的构建中的文件的模式或模式数组。

    -

    debugger

    +

    debugger

    类型: Boolean
    默认值: true
    示例: debugger: false,

    如果为true,指示插件移除debugger语句。

    -

    functions

    +

    functions

    类型: Array[...String]
    默认值: [ 'console.*', 'assert.*' ]
    示例: functions: [ 'console.log', 'MyClass.Test' ],

    指定插件将目标定位和移除的函数。

    注意:指定在链的开头使用的函数,如'a().b().c()',将导致'(void 0).b().c()',这在运行时会产生错误。

    -

    labels

    +

    labels

    类型: Array[...String]
    默认值: []
    示例: labels: ['unittest'],

    指定插件将目标定位和移除的带标签的块或语句

    注意:':'是隐含的,不应在配置中指定。

    -

    sourceMap

    +

    sourceMap

    类型: Boolean
    默认值: true
    示例: sourceMap: false,

    -

    如果为true,指示插件在从捆绑包中移除配置的目标后相应地更新源映射。

    +

    如果为true,指示插件在从捆绑包中移除配置的目标后相应地更新源映射。

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/virtual/index.html b/zh/docs/plugins/official-plugins/virtual/index.html index 10c8b2c16..e40664e4e 100644 --- a/zh/docs/plugins/official-plugins/virtual/index.html +++ b/zh/docs/plugins/official-plugins/virtual/index.html @@ -8,24 +8,24 @@ - - - + + + -
    版本:1.0.0

    @farmfe/plugin-virtual

    +
    版本:1.0.0

    @farmfe/plugin-virtual

    @rollup/plugin-virtual 启发

    一个为farm打造的rust插件,用于轻松使用虚拟模块

    -

    安装

    -
    npm install @farmfe/plugin-virtual
    -

    使用

    +

    安装

    +
    npm install @farmfe/plugin-virtual
    +

    使用

    farm.config.ts

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-virtual',
    {
    'virtual-module': 'export const a = 1',
    'src/01.js': 'export const module01 = "virtual-module"',
    },
    ],
    ],
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-virtual',
    {
    'virtual-module': 'export const a = 1',
    'src/01.js': 'export const module01 = "virtual-module"',
    },
    ],
    ],
    });

    index.js

    -
    import { a } from 'virtual-module';
    +
    import { a } from 'virtual-module';

    src/02.js

    -
    import { module01 } from './01.js';
    +
    import { module01 } from './01.js';

    这个 @farmfe/plugin-virtual 插件允许你定义虚拟模块,这些模块并不对应任何实际的文件系统中的文件,但可以像普通模块一样被导入和使用。这在模拟第三方库、环境变量或任何不便于直接放在文件系统中的数据时特别有用。

    -

    通过在 farm.config.ts 配置文件中的 plugins 数组中注册插件并配置虚拟模块,你可以在项目中的任何地方通过指定的模块名来导入这些虚拟模块。在上面的例子中,定义了一个名为 virtual-module 的虚拟模块,它导出了一个常量 a,以及另一个名为 src/01.js 的虚拟模块,它导出了一个名为 module01 的变量。这些模块随后可以在项目中的任何地方被导入和使用,就像它们是实际存在于文件系统中的一样。

    +

    通过在 farm.config.ts 配置文件中的 plugins 数组中注册插件并配置虚拟模块,你可以在项目中的任何地方通过指定的模块名来导入这些虚拟模块。在上面的例子中,定义了一个名为 virtual-module 的虚拟模块,它导出了一个常量 a,以及另一个名为 src/01.js 的虚拟模块,它导出了一个名为 module01 的变量。这些模块随后可以在项目中的任何地方被导入和使用,就像它们是实际存在于文件系统中的一样。

    \ No newline at end of file diff --git a/zh/docs/plugins/official-plugins/yaml/index.html b/zh/docs/plugins/official-plugins/yaml/index.html index 6ca34cb29..05be5cdb1 100644 --- a/zh/docs/plugins/official-plugins/yaml/index.html +++ b/zh/docs/plugins/official-plugins/yaml/index.html @@ -8,21 +8,21 @@ - - - + + + -
    版本:1.0.0

    @farmfe/plugin-yaml

    +
    版本:1.0.0

    @farmfe/plugin-yaml

    @rollup/plugin-yaml 启发

    🍣 一个Farm插件,用于将YAML文件转换为ES6模块。

    -

    安装

    -
    npm install @farmfe/plugin-yaml
    -

    使用

    +

    安装

    +
    npm install @farmfe/plugin-yaml
    +

    使用

    farm.config.ts

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-yaml',
    {
    documentMode: 'single' | 'multi', // 默认 single
    include: Regex, // 默认 None
    exclude: Regex, // 默认 None
    },
    ],
    ],
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    plugins: [
    [
    '@farmfe/plugin-yaml',
    {
    documentMode: 'single' | 'multi', // 默认 single
    include: Regex, // 默认 None
    exclude: Regex, // 默认 None
    },
    ],
    ],
    });

    注意:

    includeexclude 使用的是正则表达式而不是glob。例如 **/01.yaml 是不合法的。正确的表达方式类似于 ".*\\/01.yaml"

    -

    这个插件允许你在Farm项目中直接导入YAML文件,并将它们转换成ES6模块。documentMode 选项允许你指定处理单个文档的YAML文件(single)或包含多个文档的YAML文件(multi)。includeexclude 选项让你可以更细致地控制哪些YAML文件应该被插件处理,通过指定匹配特定格式的正则表达式。这种灵活性让你能够在Farm项目中轻松地处理和利用YAML数据。

    +

    这个插件允许你在Farm项目中直接导入YAML文件,并将它们转换成ES6模块。documentMode 选项允许你指定处理单个文档的YAML文件(single)或包含多个文档的YAML文件(multi)。includeexclude 选项让你可以更细致地控制哪些YAML文件应该被插件处理,通过指定匹配特定格式的正则表达式。这种灵活性让你能够在Farm项目中轻松地处理和利用YAML数据。

    \ No newline at end of file diff --git a/zh/docs/plugins/writing-plugins/js-plugin/index.html b/zh/docs/plugins/writing-plugins/js-plugin/index.html index 5243c93bf..8416997c6 100644 --- a/zh/docs/plugins/writing-plugins/js-plugin/index.html +++ b/zh/docs/plugins/writing-plugins/js-plugin/index.html @@ -8,21 +8,21 @@ - - - + + + -
    版本:1.0.0

    编写 JavaScript 插件

    +
    版本:1.0.0

    编写 JavaScript 插件

    一个 JavaScript 插件只是一个定义了一系列 hooks 的纯 JavaScript 对象:

    -
    // farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    plugins: [
    // 一个插件对象
    {
    name: "my-resolve-plugin",
    priority: 1000, // 插件的优先级越高越早执行 通常的优先级是 100
    resolve: {
    filters: {
    // 仅仅符合下面的条件才会执行 hook
    sources: ["\\./index.ts"], // 正则表达式的数组
    importers: ["None"],
    },
    executor: async (param) => {
    // hook 执行器
    console.log(param); // 解析 param
    // 返回最终的结果
    return {
    resolvedPath: "virtual:my-module",
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // Load、transform和 resolve 类似, 引用他们的类型
    ],
    });
    +
    // farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // ...
    plugins: [
    // 一个插件对象
    {
    name: "my-resolve-plugin",
    priority: 1000, // 插件的优先级越高越早执行 通常的优先级是 100
    resolve: {
    filters: {
    // 仅仅符合下面的条件才会执行 hook
    sources: ["\\./index.ts"], // 正则表达式的数组
    importers: ["None"],
    },
    executor: async (param) => {
    // hook 执行器
    console.log(param); // 解析 param
    // 返回最终的结果
    return {
    resolvedPath: "virtual:my-module",
    query: {},
    sideEffects: false,
    external: false,
    };
    },
    },
    },
    // Load、transform和 resolve 类似, 引用他们的类型
    ],
    });

    如果你想向插件传递参数,可以使用闭包

    -
    // my-resolve-plugin.ts
    export function myResolvePlugin(options: Options) {
    const { xx } = options;

    return {
    name: "my-resolve-plugin",
    resolve: {
    // ...
    },
    };
    }

    // farm.config.ts
    import { defineConfig } from "@farmfe/core";
    import { myResolvePlugin } from "./myResolvePlugin.ts";

    export default defineConfig({
    // ...
    plugins: [myResolvePlugin({ xx: "xx" })],
    });
    -
    备注
      +
      // my-resolve-plugin.ts
      export function myResolvePlugin(options: Options) {
      const { xx } = options;

      return {
      name: "my-resolve-plugin",
      resolve: {
      // ...
      },
      };
      }

      // farm.config.ts
      import { defineConfig } from "@farmfe/core";
      import { myResolvePlugin } from "./myResolvePlugin.ts";

      export default defineConfig({
      // ...
      plugins: [myResolvePlugin({ xx: "xx" })],
      });
      +
      备注
      • 参考 创建插件,可以根据官方模版快速写一个新的插件
      • 本文档仅介绍如何创建、开发和发布一个 JavaScript 插件,有关插件 hook 的更多细节,请参阅Javascript 插件 Hooks
      -

      约定

      +

      约定

      对于特定的 Farm JavaScript 插件

      • 一个 Farm 的 JavaScript 插件应该有一个 farm-plugin- 前缀的名称并且语义清晰
      • @@ -35,7 +35,7 @@

        约定概念

        +

        概念

        在开始编写 JavaScript 插件之前,你应该了解以下概念:

        • filters: 由于 JavaScript 插件运行要比 Rust 插件慢得多,你的 JavaScript 插件应该显式的设置 filter 来避免不必要的 hook 调用。 举个例子,你应该设置 transform.filters.moduleTypes = ['js'] 来确保你的 JavaScript 插件 transform 钩子仅仅在 .js/mjs/cjs 文件执行
        • @@ -44,26 +44,26 @@

          概念Filters

          +

          Filters

          由于 JavaScript插件Rust插件 慢得多,Farm 使用 filters 来控制 JavaScript 插件钩子的执行。为了提高性能,只有匹配当前的 filters ,插件钩子才会执行。filters 对于一些常用的钩子是必需的,例如resolveloadtransform等。 例如,如果你想转换 css 文件,你可以使用transform.filters. moduletypes = ['css']来确保 JavaScript 插件的 transform 钩子只对.css文件运行:

          -
          const myCssPlugin = {
          name: "my-css-plugin",
          transform: {
          filters: {
          // Only execute the hook when following conditions satisfied
          // resolvedPaths: ["\\./index.ts"], // a regex array to match the resolvedPaths
          moduleTypes: ["css"],
          },
          executor: async (param) => {
          // transform css
          },
          },
          };
          -

          Module Type

          +
          const myCssPlugin = {
          name: "my-css-plugin",
          transform: {
          filters: {
          // Only execute the hook when following conditions satisfied
          // resolvedPaths: ["\\./index.ts"], // a regex array to match the resolvedPaths
          moduleTypes: ["css"],
          },
          executor: async (param) => {
          // transform css
          },
          },
          };
          +

          Module Type

          在 Farm 中,一切都被认为是“一等公民”,因此 Farm 设计 module_type 来标识模块类型,并在用不同的插件处理不同的模块类型 Module_type load 钩子返回,并且可以由 transform 钩子转换。Farm 原生支持 js/ts/jsx/tsxcsshtmljsonstatic assets(png、svg等)。对于这些模块类型,你可以直接在 loadtransform hook 中返回。但是如果你想处理自定义模块类型,你需要实现其他钩子例如 parserender_resource_pot_modulesgenerate resources 等来控制如何对自定义模块进行类型解析,渲染和生成资源。

          -

          创建插件

          +

          创建插件

          Farm 提供了官方模板来帮助你快速创建 JavaScript 插件:

          -
          pnpm create farm-plugin
          +
          pnpm create farm-plugin

          然后按照提示创建插件

          或者直接运行以下命令创建插件:

          -
          pnpm create farm-plugin my-farm-plugin --type js
          +
          pnpm create farm-plugin my-farm-plugin --type js

          上面的命令会在当前目录中创建一个名为 my-farm-plugin 的js插件。——type 可以是 rust 或者 js

          -

          开发一个插件

          +

          开发一个插件

          创建插件后,就可以开始开发插件了。这个插件只是一个定义了一系列 hooks 的纯 JavaScript 对象:

          -
          // import { readFileSync } from 'node:fs';
          import type { JsPlugin } from '@farmfe/core';

          interface Options {
          /* Your options here */
          }

          export default function farmPlugin(options: Options): JsPlugin {
          return {
          name: '<FARM-JS-PLUGIN-NPM-NAME>',
          /* Your plugin hooks here: */

          // transform: {
          // filters: {
          // moduleTypes: ['js']
          // },
          // async executor(params) {
          // const { content } = params;
          // return {
          // content,
          // moduleType: 'js'
          // };
          // }
          // },
          // finish: {
          // executor() {}
          // }
          };
          }
          -
          提示

          有关插件钩子的更多细节, 参阅Javascript 插件 Hooks.

          +
          // import { readFileSync } from 'node:fs';
          import type { JsPlugin } from '@farmfe/core';

          interface Options {
          /* Your options here */
          }

          export default function farmPlugin(options: Options): JsPlugin {
          return {
          name: '<FARM-JS-PLUGIN-NPM-NAME>',
          /* Your plugin hooks here: */

          // transform: {
          // filters: {
          // moduleTypes: ['js']
          // },
          // async executor(params) {
          // const { content } = params;
          // return {
          // content,
          // moduleType: 'js'
          // };
          // }
          // },
          // finish: {
          // executor() {}
          // }
          };
          }
          +
          提示

          有关插件钩子的更多细节, 参阅Javascript 插件 Hooks.

          运行 npm Run dev 来编译插件开启监听。运行 npm Run build 来构建插件

          -

          发布插件

          -

          JavaScript 插件是一个普通的 npm 包,你可以通过运行 npm publish 将其发布到 npm registry。

    +

    发布插件

    +

    JavaScript 插件是一个普通的 npm 包,你可以通过运行 npm publish 将其发布到 npm registry。

    \ No newline at end of file diff --git a/zh/docs/plugins/writing-plugins/overview/index.html b/zh/docs/plugins/writing-plugins/overview/index.html index 5368624d3..f219287b7 100644 --- a/zh/docs/plugins/writing-plugins/overview/index.html +++ b/zh/docs/plugins/writing-plugins/overview/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:1.0.0

    概览

    +
    版本:1.0.0

    概览

    Farm 采用完全插件化的形式,提供了多种类型的插件来干预 Farm 的几乎所有行为,Farm 支持的主要插件类型分为以下几类:

    • 编译插件:干预、增强 Farm 的编译能力,支持使用 Rust(推荐)以及 Js 编写插件
    • @@ -21,11 +21,11 @@
    • Dev Server 插件:干预、增强 Farm 的 Dev Server,例如挂载更多变量,注册 middleware 等

    To use a Rust plugin, configuring plugins in farm.config.ts.

    -
    import { defineFarmConfig } from '@farmfe/core/dist/config';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    +
    import { defineFarmConfig } from '@farmfe/core/dist/config';

    defineFarmConfig({
    // ...
    plugins: [
    { /*..*/ }, // Js plugin, a object with hook defined
    '@farmfe/plugin-react', // rust plugin package name
    ]
    })

    Farm support both rust plugins and js plugins:

    +
    \ No newline at end of file diff --git a/zh/docs/plugins/writing-plugins/runtime-plugin/index.html b/zh/docs/plugins/writing-plugins/runtime-plugin/index.html index 437886eda..7a812e265 100644 --- a/zh/docs/plugins/writing-plugins/runtime-plugin/index.html +++ b/zh/docs/plugins/writing-plugins/runtime-plugin/index.html @@ -8,57 +8,57 @@ - - - + + + -
    版本:1.0.0

    编写 Runtime 插件

    +
    版本:1.0.0

    编写 Runtime 插件

    Farm 运行时插件是一个纯 JavaScript 对象,它定义了一组钩子来增强 Farm 运行时。 例子:

    -
    /**
    * HMR 客户端作为 Farm 运行时插件
    */
    import type { Plugin } from '@farmfe/runtime';
    import { createHotContext } from './hot-module-state';
    import { HmrClient } from './hmr-client';

    let hmrClient: HmrClient;
    // 导出 Farm 运行时插件对象
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // 定义钩子
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    moduleCreated(module) {
    // 为每个模块创建一个 hot 上下文
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };
    +
    /**
    * HMR 客户端作为 Farm 运行时插件
    */
    import type { Plugin } from '@farmfe/runtime';
    import { createHotContext } from './hot-module-state';
    import { HmrClient } from './hmr-client';

    let hmrClient: HmrClient;
    // 导出 Farm 运行时插件对象
    export default <Plugin>{
    name: 'farm-runtime-hmr-client-plugin',
    // 定义钩子
    bootstrap(moduleSystem) {
    hmrClient = new HmrClient(moduleSystem);
    hmrClient.connect();
    },
    moduleCreated(module) {
    // 为每个模块创建一个 hot 上下文
    module.meta.hot = createHotContext(module.id, hmrClient);
    }
    };

    上面是一个支持 Farm 的 HMR 的运行时插件。 要点:

    • 运行时插件入口文件应该 导出 定义一组钩子的默认对象。 例如 导出默认 <Plugin>{/*...*/}
    • 需要name来标识插件,确保name是唯一的
    • hook 是在导出对象中定义的方法。
    -
    备注

    有关上述示例的完整实现,请参阅 @farmfe/runtime-plugin-hmr

    -

    注意事项

    +
    备注

    有关上述示例的完整实现,请参阅 @farmfe/runtime-plugin-hmr

    +

    注意事项

    您应该使您的运行时插件尽可能简单。 你不应该

    • 使用node_modules中的大依赖,这会让你的 Farm 运行时插件非常大,可能会严重影响运行时性能。
    • 使用 top level await 等新功能,因为这些与运行时相关的功能很难针对低级别运行时进行 polyfill。

    强烈建议确保您的运行时插件尽可能小且简单

    -
    提示

    import.meta.xxx 将被编译为 module.meta.xxx,您可以在运行时插件中向 module.meta 添加值来增强 import.meta。 例如, module.meta.hot = createHotContext(module.id, hmrClient) 使 import.meta.hot 可用。

    -

    惯例

    +
    提示

    import.meta.xxx 将被编译为 module.meta.xxx,您可以在运行时插件中向 module.meta 添加值来增强 import.meta。 例如, module.meta.hot = createHotContext(module.id, hmrClient) 使 import.meta.hot 可用。

    +

    惯例

    Farm 运行时插件名称应以 farm-runtime-plugin 为前缀,例如 farm-runtime-plugin-xxx

    -
    备注

    plugin.namepackage name(仅当您将插件发布为包时)都应该加上前缀。

    -

    使用 Runtime 插件

    +
    备注

    plugin.namepackage name(仅当您将插件发布为包时)都应该加上前缀。

    +

    使用 Runtime 插件

    使用 compilation.runtime.plugins 为您的项目配置运行时插件:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // relative path
    './src/my-plugin1.ts',
    // absolute path
    '/root/project/src/my-plugin2.ts',
    // package name
    '@scope/plugin-package-from-node-modules'
    ]
    }
    }
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // relative path
    './src/my-plugin1.ts',
    // absolute path
    '/root/project/src/my-plugin2.ts',
    // package name
    '@scope/plugin-package-from-node-modules'
    ]
    }
    }
    });

    您可以通过 3 种方式配置运行时插件项:

    • 相对路径:相对于root的路径,例如./src/my-plugin1.ts将尝试从<root>/src/my-plugin1.ts加载插件。
    • 绝对路径:例如/root/project/src/my-plugin2.ts。 (在 Windows 上绝对路径应为 C:\project\src\my-plugin2.ts )。
    • 包名称:Farm将尝试从node_modules加载此包,例如@scope/plugin-package-from-node-modules
    -

    编写 Runtime 插件

    -
    提示

    Farm支持直接加载.ts文件,因此您可以直接在runtime.plugins中配置一个.ts文件(或条目为ts文件的包)。

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // configuring ts file directly
    './src/my-plugin.ts',
    ]
    }
    }
    });
    -

    创建插件

    +

    编写 Runtime 插件

    +
    提示

    Farm支持直接加载.ts文件,因此您可以直接在runtime.plugins中配置一个.ts文件(或条目为ts文件的包)。

    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    // configuring ts file directly
    './src/my-plugin.ts',
    ]
    }
    }
    });
    +

    创建插件

    正如我们上面提到的,Farm 运行时插件是一个纯 JavaScript 对象,它定义了一组钩子,您只需创建一个 ts 文件,例如:

    -
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    // ...
    }
    +
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    // ...
    }

    然后在导出的对象中定义您需要的hooks

    -
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    moduleCreated(module) {
    // ...
    },
    readModuleCache(module) {
    // ...
    },
    loadResource(resource, targetEnv) {
    // ...
    },
    // ... more hooks as long as you need
    }
    -

    定义插件

    +
    ./plugins/runtime.ts
    import type { Plugin } from '@farmfe/runtime';

    export default <Plugin> {
    name: 'my-plugin',
    moduleCreated(module) {
    // ...
    },
    readModuleCache(module) {
    // ...
    },
    loadResource(resource, targetEnv) {
    // ...
    },
    // ... more hooks as long as you need
    }
    +

    定义插件

    配置您在 runtime.plugins 中创建的插件:

    -
    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    './plugins/runtime.ts',
    ]
    }
    }
    });
    +
    export default defineConfig({
    compilation: {
    runtime: {
    plugins: [
    './plugins/runtime.ts',
    ]
    }
    }
    });

    然后启动Farm项目,这个插件会在编译时注入输出资源的 runtime 中。

    -

    发布插件(可选)

    +

    发布插件(可选)

    您可以将运行时插件发布到 npm 注册表以共享您的 Farm 运行时插件。 只需创建一个 package.json ,例如:

    -
    {
    "name": "@farmfe/runtime-plugin-hmr",
    "version": "3.4.2",
    "description": "Runtime hmr plugin of Farm",
    "main": "src/index.ts",
    // ... ignore other fields
    }
    +
    {
    "name": "@farmfe/runtime-plugin-hmr",
    "version": "3.4.2",
    "description": "Runtime hmr plugin of Farm",
    "main": "src/index.ts",
    // ... ignore other fields
    }

    You can just export ts file using "main": "src/index.ts".

    -

    运行时插件钩子

    -

    请参阅运行时插件 API

    +

    运行时插件钩子

    +

    请参阅运行时插件 API

    \ No newline at end of file diff --git a/zh/docs/plugins/writing-plugins/rust-plugin/index.html b/zh/docs/plugins/writing-plugins/rust-plugin/index.html index 485977004..a66d8c1c8 100644 --- a/zh/docs/plugins/writing-plugins/rust-plugin/index.html +++ b/zh/docs/plugins/writing-plugins/rust-plugin/index.html @@ -8,14 +8,14 @@ - - - + + + -
    版本:1.0.0

    编写 Rust 插件

    +
    版本:1.0.0

    编写 Rust 插件

    用 Rust 写你的插件是一个推荐的方式,因为 Rust 插件比 JavaScript 插件更快和富有表现力。一个 Rust 插件应该是实现了 farmfe_core::plugin::Plugin trait 的 struct, 例如

    -
    #![deny(clippy::all)]

    use farmfe_core::{config::Config, plugin::Plugin};

    use farmfe_macro_plugin::farm_plugin;

    // define your rust plugins
    #[farm_plugin]
    pub struct FarmPluginExample {}

    impl FarmPluginExample {
    // 一个 Rust 插件必须导出一个名称是 new 的函数 并且初始化的时候接受两个参数
    fn new(config: &Config, options: String) -> Self {
    Self {}
    }
    }
    // 实现插件的 trait 来定义插件 hooks
    impl Plugin for FarmPluginExample {
    fn name(&self) -> &str {
    "FarmPluginExample"
    }

    // more hooks here
    }
    +
    #![deny(clippy::all)]

    use farmfe_core::{config::Config, plugin::Plugin};

    use farmfe_macro_plugin::farm_plugin;

    // define your rust plugins
    #[farm_plugin]
    pub struct FarmPluginExample {}

    impl FarmPluginExample {
    // 一个 Rust 插件必须导出一个名称是 new 的函数 并且初始化的时候接受两个参数
    fn new(config: &Config, options: String) -> Self {
    Self {}
    }
    }
    // 实现插件的 trait 来定义插件 hooks
    impl Plugin for FarmPluginExample {
    fn name(&self) -> &str {
    "FarmPluginExample"
    }

    // more hooks here
    }

    Rust 插件注意事项:

    • struct 必须是 pub 并且需要有 #[farm_plugin] 属性
    • @@ -23,8 +23,8 @@
    • struct 必须导出一个 new 的方法,在初始化的时候接受两个参数 第一个参数是 &Config, 第二个参数是 Stringnew 方法在插件加载的时候调用。 Config 是 farm 项目的配置 String 是插件的选项

    我们同时提供了 Rust 插件示例代码仓库:farm-rust-plugin-example

    -
    备注

    本文章仅仅涵盖如何创建,开发和发布一个 Rust 插件,更多的细节参考 插件 Hooks

    -

    约定

    +
    备注

    本文章仅仅涵盖如何创建,开发和发布一个 Rust 插件,更多的细节参考 插件 Hooks

    +

    约定

    对于特定的 Farm 插件

    • 一个 Farm 的 Rust 插件应该有一个 farm-plugin- 前缀的名称并且语义清晰
    • @@ -37,7 +37,7 @@

      约定概念

      +

      概念

      在开始编写 Rust 插件之前,你应该了解以下概念:

      • module_type:模块的类型,他可能是 js, ts, css, sass, json 等等。Farm 原生支持 js/ts/jsx/tsx, css, html, json, static asserts(png, svg等等)module_type 会被 load 或者 transform 钩子返回
      • @@ -45,19 +45,19 @@

        概念模块类型

        +

        模块类型

        在 Farm 中,一切都被认为是“一等公民”,因此 Farm 设计 module_type 来标识模块类型,并在用不同的插件处理不同的模块类型 Module_type load 钩子返回,并且可以由 transform 钩子转换。Farm 原生支持 js/ts/jsx/tsxcsshtmljsonstatic assets(png、svg等)。对于这些模块类型,你可以直接在 loadtransform hook 中返回。但是如果你想处理自定义模块类型,你需要实现其他钩子例如 parserender_resource_pot_modulesgenerate resources 等来控制如何对自定义模块进行类型解析,渲染和生成资源。

        -

        创建插件

        +

        创建插件

        Farm 提供了官方模板来帮助你快速创建 Rust 插件:

        -
        pnpm create farm-plugin
        +
        pnpm create farm-plugin

        然后按照提示创建插件

        或者直接运行以下命令创建插件:

        -
        pnpm create farm-plugin my-farm-plugin --type rust
        +
        pnpm create farm-plugin my-farm-plugin --type rust

        上面的命令会在当前目录中创建一个名为 my-farm-plugin 的js插件。——type 可以是 rust 或者 js

        -

        插件项目结构

        +

        插件项目结构

        一个插件项目结构如下:

        -
        my-farm-plugin
        ├── .github
        │ └── workflows
        | ├── release.yml
        | ├── build.yml
        │ └── ci.yml
        ├── Cargo.toml
        |── .gitignore
        ├── npm
        │ ├── darwin-x64
        │ ├── linux-x64-gnu
        | ├── win32-x64-msvc
        │ └── ...
        ├── package.json
        ├── src
        │ └── lib.rs
        └── rust-toolchain.toml
        +
        my-farm-plugin
        ├── .github
        │ └── workflows
        | ├── release.yml
        | ├── build.yml
        │ └── ci.yml
        ├── Cargo.toml
        |── .gitignore
        ├── npm
        │ ├── darwin-x64
        │ ├── linux-x64-gnu
        | ├── win32-x64-msvc
        │ └── ...
        ├── package.json
        ├── src
        │ └── lib.rs
        └── rust-toolchain.toml

        值得注意的文件和目录:

        • src/lib.rs: 插件的主要文件,你在这里定义你的插件
        • @@ -68,49 +68,49 @@

          插件项
        • rust-toolchain.toml: rust 工具链文件,它不应该 被手动修改,它应该始终使用 与 farm core相同的版本

        Farm 提供了一个工具 (@farmfe/plugin-tools) 来帮助你构建和发布插件,参考 package.json:

        -
        {
        // ...
        "scripts": {
        // build your plugin for current platform
        "build": "farm-plugin-tools build --platform --cargo-name my_farm_plugin -p my_farm_plugin --release",
        // publish all platform packages under npm directory to npm registry
        "prepublishOnly": "farm-plugin-tools prepublish"
        },
        // ...
        }
        +
        {
        // ...
        "scripts": {
        // build your plugin for current platform
        "build": "farm-plugin-tools build --platform --cargo-name my_farm_plugin -p my_farm_plugin --release",
        // publish all platform packages under npm directory to npm registry
        "prepublishOnly": "farm-plugin-tools prepublish"
        },
        // ...
        }

        更多关于构建和发布的细节参考 构建发布章节:

        -

        开发插件

        +

        开发插件

        为了在本地开发和测试你的插件 你首先依据你平台构建插件,运行:

        -
        pnpm build
        +
        pnpm build

        然后你可以使用你构建好的插件,在 frame.config.tsplugins添加你的插件:

        -
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        plugins: [
        'my-farm-plugin'
        ]
        });
        +
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        plugins: [
        'my-farm-plugin'
        ]
        });

        在你的 farm 项目中运行 pnpm i 并且运行 farm start 来运行你的带有你插件的 farm 项目 当对插件进行更改时,应该重新构建插件并重启 farm 项目以查看更改。例如,在你的插件中添加 load 钩子:

        -
        src/lib.rs
        // ... ignore other code

        impl Plugin for FarmPluginExample {
        fn name(&self) -> &str {
        "FarmPluginExample"
        }

        fn load(
        &self,
        param: &farmfe_core::plugin::PluginLoadHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
        println!(
        "load path: {:?}, id: {:?}",
        param.resolved_path, param.module_id
        );
        Ok(None)
        }
        }
        +
        src/lib.rs
        // ... ignore other code

        impl Plugin for FarmPluginExample {
        fn name(&self) -> &str {
        "FarmPluginExample"
        }

        fn load(
        &self,
        param: &farmfe_core::plugin::PluginLoadHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
        println!(
        "load path: {:?}, id: {:?}",
        param.resolved_path, param.module_id
        );
        Ok(None)
        }
        }

        然后用 pnpm build 重新构建你的插件,用 farm start 重新启动你的 farm 项目,你会看到 load 钩子在编译你的 farm 项目时被调用。

        -
        备注

        想了解更多关于插件 hooks , 参阅 插件钩子.

        -

        处理 ModuleType

        +
        备注

        想了解更多关于插件 hooks , 参阅 插件钩子.

        +

        处理 ModuleType

        module_typeload hook 或 transform hook 返回。你在 load hook 中可以给 module 设置任意的 module type,该模块将由支持该模块类型的相应插件处理。 对于原生支持的模块类型,你可以在 load 钩子中返回模块类型:

        -
        src/lib.rs
        // ... ignore other code

        impl Plugin for FarmPluginExample {
        fn name(&self) -> &str {
        "FarmPluginExample"
        }

        fn load(
        &self,
        param: &farmfe_core::plugin::PluginLoadHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
        // handle virtual module
        if param.module_id.starts_with("virtual:my-css:css") {
        // return module type and content
        Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
        module_type: "css".to_string(),
        content: ".red { color: red; }".to_string(),
        ..Default::default()
        }))
        } else {
        Ok(None)
        }
        }
        }
        +
        src/lib.rs
        // ... ignore other code

        impl Plugin for FarmPluginExample {
        fn name(&self) -> &str {
        "FarmPluginExample"
        }

        fn load(
        &self,
        param: &farmfe_core::plugin::PluginLoadHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
        // handle virtual module
        if param.module_id.starts_with("virtual:my-css:css") {
        // return module type and content
        Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
        module_type: "css".to_string(),
        content: ".red { color: red; }".to_string(),
        ..Default::default()
        }))
        } else {
        Ok(None)
        }
        }
        }

        对于原生支持的模块类型,你应该使用 transform hook 将模块类型转换为原生支持的模块类型,否则你需要实现 parserenderResourcePot hook 来处理你的自定义模块类型:

        -
        src/lib.rs
        // ... ignore other code

        impl Plugin for FarmPluginExample {
        fn name(&self) -> &str {
        "FarmPluginExample"
        }

        fn transform(
        &self,
        param: &farmfe_core::plugin::PluginTransformHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
        // module type guard is required
        if matches!(param.module_type, ModuleType::Custom("sass")) {
        // compile sass and transform the module type from sass to css
        Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
        module_type: "css".to_string(),
        content: compileSass(param.content),
        ..Default::default()
        }))
        } else {
        Ok(None)
        }
        }
        }
        -
        备注

        模块类型保护,如 matches!(module_type, ModuleType::Custom("sass")) transform 钩子是必需的,因为所有模块类型都会调用 transform 钩子,并且你应该只在 transform hook 中处理你的自定义模块类型。parse和其他 hook 也是如此。

        +
        src/lib.rs
        // ... ignore other code

        impl Plugin for FarmPluginExample {
        fn name(&self) -> &str {
        "FarmPluginExample"
        }

        fn transform(
        &self,
        param: &farmfe_core::plugin::PluginTransformHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
        // module type guard is required
        if matches!(param.module_type, ModuleType::Custom("sass")) {
        // compile sass and transform the module type from sass to css
        Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
        module_type: "css".to_string(),
        content: compileSass(param.content),
        ..Default::default()
        }))
        } else {
        Ok(None)
        }
        }
        }
        +
        备注

        模块类型保护,如 matches!(module_type, ModuleType::Custom("sass")) transform 钩子是必需的,因为所有模块类型都会调用 transform 钩子,并且你应该只在 transform hook 中处理你的自定义模块类型。parse和其他 hook 也是如此。

        或者实现 parserender_resource_pot_modules 钩子来处理你的自定义模块类型 参考 farm 如何原生处理 css 插件如何处理 css 模块类型的 farm-plugin-css

        -

        处理插件选项

        +

        处理插件选项

        rust 插件选项可以在farm.config.ts中配置:

        -
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        plugins: [
        ['my-farm-plugin', {
        // plugin options
        myOption: 'myOption'
        }]
        ]
        });
        +
        import { defineConfig } from '@farmfe/core';

        export default defineConfig({
        plugins: [
        ['my-farm-plugin', {
        // plugin options
        myOption: 'myOption'
        }]
        ]
        });

        该选项将被 json 序列化并传递给插件的new方法,你可以在new方法中处理该选项:

        -
        src/lib.rs
        // ... ignore other code

        // define your rust plugin options
        #[derive(serde::Deserialize)]
        pub struct Options {
        pub my_option: Option<String>,
        }

        impl FarmPluginExample {
        fn new(config: &Config, options: String) -> Self {
        // deserialize the options
        let my_option: Options = serde_json::from_str(&options).unwrap();
        // handle the options...
        Self {}
        }
        }
        +
        src/lib.rs
        // ... ignore other code

        // define your rust plugin options
        #[derive(serde::Deserialize)]
        pub struct Options {
        pub my_option: Option<String>,
        }

        impl FarmPluginExample {
        fn new(config: &Config, options: String) -> Self {
        // deserialize the options
        let my_option: Options = serde_json::from_str(&options).unwrap();
        // handle the options...
        Self {}
        }
        }

        请注意,你应该将依赖 serdeserde_json 添加到你的Cargo.toml中。来支持反序列化:

        -
        [dependencies]
        # ... ignore other code
        serde = { version = "1.0", features = ["derive"] }
        serde_json = "1.0"
        -
        备注

        不能被 json 序列化选项不被支持。这意味着你只能使用字符串、数字、布尔值、数组、对象等类型。不支持函数选项

        -

        在插件里面使用 farm_core

        +
        [dependencies]
        # ... ignore other code
        serde = { version = "1.0", features = ["derive"] }
        serde_json = "1.0"
        +
        备注

        不能被 json 序列化选项不被支持。这意味着你只能使用字符串、数字、布尔值、数组、对象等类型。不支持函数选项

        +

        在插件里面使用 farm_core

        Farm 在 farmfe_core crate 中暴露所有核心结构和工具函数。更多细节请参阅farmfe_core文档。

        -
        备注

        如果你想在插件中使用 swc 中的 ModuleProgram 等结构,你应该使用由 farm_core 重新暴露的 farmfe_core::swc_ast。因为 farm_core 使用的 swc 版本可能与你在插件中使用的 swc 版本不同,并且 farm_core 使用的 swc 版本保证与 farm_core 兼容。

        -

        警告

        -

        在插件中使用 SWC

        +
        备注

        如果你想在插件中使用 swc 中的 ModuleProgram 等结构,你应该使用由 farm_core 重新暴露的 farmfe_core::swc_ast。因为 farm_core 使用的 swc 版本可能与你在插件中使用的 swc 版本不同,并且 farm_core 使用的 swc 版本保证与 farm_core 兼容。

        +

        警告

        +

        在插件中使用 SWC

        请注意,你的 rust 插件不应该使用任何与 SWC 相关的包,如swc_commonswc_transforms等。SWC 在进程中存储全局状态,当你在插件中使用 SWC 时,它可能会导致死锁

        如果你想要修改你的 Farm 项目的AST,建议写[SWC Plugin](/zh/docs/using-plugins#using-swc plugins)。关于如何编写SWC插件,请参阅编写SWC插件

        -

        选择 Rust 工具链

        +

        选择 Rust 工具链

        因为 Farm 的 Rust 插件是一个动态链接库,你应该始终使用和 farm core 相同版本的 Rust 工具链。rust 工具链定义在 rust-toolchain.toml中。它不应该被手动修改。 并且应该始终使用 Rust 构建插件,因为Farm Core 不支持 FFI,也不承诺 ABI 稳定性以提供最佳性能。

        -

        插件的兼容性

        +

        插件的兼容性

        Farm core 维护了一个向插件暴漏出来一个 API 版本。如果你遇到类似Incompatible Rust Plugin: Current core's version…,这意味着你的插件与当前 farm core版本不兼容。你应该更新你的插件到最新版本来解决这个问题。

        对于插件作者来说,你应该重新用最新的 farm core 版本构建和发布插件,来让你的插件与最新的 farm core版本兼容。

        -
        备注

        Farm 承诺与相同主版本的 AP I兼容,例如,如果你的插件兼容 Farm core 1.0.0,那么它也应该兼容 Farm core 1.1.0、1.2.0等,这意味着你的插件将始终适用于相同的 Farm 主版本。

        -

        交叉构建

        +
        备注

        Farm 承诺与相同主版本的 AP I兼容,例如,如果你的插件兼容 Farm core 1.0.0,那么它也应该兼容 Farm core 1.1.0、1.2.0等,这意味着你的插件将始终适用于相同的 Farm 主版本。

        +

        交叉构建

        一个 Farm Rust 插件是一个特定于平台的动态链接库,你应该为你想要支持的所有平台构建插件。 Farm 提供了一个使用 github actions 构建插件的示例,请参阅.github/workflows/build.yml

        默认情况下,farm rust 插件应该针对以下平台构建:

        @@ -126,8 +126,8 @@

        交叉构建win32-arm64-msvc

      对于公开发布到 npm registry 的插件,建议发布支持上面所有平台的插件。对于私有 rust 插件,你可以为任何你想支持的平台构建插件。

      -
      提示

      因为 rust 插件是一个纯动态链接库,如果您有关于如何为特定平台构建插件的问题,只需谷歌如何在 rust 中为该平台构建动态链接库。

      -

      发布

      +
      提示

      因为 rust 插件是一个纯动态链接库,如果您有关于如何为特定平台构建插件的问题,只需谷歌如何在 rust 中为该平台构建动态链接库。

      +

      发布

      发布 Rust插件的有以下的步骤:

      1. 交叉构建动态链接库的 Rust 插件,详情请参阅交叉构建
      2. @@ -136,25 +136,25 @@

        发布github actions publish workflow

        -

        例子

        +

        例子

        我们将使用 @farmfe/plugin-sass 作为一个真正的 Rust 插件示例。这个插件将支持在你的项目中编译.scss.sass 文件

        -

        定义一个插件

        +

        定义一个插件

        导出一个名为 FarmPluginSass 的 Rust struct

        -
        src/lib.rs
        use farmfe_macro_plugin::farm_plugin;

        // 1. define a struct with #[farm_plugin] attribute
        #[farm_plugin]
        pub struct FarmPluginSass {
        sass_options: String,
        regex: Regex,
        }

        impl FarmPluginSass {
        // 2. define a new method with 2 arguments
        pub fn new(_config: &Config, options: String) -> Self {
        Self {
        sass_options: options,
        regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
        }
        }
        }
        +
        src/lib.rs
        use farmfe_macro_plugin::farm_plugin;

        // 1. define a struct with #[farm_plugin] attribute
        #[farm_plugin]
        pub struct FarmPluginSass {
        sass_options: String,
        regex: Regex,
        }

        impl FarmPluginSass {
        // 2. define a new method with 2 arguments
        pub fn new(_config: &Config, options: String) -> Self {
        Self {
        sass_options: options,
        regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
        }
        }
        }
        • struct 必须是pub并且必须有 #[farm_plugin] 属性。
        • 结构体必须导出一个new方法,该方法接受两个参数作为初始化参数,第一个参数是&Config,第二个参数是String
        -

        实现插件 Trait

        +

        实现插件 Trait

        Plugin trait 用于定义可以挂接到 farm compiler 的 hooks

        -
        use farmfe_core::plugin::Plugin;
        use farmfe_macro_plugin::farm_plugin;

        // 1. define a struct with #[farm_plugin] attribute
        #[farm_plugin]
        pub struct FarmPluginSass {
        sass_options: String,
        regex: Regex,
        }

        impl FarmPluginSass {
        // 2. define a new method with 2 arguments
        pub fn new(_config: &Config, options: String) -> Self {
        Self {
        sass_options: options,
        regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
        }
        }
        }
        // Implement Plugin Trait
        impl Plugin for FarmPluginSass {
        fn name(&self) -> &str {
        "FarmPluginSass"
        }

        // this plugin should be executed before internal plugins
        fn priority(&self) -> i32 {
        101
        }
        }
        -

        加载 .scss 文件

        +
        use farmfe_core::plugin::Plugin;
        use farmfe_macro_plugin::farm_plugin;

        // 1. define a struct with #[farm_plugin] attribute
        #[farm_plugin]
        pub struct FarmPluginSass {
        sass_options: String,
        regex: Regex,
        }

        impl FarmPluginSass {
        // 2. define a new method with 2 arguments
        pub fn new(_config: &Config, options: String) -> Self {
        Self {
        sass_options: options,
        regex: Regex::new(r#"\.(sass|scss)$"#).unwrap(),
        }
        }
        }
        // Implement Plugin Trait
        impl Plugin for FarmPluginSass {
        fn name(&self) -> &str {
        "FarmPluginSass"
        }

        // this plugin should be executed before internal plugins
        fn priority(&self) -> i32 {
        101
        }
        }
        +

        加载 .scss 文件

        实现 load 钩子以支持加载 .scss 文件

        -
        // ignore other code ...

        // Implement Plugin Trait
        impl Plugin for FarmPluginSass {
        fn name(&self) -> &str {
        "FarmPluginSass"
        }

        // this plugin should be executed before internal plugins
        fn priority(&self) -> i32 {
        101
        }

        fn load(
        &self,
        param: &farmfe_core::plugin::PluginLoadHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
        if param.query.is_empty() && self.regex.is_match(param.resolved_path) {
        let content = fs::read_file_utf8(param.resolved_path);

        if let Ok(content) = content {
        return Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
        content,
        module_type: ModuleType::Custom(String::from("sass")),
        }));
        }
        }

        Ok(None)
        }
        }
        +
        // ignore other code ...

        // Implement Plugin Trait
        impl Plugin for FarmPluginSass {
        fn name(&self) -> &str {
        "FarmPluginSass"
        }

        // this plugin should be executed before internal plugins
        fn priority(&self) -> i32 {
        101
        }

        fn load(
        &self,
        param: &farmfe_core::plugin::PluginLoadHookParam,
        _context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        _hook_context: &farmfe_core::plugin::PluginHookContext,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginLoadHookResult>> {
        if param.query.is_empty() && self.regex.is_match(param.resolved_path) {
        let content = fs::read_file_utf8(param.resolved_path);

        if let Ok(content) = content {
        return Ok(Some(farmfe_core::plugin::PluginLoadHookResult {
        content,
        module_type: ModuleType::Custom(String::from("sass")),
        }));
        }
        }

        Ok(None)
        }
        }

        load 钩子中,我们只读取以.scss 或者 .sass结尾的文件,返回文件内容并将其 module_type 设置为ModuleType::Custom(String::from("sass"))

        -

        转化 sass 文件

        +

        转化 sass 文件

        加载 .scss 文件之后,我们需要在 transform hook 中将其转换为 css,然后 Farm 将在接下来的过程中将其视为 css

        -
        // ignore other code ...
        fn transform(
        &self,
        param: &farmfe_core::plugin::PluginTransformHookParam,
        context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
        ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
        // module type guard is neccessary
        if param.module_type == ModuleType::Custom(String::from("sass")) {
        // ... ignore other code

        // parse options
        const options = parse_options(&self.options, param.module_id);
        // compile sass to css
        let compile_result = compileSass(&param.content, options);

        return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
        content: compile_result.css,
        source_map: compile_result.source_map,
        // tell farm compiler that we have transformed this module to css
        module_type: Some(farmfe_core::module::ModuleType::Css),
        ignore_previous_source_map: false,
        }));
        }

        Ok(None)
        }
        -
        提示

        这个例子只介绍了如何实现转换器。有关 Farm 支持的更多能力,请参阅插件钩子

    +
    // ignore other code ...
    fn transform(
    &self,
    param: &farmfe_core::plugin::PluginTransformHookParam,
    context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
    ) -> farmfe_core::error::Result<Option<farmfe_core::plugin::PluginTransformHookResult>> {
    // module type guard is neccessary
    if param.module_type == ModuleType::Custom(String::from("sass")) {
    // ... ignore other code

    // parse options
    const options = parse_options(&self.options, param.module_id);
    // compile sass to css
    let compile_result = compileSass(&param.content, options);

    return Ok(Some(farmfe_core::plugin::PluginTransformHookResult {
    content: compile_result.css,
    source_map: compile_result.source_map,
    // tell farm compiler that we have transformed this module to css
    module_type: Some(farmfe_core::module::ModuleType::Css),
    ignore_previous_source_map: false,
    }));
    }

    Ok(None)
    }
    +
    提示

    这个例子只介绍了如何实现转换器。有关 Farm 支持的更多能力,请参阅插件钩子

    \ No newline at end of file diff --git a/zh/docs/quick-start/index.html b/zh/docs/quick-start/index.html index 3e7fcb9d6..7d9870229 100644 --- a/zh/docs/quick-start/index.html +++ b/zh/docs/quick-start/index.html @@ -8,38 +8,38 @@ - - - + + + -
    版本:1.0.0

    快速开始

    -
    备注

    Farm 需要 Node 16.18.0 及更高版本

    -

    在线体验

    -

    Edit Farm

    -

    1. 创建一个 Farm 项目

    -
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    -
    然后按照提示操作!

    您还可以通过附加命令行选项直接指定项目名称和要使用的模板:

    -
    npm
    yarn
    pnpm
    bun
    npm create farm my-react-app --template react
    -

    2.启动项目

    +
    版本:1.0.0

    快速开始

    +
    备注

    Farm 需要 Node 16.18.0 及更高版本

    +

    在线体验

    +

    Edit Farm

    +

    1. 创建一个 Farm 项目

    +
    npm
    yarn
    pnpm
    bun
    npm create farm@latest
    +
    然后按照提示操作!

    您还可以通过附加命令行选项直接指定项目名称和要使用的模板:

    +
    npm
    yarn
    pnpm
    bun
    npm create farm my-react-app --template react
    +

    2.启动项目

    选择您喜欢的包管理器,安装依赖项,然后启动项目。

    -
    npm
    yarn
    pnpm
    bun
    cd farm-project && npm i && npm start
    +
    npm
    yarn
    pnpm
    bun
    cd farm-project && npm i && npm start

    默认情况下,该项目将从http://localhost:9000启动。

    -

    3. 配置项目

    +

    3. 配置项目

    该项目由项目根目录中的“farm.config.ts/js/mjs”文件进行配置。

    -
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // 编译相关配置
    compilation: {
    input: {
    // 可以配置相对或者绝对路径
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Dev Server 相关配置
    server: {
    port: 9000,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    -
    备注

    配置详情请参阅 配置 Farm

    -

    4. 构建项目

    +
    farm.config.ts
    import { defineConfig } from "@farmfe/core";

    export default defineConfig({
    // 编译相关配置
    compilation: {
    input: {
    // 可以配置相对或者绝对路径
    index: "./index.html",
    },
    output: {
    path: "./build",
    publicPath: "/",
    },
    // ...
    },
    // Dev Server 相关配置
    server: {
    port: 9000,
    // ...
    },
    // 插件配置
    plugins: [],
    });
    +
    备注

    配置详情请参阅 配置 Farm

    +

    4. 构建项目

    将 Farm 项目构建为生产环境可用的静态文件:

    -
    npm run build
    +
    npm run build

    构建的产品默认降级为ES2017,并且产品将被压缩和Tree Shake。 如果您想在本地预览构建产品,可以执行npm run Previewnpx farm Preview

    -

    下一步

    +

    下一步

    -
    +
    \ No newline at end of file diff --git a/zh/docs/tutorials/build/index.html b/zh/docs/tutorials/build/index.html index dfc2f54d7..9677d406e 100644 --- a/zh/docs/tutorials/build/index.html +++ b/zh/docs/tutorials/build/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:1.0.0

    3. 使用 Farm 构建生产项目

    +
    版本:1.0.0

    3. 使用 Farm 构建生产项目

    默认情况下,Farm 已启用对生产版本的以下功能的支持:

    • Tree Shake:裁剪和过滤不相关的模块和代码
    • @@ -21,23 +21,23 @@
    • 自动注入Polyfill:默认情况下 Farm 降级到现代浏览器(ES7),如果需要旧版浏览器支持,请配置targetEnv
    • 自动局部打包:根据依赖关系和大小,对项目进行局部打包。 对于每个资源请求,会生成大约25个资源,以保证并行加载性能,并尽可能提高缓存命中率。
    -

    配置输出目录

    +

    配置输出目录

    package.json 中添加构建脚本:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build",
    "preview": "farm preview"
    },
    // ...ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start",
    "build": "farm build",
    "preview": "farm preview"
    },
    // ...ignore other fields
    }

    然后执行npm run build,构建的资源将被生成到build目录

    -
    build
    ├─ favicon.ico
    ├─ index.html
    ├─ index_02bc.bd68e90b.js
    ├─ index_02bc.bd68e90b.js.map
    ├─ index_1c74.4b50f73e.js
    ├─ index_7734.440d56a3.js
    ├─ index_880b.4631ecee.js
    ├─ index_8d49.63f7b906.css
    ├─ index_8d49.63f7b906.css.map
    ├─ index_9025.84e1f8e6.js
    ├─ index_ca37.f2c276ef.js
    ├─ index_ef2f.e25349d8.js
    ├─ index_f346.369a7312.js
    +
    build
    ├─ favicon.ico
    ├─ index.html
    ├─ index_02bc.bd68e90b.js
    ├─ index_02bc.bd68e90b.js.map
    ├─ index_1c74.4b50f73e.js
    ├─ index_7734.440d56a3.js
    ├─ index_880b.4631ecee.js
    ├─ index_8d49.63f7b906.css
    ├─ index_8d49.63f7b906.css.map
    ├─ index_9025.84e1f8e6.js
    ├─ index_ca37.f2c276ef.js
    ├─ index_ef2f.e25349d8.js
    ├─ index_f346.369a7312.js

    如果您想自定义资源生成的路径,您可以使用:

    -
    import defineConfig from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    path: 'build',
    filename: 'assets/[name].[hash].[ext]',
    assetsFilename: 'static/[resourceName].[ext]'
    }
    }
    })
    +
    import defineConfig from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    path: 'build',
    filename: 'assets/[name].[hash].[ext]',
    assetsFilename: 'static/[resourceName].[ext]'
    }
    }
    })

    对于上面的示例,所有js/css将被发送到build/assets/(例如:build/assets/index-ea54.abbe3e.js)。 所有静态资源(例如图像)都将发送到build/static(例如:build/static/background.png

    -

    预览构建的资源

    +

    预览构建的资源

    资源构建完成后,您可以通过npm run Preview进行预览:

    -
    $ npm run preview

    > 3-build@1.0.0 preview
    > farm preview

    [ Farm ] Using config file at /root/tutorials/3-build-for-production/farm.config.ts
    [ Farm ] preview server running at:

    [ Farm ] > Local: http://localhost:1911/
    [ Farm ] > Network: http://198.18.0.1:1911/
    [ Farm ] > Network: http://10.242.197.146:1911/
    [ Farm ] > Network: http://192.168.1.31:1911/
    +
    $ npm run preview

    > 3-build@1.0.0 preview
    > farm preview

    [ Farm ] Using config file at /root/tutorials/3-build-for-production/farm.config.ts
    [ Farm ] preview server running at:

    [ Farm ] > Local: http://localhost:1911/
    [ Farm ] > Network: http://198.18.0.1:1911/
    [ Farm ] > Network: http://10.242.197.146:1911/
    [ Farm ] > Network: http://192.168.1.31:1911/

    打开http://localhost:1911/来预览项目。

    -

    浏览器兼容性

    +

    浏览器兼容性

    默认情况下,Farm 将项目构建到本机支持async/await的现代浏览器:

    • Chrome >= 62
    • @@ -46,22 +46,22 @@

      浏览器
    • Edge >= 79

    可以使用 output.targetEnv 来配置目标浏览器:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    targetEnv: 'browser-legacy'
    }
    }
    })
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    compilation: {
    output: {
    targetEnv: 'browser-legacy'
    }
    }
    })

    在上面的例子中,Farm 会将语法降级为 es5 并自动注入 polyfill。 然后我们必须安装core-js@3来进行polyfill注入:

    -
    pnpm add -D core-js@3
    -
    备注
      +
      pnpm add -D core-js@3
      +
      备注
      • 如果您的目标是旧版浏览器,则需要手动安装 core-js@3
      • 如果你想更精确地配置浏览器目标,请参阅语法 Downgrade 和 Polyfill
      -

      配置 Tree Shake 和 Minify

      +

      配置 Tree Shake 和 Minify

      出于性能原因,像treeShakeminify这样的生产优化在development中默认被禁用,而在生产中默认被启用。 但如果手动配置了treeShakeminify,则无论developmentproductive都将使用默认值。

      有关 Tree Shake 和 Minify 的详细信息,请参阅:

      -

      配置局部打包策略

      -
      备注

      详细信息参考局部打包

      -

      Farm 已经启用了打包的最佳实践,请确保您确实需要手动配置打包策略,参考局部打包 了解详情。

    +

    配置局部打包策略

    +
    备注

    详细信息参考局部打包

    +

    Farm 已经启用了打包的最佳实践,请确保您确实需要手动配置打包策略,参考局部打包 了解详情。

    \ No newline at end of file diff --git a/zh/docs/tutorials/create/index.html b/zh/docs/tutorials/create/index.html index 77b5580ec..d688fe444 100644 --- a/zh/docs/tutorials/create/index.html +++ b/zh/docs/tutorials/create/index.html @@ -8,34 +8,34 @@ - - - + + + -
    版本:1.0.0

    1. 创建一个项目

    +
    版本:1.0.0

    1. 创建一个项目

    在本章中,我们将从头开始创建一个新的 Farm React 项目,并以开发模式启动它。

    -
    备注

    在本教程中,我们使用 pnpm 作为默认包管理器。 本章将 从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令 pnpm create farm

    -

    创建一个 Npm 包

    +
    备注

    在本教程中,我们使用 pnpm 作为默认包管理器。 本章将 从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令 pnpm create farm

    +

    创建一个 Npm 包

    首先我们执行pnpm init来创建一个新包。

    -
    mkdir farm-react && cd farm-react && pnpm init
    +
    mkdir farm-react && cd farm-react && pnpm init

    将自动生成package.json文件。

    -

    安装依赖项

    +

    安装依赖项

    安装必要的依赖项(react 以及 react-dom:):

    -
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D
    +
    pnpm add react react-dom && pnpm add react-refresh @types/react @types/react-dom -D

    然后安装 Farm 相关依赖:

    -
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react
    +
    pnpm add -D @farmfe/cli @farmfe/core @farmfe/plugin-react

    React 项目需要 3 个包:

    • @farmfe/cli:该包提供了farm startfarm buildfarm Preview等命令,必须与@farmfe/core一起使用,不能单独使用。
    • @farmfe/core:该软件包提供编译Dev Server,为本地开发和产品构建提供所有必要的组件。 它导出CompilerDevServerWatcher,用于编译项目以开发模式服务项目监视项目的热模块替换
    • @farmfe/plugin-react:此包提供 React Jsx 编译和 React-refresh 支持。
    -

    创建 Farm 配置文件

    +

    创建 Farm 配置文件

    在项目根目录下创建一个farm.config.ts文件:

    -
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml
    +
    .
    ├── farm.config.ts
    ├── package.json
    └── pnpm-lock.yaml

    并添加以下配置:

    -
    import { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig): UserConfig {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });
    +
    import { UserConfig } from '@farmfe/core';

    function defineConfig(config: UserConfig): UserConfig {
    return config;
    }

    export default defineConfig({
    compilation: {
    input: {
    index: './src/index.html'
    },
    output: {
    path: 'build',
    publicPath: '/',
    targetEnv: 'browser'
    }
    },
    plugins: [
    '@farmfe/plugin-react',
    ]
    });

    对于上面的配置文件,我们使用了inputoutputplugins,这是Farm中最基本的配置。

    • input:配置入口点。 Farm 将根据条目编译并构建模块图。
    • @@ -43,20 +43,20 @@

    • plugins:配置farm插件,React、Vue SFC等所有扩展能力均由插件支持。 这里我们使用一个 Rust 插件(@farmfe/plugin-react)来支持编译 React jsx。

    查阅配置参考以获取更多选项。

    -
    备注

    在上面的例子中,我们将 input 配置为 index: './src/index.html',如果我们不配置 input,则默认为 index: './index.html'。 并且我们可以在input中配置多个条目,详细信息请参见多页面应用

    -

    创建一个入口Html和Js

    +
    备注

    在上面的例子中,我们将 input 配置为 index: './src/index.html',如果我们不配置 input,则默认为 index: './index.html'。 并且我们可以在input中配置多个条目,详细信息请参见多页面应用

    +

    创建一个入口Html和Js

    在项目根目录下创建 2 个文件 src/index.htmlsrc/index.tsx

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    └── index.tsx

    src/index.html 的内容是:

    -
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    -
    备注

    请注意,我们必须添加至少一个<script>来引用脚本模块。

    +
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="root"></div>
    <!-- we must use script to make ./index.tsx as a dependency -->
    <script src="./index.tsx"></script>
    </body>
    </html>
    +
    备注

    请注意,我们必须添加至少一个<script>来引用脚本模块。

    src/index.tsx 的内容是:

    -
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    -

    启动 Farm 项目!

    +
    src/index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(<div>A React Page compiled by Farm</div>);
    +

    启动 Farm 项目!

    现在一切都准备好了,将启动脚本添加到您的package.json中:

    -
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }
    +
    package.json
    {
    "name": "1-create-a-project",
    "version": "1.0.0",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "farm start"
    },
    // ... ignore other fields
    }

    然后运行npm start,如果 Farm 输出以下消息,则意味着您的项目已成功启动:

    -
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    -

    在浏览器中打开http://localhost:9000

    +
    $ npm start

    > 1-create-a-project@1.0.0 start
    > farm start

    [ Farm ] Using config file at /home/tutorials/1-create-a-project/farm.config.ts

    ϟ Farm v0.16.0
    ✓ Ready in 20ms ⚡️ FULL EXTREME !

    [ Farm ] > Local: http://localhost:9000/
    [ Farm ] > Network: http://192.168.1.3:9000/
    +

    在浏览器中打开http://localhost:9000

    \ No newline at end of file diff --git a/zh/docs/tutorials/overview/index.html b/zh/docs/tutorials/overview/index.html index 70b7dadf8..9e314f062 100644 --- a/zh/docs/tutorials/overview/index.html +++ b/zh/docs/tutorials/overview/index.html @@ -8,14 +8,14 @@ - - - + + + -
    版本:1.0.0

    概述

    +
    版本:1.0.0

    概述

    在本教程中,我们将从头开始创建一个 Farm React 项目,并介绍如何添加有用的组件库和 Farm 插件。

    -
    备注

    Vue项目也得到了Farm的全力支持。 Farm中可以直接使用Vite@vitejs/plugin-vue。 Farm 与大多数 vite 插件兼容,并且可以开箱即用。

    +
    备注

    Vue项目也得到了Farm的全力支持。 Farm中可以直接使用Vite@vitejs/plugin-vue。 Farm 与大多数 vite 插件兼容,并且可以开箱即用。

    你将学习:

    • 如何从头开始构建一个生产就绪的 Farm React 项目。 我们将介绍配置常用插件、添加常见组件库等。
    • @@ -23,13 +23,13 @@
    • Farm的日常配置和常用插件。

    我们的目标是通过本教程简化您使用 Farm 生态系统的开发体验。 如果您想从其他工具迁移到 Farm,它也会很有帮助。

    -
    备注

    本教程将 从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令 pnpm create farm

    +
    备注

    本教程将 从头开始构建 Farm React 项目,如果您想快速启动一个新的 Farm 项目,请使用我们的官方模板和命令 pnpm create farm

    跟着我们的教程,开启你的 Farm 极速开发之旅吧!

    -
    备注

    本教程的源代码在Farm 教程仓库

    +
    备注

    本教程的源代码在Farm 教程仓库

    \ No newline at end of file diff --git a/zh/docs/tutorials/start/index.html b/zh/docs/tutorials/start/index.html index 6bc271217..dfc7e6477 100644 --- a/zh/docs/tutorials/start/index.html +++ b/zh/docs/tutorials/start/index.html @@ -8,93 +8,93 @@ - - - + + + -
    版本:1.0.0

    2. 使用 Farm 开发项目

    +
    版本:1.0.0

    2. 使用 Farm 开发项目

    在本章中,我们将介绍常用的配置和插件来帮助您使用 Farm 构建复杂的生产就绪的 Web 项目。

    -
    备注

    本章重用我们在第 1 章中创建的项目

    +
    备注

    本章重用我们在第 1 章中创建的项目

    我们将逐步设置我们的项目: 1.引入流行的组件库antd,并为其配置必要的插件 2.介绍postcss、svgr、less等常用插件。 3. 配置代理和其他有用的开发服务器选项

    -

    引入组件库

    +

    引入组件库

    开发 Web 项目时常常需要用到组件库,本节我们将使用ant-design作为 demo 来展示如何在 Farm 中添加组件库。

    我们这里使用ant design只是为了说明,你可以引入任何组件库。 对于组件库选择,Farm 没有任何倾向。

    首先我们需要将 ant-design 安装到我们的项目中:

    -
    pnpm add antd # 在项目根目录下执行
    +
    pnpm add antd # 在项目根目录下执行

    Ant Design需要Sass,所以我们还需要安装编译 scss 的插件。 我们可以使用 Farm 官方提供的 Rust 插件 @farmfe/plugin-sass

    -
    pnpm add @farmfe/plugin-sass -D
    +
    pnpm add @farmfe/plugin-sass -D

    然后将此插件添加到plugins中:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ]
    });
    +
    farm.config.ts
    // ...

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass'
    ]
    });

    现在 Antd 已经准备好了,将其添加到我们的项目中:

    -
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    antd DatePicker: <DatePicker />
    </div>
    );
    +
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    antd DatePicker: <DatePicker />
    </div>
    );

    然后执行npm start并在浏览器中打开http://localhost:9000

     

    -

    给项目添加 CSS 样式

    +

    给项目添加 CSS 样式

    现在我们已经成功地将组件库引入到我们的项目中。 接下来我们将学习如何给项目添加样式。

    -

    创建基本的管理站点布局

    +

    创建基本的管理站点布局

    首先,我们在index.tsx旁边创建一个新的app.tsx

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    └── index.tsx

    app.tsx的内容(来自Antd官网的演示代码):

    -
    app.tsx
    import React from 'react';
    import { Breadcrumb, Layout, Menu, theme } from 'antd';

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: 'flex', alignItems: 'center' }}>
    <div className="demo-logo" />
    <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: '0 50px' }}>
    <Breadcrumb style={{ margin: '16px 0' }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div className="site-layout-content" style={{ background: colorBgContainer }}>
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
    </Layout>
    );
    };

    export default App;
    +
    app.tsx
    import React from 'react';
    import { Breadcrumb, Layout, Menu, theme } from 'antd';

    const { Header, Content, Footer } = Layout;

    const App: React.FC = () => {
    const {
    token: { colorBgContainer },
    } = theme.useToken();

    return (
    <Layout className="layout">
    <Header style={{ display: 'flex', alignItems: 'center' }}>
    <div className="demo-logo" />
    <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}
    items={new Array(15).fill(null).map((_, index) => {
    const key = index + 1;
    return {
    key,
    label: `nav ${key}`,
    };
    })}
    />
    </Header>
    <Content style={{ padding: '0 50px' }}>
    <Breadcrumb style={{ margin: '16px 0' }}>
    <Breadcrumb.Item>Home</Breadcrumb.Item>
    <Breadcrumb.Item>List</Breadcrumb.Item>
    <Breadcrumb.Item>App</Breadcrumb.Item>
    </Breadcrumb>
    <div className="site-layout-content" style={{ background: colorBgContainer }}>
    Content
    </div>
    </Content>
    <Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
    </Layout>
    );
    };

    export default App;

    然后将 index.tsx 修改为:

    -
    index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import App from './app';
    // import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );

    +
    index.tsx
    import React from 'react';
    import { createRoot } from 'react-dom/client';

    import App from './app';
    // import { DatePicker } from 'antd';

    const container = document.querySelector('#root');
    const root = createRoot(container);

    root.render(
    <div>
    A React Page compiled by Farm.
    <App />
    {/* antd DatePicker: <DatePicker /> */}
    </div>
    );

    然后我们得到一个基本的管理站点布局:

    -

    使用 CSS Modules

    +

    使用 CSS Modules

    Farm 开箱即用地支持css modules,默认情况下,Farm 会将任何.module.(css|scss|less)视为css 模块。 首先我们创建一个app.module.scss

    -
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx
    +
    .
    ├── farm.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    └── src
    ├── index.html
    ├── app.tsx
    ├── app.module.scss
    └── index.tsx

    Content of app.module.scss:

    -
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }
    +
    app.module.scss
    $primary-color: #1890ff;

    .site-layout-content {
    min-height: 200px;
    padding: 24px;
    font-size: 24px;
    color: $primary-color;
    }

    然后在app.tsx中导入app.module.scss并保存:

    -
    import styles from './app.module.scss';
    // ...
    +
    import styles from './app.module.scss';
    // ...

    然后你的页面应该更新成如下:

    -

    使用 CSS 预处理器

    +

    使用 CSS 预处理器

    Farm 为 postcss(@farmfe/js-plugin-postcss) 和 less(@farmfe/js-plugin-less) 提供了官方 js 插件(在上文中,我们已经安装了 sass 插件(@farmfe/plugin-sass))。

    要使用postcss,首先我们需要安装插件:

    -
    pnpm add -D @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/js-plugin-postcss

    然后在farm.config.tsplugins中配置它:

    -
    farm.config.ts
    // ...
    import farmPluginPostcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass',
    farmPluginPostcss()
    ]
    });
    +
    farm.config.ts
    // ...
    import farmPluginPostcss from '@farmfe/js-plugin-postcss';

    export default defineConfig({
    // ... ignore other fields
    plugins: [
    '@farmfe/plugin-react',
    '@farmfe/plugin-sass',
    farmPluginPostcss()
    ]
    });

    现在 Farm 完全支持 postcss,我们不会在这里介绍 postcss 细节,请参阅 postcss 文档以获取更多详细信息。

    -
    提示

    请参阅 使用 Farm 插件 了解有关 Farm 插件的更多信息。

    -

    配置 public 目录

    +
    提示

    请参阅 使用 Farm 插件 了解有关 Farm 插件的更多信息。

    +

    配置 public 目录

    对于不需要编译的资源,可以将它们放在 public 目录下。 在public下添加favicon.ico

    -
    .
    ├── ...
    └── public
    └── favicon.icon
    +
    .
    ├── ...
    └── public
    └── favicon.icon

    然后favicon即可用于您的网站。 你还可以放入一些可以直接获取的静态资源,例如图片:

    -
    .
    ├── ...
    └── public
    ├── favicon.icon
    └── images
    └── background.png
    -
    备注

    使用配置选项 publicDir 自定义您的公共目录。

    -

    配置 publicPath

    +
    .
    ├── ...
    └── public
    ├── favicon.icon
    └── images
    └── background.png
    +
    备注

    使用配置选项 publicDir 自定义您的公共目录。

    +

    配置 publicPath

    使用 compilation.output.publicPath 配置动态资源加载的 url 前缀 以及将 <script><link> 标签注入到 html 中时。 我们在 farm.config.ts 中添加以下配置:

    -
    farm.config.ts
    // ...
    export default defineConfig({
    compilation: {
    output: {
    publicPath: process.env.NODE_ENV === 'production' ? 'https://cdn.com' : '/'
    }
    }
    // ...
    });
    +
    farm.config.ts
    // ...
    export default defineConfig({
    compilation: {
    output: {
    publicPath: process.env.NODE_ENV === 'production' ? 'https://cdn.com' : '/'
    }
    }
    // ...
    });

    在构建时,注入的资源 URL 将类似 https://cdn.com/index-s2f3.s14dqwa.js。 例如,在输出 html 中,所有 <script><link> 将为:

    -
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>
    +
    <html>
    <head>
    <!-- ... -->
    <link href="https://cdn.com/index-a23e.s892s1.css" />
    </head>
    <body>
    <!-- ... -->
    <script src="https://cdn.com/index-s2f3.s14dqwa.js"></script>
    </body>
    </html>

    当加载动态脚本和CSS时,动态获取的资源url也将是:https://cdn.com/<asset-path>

    -

    配置 Alias 以及 Externals

    +

    配置 Alias 以及 Externals

    Alias 和 externals 是最常用的配置之一, 在 Farm 中,可以使用 compilation.resolve.aliascompilation.externals 配置项:

    -
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '@/': path.join(process.cwd(), 'src')
    },
    externals: [
    'node:fs'
    ]
    }
    }
    // ...
    });
    -

    配置开发服务器

    +
    farm.config.ts
    // ...

    export default defineConfig({
    compilation: {
    resolve: {
    alias: {
    '@/': path.join(process.cwd(), 'src')
    },
    externals: [
    'node:fs'
    ]
    }
    }
    // ...
    });
    +

    配置开发服务器

    您可以在Farm Dev Server Config中找到服务器配置。

    -

    常用配置

    +

    常用配置

    配置示例:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // 所有开发服务器选项都在 server 下
    server: {
    open: true,
    port: 9001,
    hmr: {
    // 配置Websocket的监听端口
    port: 9801
    host: 'localhost',
    // 配置文件监听时要忽略的文件
    ignores: ['auto_generated/*']
    }
    //...
    }
    });
    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    // 所有开发服务器选项都在 server 下
    server: {
    open: true,
    port: 9001,
    hmr: {
    // 配置Websocket的监听端口
    port: 9801
    host: 'localhost',
    // 配置文件监听时要忽略的文件
    ignores: ['auto_generated/*']
    }
    //...
    }
    });

    对于上面的示例,我们使用了以下选项:

    • 打开:自动打开指定端口的浏览器
    • 端口:将开发服务器端口设置为9001
    • hmr:设置 hmr 端口和监视文件,我们忽略 auto_generate 目录下的文件更改。
    -

    Setup Proxy

    +

    Setup Proxy

    配置服务器代理。基于 http-proxy 实现,具体选项参考其文档,示例:

    -
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });
    -

    配置 root 和 envDir

    +
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    server: {
    proxy: {
    '/api': {
    target: 'https://music-erkelost.vercel.app/banner',
    changeOrigin: true,
    pathRewrite: (path: any) => path.replace(/^\/api/, ''),
    },
    },
    },
    });
    +

    配置 root 和 envDir

    使用rootenvDir指定项目根目录和加载环境变量的目录。 在farm.config.ts中添加以下选项:

    -
    farm.config.ts
    import path from 'node:path';
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    root: path.join(process.cwd(), 'client'),
    envDir: 'my-env-dir'
    });
    -
    备注

    有关 envDir 的详细信息,请参阅环境变量和模式

    +
    farm.config.ts
    import path from 'node:path';
    import { defineConfig } from '@farmfe/core';

    export default defineConfig({
    root: path.join(process.cwd(), 'client'),
    envDir: 'my-env-dir'
    });
    +
    备注

    有关 envDir 的详细信息,请参阅环境变量和模式

    \ No newline at end of file diff --git a/zh/docs/using-plugins/index.html b/zh/docs/using-plugins/index.html index 175206b65..e89f58908 100644 --- a/zh/docs/using-plugins/index.html +++ b/zh/docs/using-plugins/index.html @@ -8,12 +8,12 @@ - - - + + + -
    版本:1.0.0

    使用插件

    +
    版本:1.0.0

    使用插件

    Farm支持4种插件:

    • Farm 编译插件:支持 Rust 插件和 Js 插件,采用 rollup 风格的 hooks。
    • @@ -21,66 +21,66 @@
    • Farm 运行时插件:为 Farm 的运行时系统添加功能。
    • Swc 插件:Farm 开箱即用支持 Swc 插件。
    -
    提示

    如何编写自己的插件,请参考插件

    -

    Farm 编译插件

    +
    提示

    如何编写自己的插件,请参考插件

    +

    Farm 编译插件

    首先,安装您需要的插件,例如:

    -
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss
    +
    pnpm add -D @farmfe/plugin-sass @farmfe/js-plugin-postcss

    使用 plugins 配置 Farm 编译插件:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust插件,配置其包名
    "@farmfe/plugin-sass",
    // JS插件,配置插件对象
    farmPostcssPlugin()
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    // ...
    plugins: [
    // Rust插件,配置其包名
    "@farmfe/plugin-sass",
    // JS插件,配置插件对象
    farmPostcssPlugin()
    ],
    });

    Farm编译插件有2种:

    • Rust Plugins:用 Rust 编写,具有最佳性能。
    • Js Plugins:用JS/TS编写,用于兼容当前的JS生态系统
    -

    使用 Rust 插件

    +

    使用 Rust 插件

    使用 package name 来配置 Rust 插件,例如:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    "@farmfe/plugin-sass",
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    "@farmfe/plugin-sass",
    ],
    });

    对于上面的例子,Farm 将解析包 @farmfe/plugin-sass 并将其视为 Farm Rust 插件。

    如果要为 Rust 插件配置选项,可以使用数组语法,如[packageName, optionsObject],例如:

    -
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // 使用数组语法来配置 Rust 插件
    [
    // Rust 插件的名称
    "@farmfe/plugin-sass",
    // Rust 插件的选项
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });
    +
    farm.config.ts
    export default defineConfig({
    // ...
    plugins: [
    // 使用数组语法来配置 Rust 插件
    [
    // Rust 插件的名称
    "@farmfe/plugin-sass",
    // Rust 插件的选项
    {
    additionalData: '@use "@/global-variables.scss";'
    }
    ],
    ],
    });

    目前 Farm 官方支持 2 个 Rust 插件:

    • @farmfe/plugin-react:Farm rust 插件,用于 React jsx 编译和 React-refresh 注入。
    • @farmfe/plugin-sass:用于 scss 文件编译的 Farm rust 插件,内部使用 sass-embedded
    -
    提示

    要了解有关 rust 插件的更多信息,请参阅 Rust 插件

    -

    使用 Js 插件

    +
    提示

    要了解有关 rust 插件的更多信息,请参阅 Rust 插件

    +

    使用 Js 插件

    Farm JS 插件是一个以方法为钩子的 JS 对象,例如:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    farmPostcssPlugin({
    // ... 配置 postcss 选项
    })
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    farmPostcssPlugin({
    // ... 配置 postcss 选项
    })
    ],
    });

    farmPostcssPlugin()返回一个插件对象,您可以通过其参数传递任何 postcss 选项。

    您可以使用priority来控制插件的顺序,例如:

    -
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });
    +
    farm.config.ts
    import farmPostcssPlugin from "@farmfe/js-plugin-postcss";

    export default defineConfig({
    plugins: [
    {
    ...farmPostcssPlugin({
    // ... configure postcss options
    }),
    // larger priority will be executed first, priority of internal plugin are 100.
    priority: 1000,
    }
    ],
    });

    内部插件的优先级都是100,如果想让插件先执行,就设置大于100,否则设置小于100。

    如果你想快速添加 Farm JS 插件,只需配置一个插件对象即可:

    -
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // 配置自定义插件
    {
    // 插件名称,必填
    name: 'my-first-farm-plugin',
    // 这个插件的优先级,值越大先执行,默认100。
    priority: 1000,
    // 定义一个加载钩子来确定如何加载模块
    load: {
    // 为了提高性能,如果模块与过滤器不匹配,将被跳过。
    filters: {
    // 仅对 .png 文件执行。
    resolvedPaths: ['\\.txt$']
    },
    // 该钩子的执行回调
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    -
    注意

    Farm 中的 js 插件需要 filters。 因为Js Plugin实在是太慢了,我们应该尽量避免执行它。配置 filters 后,对于那些不符合过滤器的模块,Farm 根本不会为它们触发 js 插件钩子! 这意味着 Farm 只在 Rust 侧就能安全、并发地进行处理,以最大化提升编译性能。

    -
    提示

    了解更多关于 Farm Js 插件的信息,请参考 JS 插件

    -

    使用 Vite/Rollup/Unplugin 插件

    +
    farm.config.ts
    import readFileSync from 'fs';

    export default defineConfig({
    plugins: [
    // 配置自定义插件
    {
    // 插件名称,必填
    name: 'my-first-farm-plugin',
    // 这个插件的优先级,值越大先执行,默认100。
    priority: 1000,
    // 定义一个加载钩子来确定如何加载模块
    load: {
    // 为了提高性能,如果模块与过滤器不匹配,将被跳过。
    filters: {
    // 仅对 .png 文件执行。
    resolvedPaths: ['\\.txt$']
    },
    // 该钩子的执行回调
    executor: (params, context) => {
    const { resolvedPath } = params;
    const content = readFileSync(resolvedPath, 'utf-8');

    return {
    content: `export default '${content}'`,
    moduleType: 'js'
    }
    }
    }
    }
    ],
    });
    +
    注意

    Farm 中的 js 插件需要 filters。 因为Js Plugin实在是太慢了,我们应该尽量避免执行它。配置 filters 后,对于那些不符合过滤器的模块,Farm 根本不会为它们触发 js 插件钩子! 这意味着 Farm 只在 Rust 侧就能安全、并发地进行处理,以最大化提升编译性能。

    +
    提示

    了解更多关于 Farm Js 插件的信息,请参考 JS 插件

    +

    使用 Vite/Rollup/Unplugin 插件

    Farm 兼容 Vite 插件,Vite 插件可以直接在 Farm 中配置使用。 首先需要安装 vite 插件,例如:

    -
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D
    +
    pnpm add @vitejs/plugin-vue @vitejs/plugin-vue-jsx vite -D

    然后就可以通过farm.config.ts中的vitePlugins直接使用vite插件了。

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // 配置vite插件
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import vueJsx from '@vitejs/plugin-vue-jsx';

    export default defineConfig({
    // 配置vite插件
    vitePlugins: [
    vue(),
    vueJsx()
    ]
    });

    为了提高 vite 插件的性能,您可以使用返回过滤器函数语法,例如:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // // 使用Farm 中 Vite 插件的函数语法
    function configureVitePluginVue() {
    // 返回插件及其过滤器
    return {
    // 使用 vue 插件
    vitePlugin: vue(),
    // 为其配置过滤器。 不匹配的模块路径将被跳过。
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    vitePlugins: [
    configureVitePluginVue
    ]
    });
    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',

    // // 使用Farm 中 Vite 插件的函数语法
    function configureVitePluginVue() {
    // 返回插件及其过滤器
    return {
    // 使用 vue 插件
    vitePlugin: vue(),
    // 为其配置过滤器。 不匹配的模块路径将被跳过。
    filters: ['\\.vue$', '\\\\0.+']
    };
    }

    export default defineConfig({
    vitePlugins: [
    configureVitePluginVue
    ]
    });

    使用 unplugin:

    -
    pnpm add unplugin-auto-import unplugin-vue-components -D
    +
    pnpm add unplugin-auto-import unplugin-vue-components -D

    vitePlugins 中配置,通过 unplugin/vite 或者 unplugin/rollup 支持:

    -
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    -
    备注

    目前,您可以在 Farm 中使用unplugin/farmunplugin/viteunplugin/rollup。如果您使用的是unplugin/viteunplugin/Rolup,有些属性可能还没有完全适配,或者 Farm 团队认为该 api 不具备适配条件,可以提供issues .

    -

    Farm 运行时插件

    +
    farm.config.ts
    import vue from '@vitejs/plugin-vue',
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

    export default defineConfig({
    vitePlugins: [
    vue(),
    // ...
    AutoImport({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    Components({
    resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
    }),
    ]
    });
    +
    备注

    目前,您可以在 Farm 中使用unplugin/farmunplugin/viteunplugin/rollup。如果您使用的是unplugin/viteunplugin/Rolup,有些属性可能还没有完全适配,或者 Farm 团队认为该 api 不具备适配条件,可以提供issues .

    +

    Farm 运行时插件

    Farm有一个运行时模块系统来控制如何加载和执行模块。 配置 compilation.runtime.plugins 以添加更多运行时插件,例如:

    -
    export default defineConfig({
    compilation: {
    // 配置 Farm 运行时模块系统
    runtime: {
    plugins: [
    // 运行时插件包
    require.resolve('farm-plugin-runtime-mock'),
    // 本地运行时插件
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });
    +
    export default defineConfig({
    compilation: {
    // 配置 Farm 运行时模块系统
    runtime: {
    plugins: [
    // 运行时插件包
    require.resolve('farm-plugin-runtime-mock'),
    // 本地运行时插件
    path.join(process.cwd(), "build/runtime-plugin.ts")
    ]
    }
    }
    });

    您必须配置指向运行时插件的路径。 推荐使用 绝对路径 以避免路径问题。

    -
    提示

    要了解有关运行时插件的更多信息,请参阅 运行时插件

    -

    使用 SWC 插件

    +
    提示

    要了解有关运行时插件的更多信息,请参阅 运行时插件

    +

    使用 SWC 插件

    Swc Plugin 也可以直接在Farm中使用,配置compilation.script.plugins来添加SWC插件,例如:

    -
    import jsPluginVue from '@farmfe/js-plugin-vue';

    export default defineConfig({
    compilation: {
    script: {
    plugins: [{
    //swc插件的包名
    name: 'swc-plugin-vue-jsx',
    // 该swc插件的选项
    options: {
    "transformOn": true,
    "optimize": true
    },
    // 当过滤器匹配时插件执行。
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    });
    +
    import jsPluginVue from '@farmfe/js-plugin-vue';

    export default defineConfig({
    compilation: {
    script: {
    plugins: [{
    //swc插件的包名
    name: 'swc-plugin-vue-jsx',
    // 该swc插件的选项
    options: {
    "transformOn": true,
    "optimize": true
    },
    // 当过滤器匹配时插件执行。
    filters: {
    // resolvedPaths: [".+"]
    moduleTypes: ['tsx', 'jsx'],
    }
    }]
    }
    },
    plugins: [jsPluginVue()],
    });

    数组的每个插件项包含三个字段:

    • name:swc插件的包名
    • options:传递给swc插件的配置项
    • filters:执行插件的哪些模块,必须配置,支持resolvedPathsmoduleTypes这两个过滤项,如果两者同时指定,则取并集。
    -
    备注

    SWC 插件可能与 Farm 使用的 SWC 版本(rust crate swc_core v0.90) 不兼容。 如果出现错误,请尝试升级插件。

    +
    备注

    SWC 插件可能与 Farm 使用的 SWC 版本(rust crate swc_core v0.90) 不兼容。 如果出现错误,请尝试升级插件。

    \ No newline at end of file diff --git a/zh/docs/why-farm/index.html b/zh/docs/why-farm/index.html index e1a7469ea..c21405b82 100644 --- a/zh/docs/why-farm/index.html +++ b/zh/docs/why-farm/index.html @@ -8,15 +8,15 @@ - - - + + + -
    版本:1.0.0

    为什么需要 Farm?

    -

    Farm 是什么?

    +
    版本:1.0.0

    为什么需要 Farm?

    +

    Farm 是什么?

    Farm 是一个非常快的基于 Rust 的 Web 构建工具,类似 webpackvite,但更快。 farm resolve, load, transform 所有 asset(js/jsx/ts/tsx、css/sass/less、html、静态资源、json 等),并将它们打包成一系列可部署文件。 Farm 是一个速度极快的构建工具,可帮助您构建更快的 web/nodejs 应用程序。

    -

    为什么需要 Farm?

    +

    为什么需要 Farm?

    随着 web 项目规模的扩大,构建性能已经成为主要瓶颈,对于一个庞大的项目,使用 webpack 编译可能需要 10min 甚至更多,一次 hmr 更新可能需要 10s 甚至更多,严重降低了研发效率。

    因此我们急需极速的构建工具,解决项目编译性能问题。然后 vite/snowpack 这样的 unbundled 工具应运而生,此类工具主要有下面三个特性:

      @@ -33,7 +33,7 @@

      事实上,我们真正需要的是一个快速、强大、一致的 Web 构建工具,可以在解决上述问题的基础上,提供更加极致的编译效率。因此我们设计并开发了 Farm。

      不过 Farm 不仅仅是一个用 Rust 重写的打包工具,它还有很多强大且先进的设计:

      -

      Farm 设计理念

      +

      Farm 设计理念

      • 性能优先:一切都会用 Rust 编写,只有少数不是性能瓶颈的部分会用 JS 编写
      • 一致性:默认情况下确保开发和生产完全相同,您在开发中看到的将与您在生产中得到的相同。
      • @@ -42,6 +42,6 @@

        Farm 设
      • 兼容性:Farm 将适用于旧版 (ES5) 和现代浏览器。
      • Rollup 风格的插件系统:轻松创建自己的插件,并轻松从 rollup/vite/webpack 迁移您的插件/项目。兼容 Vite/Rollup/Unplugin 插件
      -

      Farm 的目标是成为真正的下一代构建工具,快速、强大、一致,并为 Web 开发人员提供最佳的开发体验。

    +

    Farm 的目标是成为真正的下一代构建工具,快速、强大、一致,并为 Web 开发人员提供最佳的开发体验。

    \ No newline at end of file diff --git a/zh/index.html b/zh/index.html index 51d3b31d8..ebe6034d5 100644 --- a/zh/index.html +++ b/zh/index.html @@ -8,11 +8,11 @@ - - - + + + -
    ⭐️
    Give Star with Farm Github

    极速Web
    使用

    是一个基于 Rust 实现的极速构建引擎,帮助您更快地构建 Web 程序 和 JavaScript 库。

    超级快

    用Rust编写,可以在毫秒内启动React/Vue项目,并在大多数情况下在10毫秒内进行热模块替换(HMR)更新。

    增量构建

    增量构建:默认启用, 支持持久缓存,模块级别缓存,任何模块在未发生变化之前不会被重新编译!

    丰富的特性

    丰富的编译能力支持: 开箱即用, Farm 内置了 Js/Ts/Jsx/Tsx、Css/Css Modules/Sass/Less、HTML 和静态资源,可以通过官方插件支持 sass、less、postcss、react、vue、solid 等常用技术栈,支持懒编译、局部打包等海量特性。

    完全可插拔 & 兼容 Vite 生态

    Farm 由插件驱动, 通过创建插件来实现任何您想要的功能, 同时支持 Rust 和 JavaScript 两种插件模式, 开箱即用支持 Vite 插件。

    局部打包

    自动根据依赖关系、资源大小,将项目打包成若干个资源,提升资源加载性能的同时,保证缓存命中率。

    一致性 & 兼容性

    一致性: 开发环境和生产环境的表现一致,所见即所得。支持传统(ES5)和现代浏览器。

    +
    ⭐️
    Give Star with Farm Github

    极速Web
    使用

    是一个基于 Rust 实现的极速构建引擎,帮助您更快地构建 Web 程序 和 JavaScript 库。

    超级快

    用Rust编写,可以在毫秒内启动React/Vue项目,并在大多数情况下在10毫秒内进行热模块替换(HMR)更新。

    增量构建

    增量构建:默认启用, 支持持久缓存,模块级别缓存,任何模块在未发生变化之前不会被重新编译!

    丰富的特性

    Farm supports compiling HTML, CSS, CSS Modules, Js/Jsx/Ts/Tsx, JSON, Static Assets out of the box, supports Sass, Less, PostCSS, Vue, React, Solid by way of official plugins, supports lazy compiling, partial bundling and more

    完全可插拔 & 兼容 Vite 生态

    Farm 由插件驱动, 通过创建插件来实现任何您想要的功能, 同时支持 Rust 和 JavaScript 两种插件模式, 开箱即用支持 Vite 插件。

    局部打包

    自动根据依赖关系、资源大小,将项目打包成若干个资源,提升资源加载性能的同时,保证缓存命中率。

    一致性 & 兼容性

    一致性: 开发环境和生产环境的表现一致,所见即所得。支持传统(ES5)和现代浏览器。

    \ No newline at end of file diff --git a/zh/markdown-page/index.html b/zh/markdown-page/index.html index 9747c44a5..a30f5c8af 100644 --- a/zh/markdown-page/index.html +++ b/zh/markdown-page/index.html @@ -8,12 +8,12 @@ - - - + + + -

    Markdown page example

    +

    Markdown page example

    You don't need React to write simple standalone pages.

    \ No newline at end of file diff --git a/zh/search/index.html b/zh/search/index.html index 294d117ff..707473f99 100644 --- a/zh/search/index.html +++ b/zh/search/index.html @@ -8,11 +8,11 @@ - - - + + + - + \ No newline at end of file diff --git a/zh/team/index.html b/zh/team/index.html index d34f4425c..4b3d23784 100644 --- a/zh/team/index.html +++ b/zh/team/index.html @@ -8,11 +8,11 @@ - - - + + + -
    brightwu

    brightwu

    @bytedance

    Author/Lead Maintainer of @farm-fe. Rust && TS && Java..

    Erkelost

    Erkelost

    Rust & Go & Node & Web development ❤️❤️

    shulandmimi

    shulandmimi

    Core team member of Farm.

    Nirvana-Jie

    Nirvana-Jie

    @bytedance

    There are too many things to learn, I can only keep moving forward.

    NidMo

    NidMo

    Core team member of Farm.

    wjq990112

    wjq990112

    Member of @raxjs, @ice-lab and @farm-fe.

    callqh

    callqh

    Javascript & Rust.

    oblador

    oblador

    ╥━━━━━━━━╭━━╮━━┳ ╢╭╮╭━━━━━┫┃▋▋━▅┣ ╢┃╰┫┈┈┈┈┈┃┃┈┈╰┫┣ ╢╰━┫┈┈┈┈┈╰╯╰┳━╯┣ ╢┊┊┃┏┳┳━━┓┏┳┫┊┊┣ ╨━━┗┛┗┛━━┗┛┗┛━━┻

    ysy945

    ysy945

    Core team member of Farm.

    NaturelLee

    NaturelLee

    Core team member of Farm.

    Cherry7

    Cherry7

    @bytedance

    Core team member of Farm & Ant Design Vue.

    +
    brightwu

    brightwu

    @bytedance

    Author/Lead Maintainer of @farm-fe. Rust && TS && Java..

    Erkelost

    Erkelost

    Rust & Go & Node & Web development ❤️❤️

    shulandmimi

    shulandmimi

    Core team member of Farm.

    Nirvana-Jie

    Nirvana-Jie

    @bytedance

    There are too many things to learn, I can only keep moving forward.

    NidMo

    NidMo

    Core team member of Farm.

    wjq990112

    wjq990112

    Member of @raxjs, @ice-lab and @farm-fe.

    callqh

    callqh

    Javascript & Rust.

    oblador

    oblador

    ╥━━━━━━━━╭━━╮━━┳ ╢╭╮╭━━━━━┫┃▋▋━▅┣ ╢┃╰┫┈┈┈┈┈┃┃┈┈╰┫┣ ╢╰━┫┈┈┈┈┈╰╯╰┳━╯┣ ╢┊┊┃┏┳┳━━┓┏┳┫┊┊┣ ╨━━┗┛┗┛━━┗┛┗┛━━┻

    ysy945

    ysy945

    Core team member of Farm.

    NaturelLee

    NaturelLee

    Core team member of Farm.

    Cherry7

    Cherry7

    @bytedance

    Core team member of Farm & Ant Design Vue.

    \ No newline at end of file