PageSourceSearch

https://www.electronjs.org/assets/js/6dde4314.36bab8ad.js

js electronjs.org collected 2026-09-24 07:03:51 UTC 20,057 bytes, 2 lines download raw bytes

1"use strict";(self.webpackChunkelectronjs=self.webpackChunkelectronjs||[]).push([["22957"],{27770(e,t,n){n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>c,default:()=>p,frontMatter:()=>s,metadata:()=>r,toc:()=>h});var r=n(4533),o=n(74848),i=n(28453),a=n(50773),l=n(57250);let s={title:"Introducing Electron Forge 6",date:new Date("2022-11-03T00:00:00.000Z"),authors:["georgexu99","VerteDinde","erickzhao"],slug:"forge-v6-release",toc_max_heading_level:3,tags:["ecosystem"]},c,d={authorsImageUrls:[void 0,void 0,void 0]},h=[{value:"What is Electron Forge?",id:"what-is-electron-forge",level:2},{value:"What's new in v6?",id:"whats-new-in-v6",level:2},{value:"Completely rewritten",id:"completely-rewritten",level:3},{value:"Officially supported",id:"officially-supported",level:3},{value:"Getting started",id:"getting-started",level:2},{value:"Initializing a new Forge project",id:"initializing-a-new-forge-project",level:3},{value:"Importing an existing project",id:"importing-an-existing-project",level:3},{value:"Why switch to Forge?",id:"why-switch-to-forge",level:2},{value:"Breaking changes",id:"breaking-changes",level:2},{value:"Submit your feedback!",id:"submit-your-feedback",level:2}];function u(e){let t={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)(t.p,{children:["We are excited to announce that Electron Forge v6.0.0 is now available! This release marks the first major release of Forge since 2018 and moves the project from ",(0,o.jsx)(t.code,{children:"electron-userland"})," into the main ",(0,o.jsx)(t.code,{children:"electron"})," organization on Github."]}),"\n",(0,o.jsx)(t.p,{children:"Keep on reading to see what's new and how your app can adopt Electron Forge!"}),"\n",(0,o.jsx)(t.h2,{id:"what-is-electron-forge",children:"What is Electron Forge?"}),"\n",(0,o.jsxs)(t.p,{children:[(0,o.jsx)(t.a,{href:"https://electronforge.io",children:"Electron Forge"})," is a tool for packaging and distributing Electron applications. It unifies Electron's build tooling ecosystem into a single extensible interface so that anyone can jump right into making Electron apps."]}),"\n",(0,o.jsx)(t.p,{children:"Highlight features include:"}),"\n",(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsx)(t.li,{children:"\u{1F4E6} Application packaging and code signing"}),"\n",(0,o.jsx)(t.li,{children:"\u{1F69A} Customizable installers on Windows, macOS, and Linux (DMG, deb, MSI, PKG, AppX, etc.)"}),"\n",(0,o.jsx)(t.li,{children:"\u2601\uFE0F Automated publishing flow for cloud providers (GitHub, S3, Bitbucket, etc.)"}),"\n",(0,o.jsx)(t.li,{children:"\u26A1\uFE0F Easy-to-use boilerplate templates for webpack and TypeScript"}),"\n",(0,o.jsx)(t.li,{children:"\u2699\uFE0F Native Node.js module support"}),"\n",(0,o.jsx)(t.li,{children:"\u{1F50C} Extensible JavaScript plugin API"}),"\n"]}),"\n",(0,o.jsx)(t.admonition,{title:"Further reading",type:"info",children:(0,o.jsxs)(t.p,{children:["Visit the ",(0,o.jsx)(t.a,{href:"https://www.electronforge.io/core-concepts/why-electron-forge",children:"Why Electron Forge"})," explainer document to learn more about Forge's philosophy and architecture."]})}),"\n",(0,o.jsx)(t.h2,{id:"whats-new-in-v6",children:"What's new in v6?"}),"\n",(0,o.jsx)(t.h3,{id:"completely-rewritten",children:"Completely rewritten"}),"\n",(0,o.jsxs)(t.p,{children:["From v1 to v5, Electron Forge was based on the now-discontinued ",(0,o.jsx)(t.a,{href:"https://www.npmjs.com/package/electron-compile",children:(0,o.jsx)(t.code,{children:"electron-compile"})})," project. Forge 6 is a complete rewrite of the project with a new modular architecture that can be extended to meet any Electron application's needs."]}),"\n",(0,o.jsxs)(t.p,{children:["In the past few years, Forge ",(0,o.jsx)(t.code,{children:"v6.0.0-beta"})," has achieved feature parity with v5 and code churn has slowed down dramatically, making the tool ready for general adoption."]}),"\n",(0,o.jsx)(t.admonition,{title:"Don't install the wrong package",type:"caution",children:(0,o.jsxs)(t.p,{children:["For versions 5 and below, Electron Forge was published to the ",(0,o.jsx)(t.code,{children:"electron-forge"})," package on npm.\nStarting with the v6 rewrite, Forge is instead structured as a monorepo project with many smaller\nprojects."]})}),"\n",(0,o.jsx)(t.h3,{id:"officially-supported",children:"Officially supported"}),"\n",(0,o.jsx)(t.p,{children:"Historically, Electron maintainers have been unopinionated about build tooling, leaving the task to various community packages. However, with Electron maturing as a project, it has become harder for new Electron developers to understand which tools they need to build and distribute their apps."}),"\n",(0,o.jsxs)(t.p,{children:["To help guide Electron developers in the distribution process, ",(0,o.jsx)(t.strong,{children:"we have have decided to make Forge the official batteries-included build pipeline for Electron"}),"."]}),"\n",(0,o.jsxs)(t.p,{children:["Over the past year, we have been slowly integrating Forge into the official Electron documentation, and we have recently moved Forge over from its old home in ",(0,o.jsx)(t.code,{children:"electron-userland/electron-forge"})," to the ",(0,o.jsx)(t.a,{href:"https://github.com/electron/forge",children:"electron/forge"})," repo. Now, we are finally ready to release Electron Forge to a general audience!"]}),"\n",(0,o.jsx)(t.h2,{id:"getting-started",children:"Getting started"}),"\n",(0,o.jsx)(t.h3,{id:"initializing-a-new-forge-project",children:"Initializing a new Forge project"}
1),"\n",(0,o.jsxs)(t.p,{children:["Scaffolding a new Electron Forge project can be done using the ",(0,o.jsx)(t.code,{children:"create-electron-app"})," CLI script."]}),"\n",(0,o.jsxs)(a.A,{children:[(0,o.jsx)(l.A,{value:"Yarn",label:"Yarn",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-bash",children:"yarn create electron-app my-app --template=webpack\ncd my-app\nyarn start\n"})})}),(0,o.jsx)(l.A,{value:"npm",label:"npm",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-bash",children:"npm init electron-app@latest my-app -- --template=webpack\ncd my-app\nnpm start\n"})})})]}),"\n",(0,o.jsxs)(t.p,{children:["The script will create an Electron project in the ",(0,o.jsx)(t.code,{children:"my-app"})," folder with completely JavaScript bundling and a preconfigured build pipeline."]}),"\n",(0,o.jsxs)(t.p,{children:["For more info, see the ",(0,o.jsx)(t.a,{href:"https://www.electronforge.io/",children:"Getting Started"})," guide in the Forge docs."]}),"\n",(0,o.jsxs)(t.admonition,{title:"First-class webpack support",type:"info",children:[(0,o.jsxs)(t.p,{children:["The above snippet uses Forge's ",(0,o.jsx)(t.a,{href:"https://www.electronforge.io/templates/webpack-template",children:"Webpack Template"}),", which we recommend as a starting point for new Electron projects. This template is built around the ",(0,o.jsx)(t.a,{href:"https://www.electronforge.io/config/plugins/webpack",children:(0,o.jsx)(t.code,{children:"@electron-forge/plugin-webpack"})})," plugin, which integrates webpack with Electron Forge in a few ways, including:"]}),(0,o.jsxs)(t.ul,{children:["\n",(0,o.jsxs)(t.li,{children:["enhancing local dev flow with ",(0,o.jsx)(t.a,{href:"https://webpack.js.org/configuration/dev-server/",children:"webpack-dev-server"}),", including support for HMR in the renderer;"]}),"\n",(0,o.jsx)(t.li,{children:"handling build logic for webpack bundles before application packaging; and"}),"\n",(0,o.jsx)(t.li,{children:"adding support for Native Node modules in the webpack bundling process."}),"\n"]}),(0,o.jsxs)(t.p,{children:["If you need TypeScript support, consider using the ",(0,o.jsx)(t.a,{href:"https://www.electronforge.io/templates/typescript-+-webpack-template",children:"Webpack + TypeScript Template"})," instead."]})]}),"\n",(0,o.jsx)(t.h3,{id:"importing-an-existing-project",children:"Importing an existing project"}),"\n",(0,o.jsx)(t.p,{children:"The Electron Forge CLI also contains an import command for existing Electron projects."}),"\n",(0,o.jsxs)(a.A,{children:[(0,o.jsx)(l.A,{value:"Yarn",label:"Yarn",default:!0,children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-bash",children:"cd my-app\nyarn add --dev @electron-forge/cli\nyarn electron-forge import\n"})})}),(0,o.jsx)(l.A,{value:"npm",label:"npm",children:(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-bash",children:'cd my-app\nnpm install --save-dev @electron-forge/cli\nnpm exec --package=@electron-forge/cli -c "electron-forge import"\n'})})})]}),"\n",(0,o.jsxs)(t.p,{children:["When you use the ",(0,o.jsx)(t.code,{children:"import"})," command, Electron Forge will add a few core dependencies and create a new ",(0,o.jsx)(t.code,{children:"forge.config.js"})," configuration. If you have any existing build tooling (e.g. Electron Packager, Electron Builder, or Forge 5), it will try to migrate as many settings as possible. Some of your existing configuration may need to be migrated manually."]}),"\n",(0,o.jsxs)(t.p,{children:["Manual migration details can be found in the Forge ",(0,o.jsx)(t.a,{href:"https://www.electronforge.io/import-existing-project",children:"import documentation"}),". If you need help, please stop by ",(0,o.jsx)(t.a,{href:"https://discord.gg/f4cH9BzaDw",children:"our Discord server"}),"!"]}),"\n",(0,o.jsx)(t.h2,{id:"why-switch-to-forge",children:"Why switch to Forge?"}),"\n",(0,o.jsx)(t.p,{children:"If you already have tooling for packaging and publishing your Electron app, the benefits associated with adopting Electron Forge can still outweigh the initial switching cost."}),"\n",(0,o.jsx)(t.p,{children:"We believe there are two main benefits to using Forge:"}),"\n",(0,o.jsxs)(t.ol,{children:["\n",(0,o.jsxs)(t.li,{children:["\n",(0,o.jsxs)(t.p,{children:[(0,o.jsx)(t.strong,{children:"Forge receives new features for application building as soon as they are supported in Electron"}),". In this case, you won't need to wire in new tooling support yourself, or wait for that support to be eventually implemented by other packages before upgrading. For recent examples, see ",(0,o.jsx)(t.a,{href:"https://github.com/electron/universal",children:"macOS universal binaries"})," and ",(0,o.jsx)(t.a,{href:"https://www.electronjs.org/docs/latest/tutorial/asar-integrity",children:"ASAR integrity checking"}),"."]}),"\n"]}),"\n",(0,o.jsxs)(t.li,{children:["\n",(0,o.jsxs)(t.p,{children:[(0,o.jsx)(t.strong,{children:"Forge's multi-package architecture makes it easy to understand and extend."})," Since Forge is made up of many smaller packages with clear responsibilities, it is easier to follow code flow. In addition, Forge's extensible API design means that you can write your own additional build logic separate from the provided configuration options for advanced use cases. For more details on writing custom Forge plugins, makers, and publishers, see the ",(0,o.jsx)(t.a,{href:"https://www.electronforge.io/advanced/extending-electron-forge",children:"Extending Electron Forge"})," section of the docs."]}),"\n"]}),"\n"]}),"\n",(0,o.jsx)(t.h2,{id:"breaking-changes",children:"Breaking changes"}),"\n",(0,o.jsx)(t.p,{children:"Forge 6 has spent a long time in the beta phase, and its release cadence has gradually slowed down. However, we have accelerated development in the second half of 2022 and used the last few releases to push some final breaking changes before the v6.0.0 stable release."}),"\n",(0,o.jsxs)(t.p,{children:["If you are an Electron Forge 6 beta user, see the ",(0,o.jsx)(t.a,{href:"https://github.com/electron/forge/releases/tag/v6.0.0",children:"v6.0.0 GitHub release notes"})," for a list of breaking changes made in recent betas (",(0,o.jsx)(t.code,{children:">=6.0.0-beta.65"}),")."]}),"\n",(0,o.jsxs)(t.p,{children:["A complete list of changes and commits can be found in the repo's ",(0,o.jsx)(t.a,{href:"https://github.com/electron/forge/blob/main/CHANGELOG.md",children:"CHA
1NGELOG.md"}),"."]}),"\n",(0,o.jsx)(t.h2,{id:"submit-your-feedback",children:"Submit your feedback!"}),"\n",(0,o.jsx)(t.p,{children:"Tell us what you need! The Electron Forge team is always looking to build the project to better suit its users."}),"\n",(0,o.jsxs)(t.p,{children:["You can help us improve Electron Forge by submitting feature requests, posting ",(0,o.jsx)(t.a,{href:"https://github.com/electron/forge/issues",children:"issues"}),", or just letting us know your feedback! You can also join us in the ",(0,o.jsx)(t.a,{href:"https://discord.com/invite/electronjs",children:"official Electron Discord server"}),", where there is a dedicated channel for Electron Forge discussion."]}),"\n",(0,o.jsxs)(t.p,{children:["If you want to give any feedback on the Forge docs at ",(0,o.jsx)(t.a,{href:"https://electronforge.io",children:"https://electronforge.io"}),", we have a\nGitBook instance synced to the\n",(0,o.jsx)(t.a,{href:"https://github.com/electron-forge/electron-forge-docs",children:"electron-forge/electron-forge-docs"})," repo."]})]})}function p(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(u,{...e})}):u(e)}},57250(e,t,n){n.d(t,{A:()=>l});var r=n(74848);n(96540);var o=n(18215),i=n(57663);function a({children:e,className:t,hidden:n}){return(0,r.jsx)("div",{role:"tabpanel",className:(0,o.A)("tabItem_Ymn6",t),hidden:n,children:e})}function l({children:e,className:t,value:n}){let{selectedValue:o,lazy:s}=(0,i.uc)(),c=n===o;return!c&&s?null:(0,r.jsx)(a,{className:t,hidden:!c,children:e})}},50773(e,t,n){n.d(t,{A:()=>u});var r=n(74848);n(96540);var o=n(18215),i=n(88287),a=n(57663),l=n(28584),s=n(19863);function c({className:e}){let{selectedValue:t,selectValue:n,tabValues:i,block:s}=(0,a.uc)(),d=[],{blockElementScrollPositionUntilNextRender:h}=(0,l.a_)(),u=e=>{let r=e.currentTarget,o=i[d.indexOf(r)].value;o!==t&&(h(r),n(o))},p=e=>{let t=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{let n=d.indexOf(e.currentTarget)+1;t=d[n]??d[0];break}case"ArrowLeft":{let n=d.indexOf(e.currentTarget)-1;t=d[n]??d[d.length-1]}}t?.focus()};return(0,r.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.A)("tabs",{"tabs--block":s},e),children:i.map(({value:e,label:n,attributes:i})=>(0,r.jsx)("li",{role:"tab",tabIndex:t===e?0:-1,"aria-selected":t===e,ref:e=>{d.push(e)},onKeyDown:p,onClick:u,...i,className:(0,o.A)("tabs__item","tabItem_LNqP",i?.className,{"tabs__item--active":t===e}),children:n??e},e))})}function d({children:e}){return(0,r.jsx)("div",{className:"margin-top--md",children:e})}function h({className:e,children:t}){return(0,r.jsxs)("div",{className:(0,o.A)(i.G.tabs.container,"tabs-container","tabList__CuJ"),children:[(0,r.jsx)(c,{className:e}),(0,r.jsx)(d,{children:t})]})}function u(e){let t=(0,s.A)(),n=(0,a.OC)(e);return(0,r.jsx)(a.O_,{value:n,children:(0,r.jsx)(h,{className:e.className,children:(0,a.vT)(e.children)})},String(t))}},57663(e,t,n){n.d(t,{OC:()=>u,O_:()=>f,uc:()=>g,vT:()=>d});var r=n(74848),o=n(96540),i=n(56347),a=n(99989),l=n(96629),s=n(80618),c=n(41367);function d(e){return o.Children.toArray(e).filter(e=>"\n"!==e)}function h({value:e,tabValues:t}){return t.some(t=>t.value===e)}function u(e){let t,{defaultValue:n,queryString:r=!1,groupId:d}=e,u=function(e){let{values:t,children:n}=e;return(0,o.useMemo)(()=>{let e=t??o.Children.toArray(n).flatMap(e=>{if(!e)return[];if((0,o.isValidElement)(e)&&function(e){let{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return[e];let t="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${t}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.
2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:t,attributes:n,default:r}})=>({value:e,label:t,attributes:n,default:r})),r=(0,s.XI)(e,(e,t)=>e.value===t.value);if(r.length>0)throw Error(`Docusaurus error: Duplicate values "${r.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[t,n])}(e),[p,g]=(0,o.useState)(()=>(function({defaultValue:e,tabValues:t}){if(0===t.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!h({value:e,tabValues:t}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${t.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let n=t.find(e=>e.default)??t[0];if(!n)throw Error("Unexpected error: 0 tabValues");return n.value})({defaultValue:n,tabValues:u})),[f,m]=function({queryString:e=!1,groupId:t}){let n=(0,i.W6)(),r=function({queryString:e=!1,groupId:t}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!t)throw Error('Docusaurus error: The <Tabs> 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 t??null}({queryString:e,groupId:t});return[(0,l.aZ)(r),(0,o.useCallback)(e=>{if(!r)return;let t=new URLSearchParams(n.location.search);t.set(r,e),n.replace({...n.location,search:t.toString()})},[r,n])]}({queryString:r,groupId:d}),[b,x]=function({groupId:e}){let t=e?`docusaurus.tab.${e}`:null,[n,r]=(0,c.Dv)(t);return[n,(0,o.useCallback)(e=>{t&&r.set(e)},[t,r])]}({groupId:d}),w=h({value:t=f??b,tabValues:u})?t:null;return(0,a.A)(()=>{w&&g(w)},[w]),{selectedValue:p,selectValue:(0,o.useCallback)(e=>{if(!h({value:e,tabValues:u}))throw Error(`Can't select invalid tab value=${e}`);g(e),m(e),x(e)},[m,x,u]),tabValues:u,lazy:e.lazy??!1,block:e.block??!1}}let p=(0,o.createContext)(null);function g(){let e=o.useContext(p);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function f(e){return(0,r.jsx)(p.Provider,{value:e.value,children:e.children})}},28453(e,t,n){n.d(t,{R:()=>a,x:()=>l});var r=n(96540);let o={},i=r.createContext(o);function a(e){let t=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),r.createElement(i.Provider,{value:t},e.children)}},4533(e){e.exports=JSON.parse('{"permalink":"/blog/forge-v6-release","source":"@site/blog/forge-v6-release.md","title":"Introducing Electron Forge 6","description":"We are excited to announce that Electron Forge v6.0.0 is now available! This release marks the first major release of Forge since 2018 and moves the project from electron-userland into the main electron organization on Github.","date":"2022-11-03T00:00:00.000Z","tags":[{"inline":false,"label":"Ecosystem","permalink":"/blog/tags/ecosystem","description":"\'Blog posts about Electron\'s package ecosystem\'\\n"}],"readingTime":5.99,"hasTruncateMarker":false,"authors":[{"name":"georgexu99","url":"https://github.com/georgexu99","imageURL":"https://github.com/georgexu99.png?size=96","key":"georgexu99","page":null},{"name":"VerteDinde","url":"https://github.com/VerteDinde","imageURL":"https://github.com/VerteDinde.png?size=96","key":"VerteDinde","page":null},{"name":"erickzhao","url":"https://github.com/erickzhao","imageURL":"https://github.com/erickzhao.png?size=96","key":"erickzhao","page":null}],"frontMatter":{"title":"Introducing Electron Forge 6","date":"2022-11-03T00:00:00.000Z","authors":["georgexu99","VerteDinde","erickzhao"],"slug":"forge-v6-release","toc_max_heading_level":3,"tags":["ecosystem"]},"unlisted":false,"prevItem":{"title":"A Quiet Place Part II (Dec\'22)","permalink":"/blog/a-quiet-place-22"},"nextItem":{"title":"Maintainer Summit 2022 Recap","permalink":"/blog/maintainer-summit-2022-recap"}}')}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.