diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md index ac7d60212c9..e57ad9f821f 100644 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -209,13 +209,10 @@ export class Something { * Ordered by their natural call order, for example * WillLoad should go before DidLoad. */ + connectedCallback() {} componentWillLoad() {} componentDidLoad() {} - componentWillEnter() {} - componentDidEnter() {} - componentWillLeave() {} - componentDidLeave() {} - componentDidUnload() {} + disconnectedCallbac() {} /** * 8. Listeners diff --git a/src/compiler/transformers/decorators-to-static/convert-decorators.ts b/src/compiler/transformers/decorators-to-static/convert-decorators.ts index 7d3f58d4745..ebfb4ab5076 100644 --- a/src/compiler/transformers/decorators-to-static/convert-decorators.ts +++ b/src/compiler/transformers/decorators-to-static/convert-decorators.ts @@ -5,7 +5,7 @@ import { elementDecoratorsToStatic } from './element-decorator'; import { eventDecoratorsToStatic } from './event-decorator'; import { listenDecoratorsToStatic } from './listen-decorator'; import { isDecoratorNamed } from './decorator-utils'; -import { methodDecoratorsToStatic } from './method-decorator'; +import { methodDecoratorsToStatic, validateMethods } from './method-decorator'; import { propDecoratorsToStatic } from './prop-decorator'; import { stateDecoratorsToStatic } from './state-decorator'; import { watchDecoratorsToStatic } from './watch-decorator'; @@ -36,8 +36,9 @@ export const visitClassDeclaration = (config: d.Config, diagnostics: d.Diagnosti return classNode; } - const decoratedMembers = classNode.members.filter(member => Array.isArray(member.decorators) && member.decorators.length > 0); - const newMembers = removeStencilDecorators(Array.from(classNode.members)); + const classMembers = classNode.members; + const decoratedMembers = classMembers.filter(member => Array.isArray(member.decorators) && member.decorators.length > 0); + const newMembers = removeStencilDecorators(Array.from(classMembers)); // parser component decorator (Component) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, newMembers, componentDecorator); @@ -54,6 +55,8 @@ export const visitClassDeclaration = (config: d.Config, diagnostics: d.Diagnosti listenDecoratorsToStatic(diagnostics, decoratedMembers, newMembers); } + validateMethods(diagnostics, classMembers); + return ts.updateClassDeclaration( classNode, removeDecorators(classNode, CLASS_DECORATORS_TO_REMOVE), diff --git a/src/compiler/transformers/decorators-to-static/method-decorator.ts b/src/compiler/transformers/decorators-to-static/method-decorator.ts index c3e7f1981f4..3a32a26e073 100644 --- a/src/compiler/transformers/decorators-to-static/method-decorator.ts +++ b/src/compiler/transformers/decorators-to-static/method-decorator.ts @@ -89,3 +89,14 @@ const parseMethodDecorator = (config: d.Config, diagnostics: d.Diagnostic[], tsS const isTypePromise = (typeStr: string) => { return /^Promise<.+>$/.test(typeStr); }; + +export const validateMethods = (diagnostics: d.Diagnostic[], members: ts.NodeArray) => { + members.filter(ts.isMethodDeclaration).map(method => { + if (method.name.getText() === 'componentDidUnload') { + const err = buildError(diagnostics); + err.header = `Replace "componentDidUnload()" with "disconnectedCallback()"`; + err.messageText = `The "componentDidUnload()" method was removed in Stencil 2. Please use the "disconnectedCallbac()" method instead.`; + augmentDiagnosticWithNode(err, method.name); + } + }); +}; diff --git a/src/compiler/transformers/static-to-meta/component.ts b/src/compiler/transformers/static-to-meta/component.ts index 155975b5c94..9708b082a21 100644 --- a/src/compiler/transformers/static-to-meta/component.ts +++ b/src/compiler/transformers/static-to-meta/component.ts @@ -41,7 +41,6 @@ export const parseStaticComponentMeta = ( const encapsulation = parseStaticEncapsulation(staticMembers); const cmp: d.ComponentCompilerMeta = { - isLegacy: false, tagName: tagName, excludeFromCollection: moduleFile.excludeFromCollection, isCollectionDependency, diff --git a/src/compiler/transpile/run-program.ts b/src/compiler/transpile/run-program.ts index 2d3ea20422a..88a2f1c5ac6 100644 --- a/src/compiler/transpile/run-program.ts +++ b/src/compiler/transpile/run-program.ts @@ -1,14 +1,15 @@ -import * as d from '../../declarations'; -import { basename, join, relative } from 'path'; -import { buildError, loadTypeScriptDiagnostics, normalizePath } from '@utils'; +import type * as d from '../../declarations'; +import { basename, join } from 'path'; import { convertDecoratorsToStatic } from '../transformers/decorators-to-static/convert-decorators'; import { generateAppTypes } from '../types/generate-app-types'; import { getComponentsFromModules, isOutputTargetDistTypes } from '../output-targets/output-utils'; +import { loadTypeScriptDiagnostics, normalizePath } from '@utils'; import { resolveComponentDependencies } from '../entries/resolve-component-dependencies'; +import type ts from 'typescript'; import { updateComponentBuildConditionals } from '../app-core/app-data'; import { updateModule } from '../transformers/static-to-meta/parse-static'; -import ts from 'typescript'; import { updateStencilTypesImports } from '../types/stencil-types'; +import { validateTranspiledComponents } from './validate-components'; export const runTsProgram = async (config: d.Config, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx, tsBuilder: ts.BuilderProgram) => { const tsSyntactic = loadTypeScriptDiagnostics(tsBuilder.getSyntacticDiagnostics()); @@ -54,7 +55,7 @@ export const runTsProgram = async (config: d.Config, compilerCtx: d.CompilerCtx, updateComponentBuildConditionals(compilerCtx.moduleMap, buildCtx.components); resolveComponentDependencies(buildCtx.components); - validateUniqueTagNames(config, buildCtx); + validateTranspiledComponents(config, buildCtx); if (buildCtx.hasError) { return false; @@ -82,18 +83,6 @@ export const runTsProgram = async (config: d.Config, compilerCtx: d.CompilerCtx, return false; }; -const validateUniqueTagNames = (config: d.Config, buildCtx: d.BuildCtx) => { - buildCtx.components.forEach(cmp => { - const tagName = cmp.tagName; - const cmpsWithTagName = buildCtx.components.filter(c => c.tagName === tagName); - if (cmpsWithTagName.length > 1) { - const err = buildError(buildCtx.diagnostics); - err.header = `Component Tag Name "${tagName}" Must Be Unique`; - err.messageText = `Please update the components so "${tagName}" is only used once: ${cmpsWithTagName.map(c => relative(config.rootDir, c.sourceFilePath)).join(' ')}`; - } - }); -}; - const getRelativeDts = (config: d.Config, srcPath: string, emitDtsPath: string) => { const parts: string[] = []; srcPath = normalizePath(srcPath); diff --git a/src/compiler/transpile/validate-components.ts b/src/compiler/transpile/validate-components.ts new file mode 100644 index 00000000000..aade12b5563 --- /dev/null +++ b/src/compiler/transpile/validate-components.ts @@ -0,0 +1,19 @@ +import type * as d from '../../declarations'; +import { buildError } from '@utils'; +import { relative } from 'path'; + +export const validateTranspiledComponents = (config: d.Config, buildCtx: d.BuildCtx) => { + for (const cmp of buildCtx.components) { + validateUniqueTagNames(config, buildCtx, cmp); + } +}; + +const validateUniqueTagNames = (config: d.Config, buildCtx: d.BuildCtx, cmp: d.ComponentCompilerMeta) => { + const tagName = cmp.tagName; + const cmpsWithTagName = buildCtx.components.filter(c => c.tagName === tagName); + if (cmpsWithTagName.length > 1) { + const err = buildError(buildCtx.diagnostics); + err.header = `Component Tag Name "${tagName}" Must Be Unique`; + err.messageText = `Please update the components so "${tagName}" is only used once: ${cmpsWithTagName.map(c => relative(config.rootDir, c.sourceFilePath)).join(' ')}`; + } +}; diff --git a/src/compiler/types/generate-app-types.ts b/src/compiler/types/generate-app-types.ts index 9db22676a7d..17f9ebb1a5f 100644 --- a/src/compiler/types/generate-app-types.ts +++ b/src/compiler/types/generate-app-types.ts @@ -45,7 +45,6 @@ const generateComponentTypesFile = (config: d.Config, buildCtx: d.BuildCtx, inte let typeImportData: d.TypesImportData = {}; const c: string[] = []; const allTypes = new Map(); - const needsJSXElementHack = buildCtx.components.some(cmp => cmp.isLegacy); const components = buildCtx.components.filter(m => !m.isCollectionDependency); const modules: d.TypesModule[] = components.map(cmp => { @@ -83,13 +82,6 @@ const generateComponentTypesFile = (config: d.Config, buildCtx: d.BuildCtx, inte c.push(`declare global {`); - if (needsJSXElementHack) { - c.push(` // Adding a global JSX for backcompatibility with legacy dependencies`); - c.push(` export namespace JSX {`); - c.push(` export interface Element {}`); - c.push(` }`); - } - c.push(...modules.map(m => m.element)); c.push(` interface HTMLElementTagNameMap {`); diff --git a/src/declarations/stencil-core/index.ts b/src/declarations/stencil-core/index.ts index 267af175da2..28e3f4051b2 100644 --- a/src/declarations/stencil-core/index.ts +++ b/src/declarations/stencil-core/index.ts @@ -4,7 +4,6 @@ export { Component, ComponentOptions, ComponentDidLoad, - ComponentDidUnload, ComponentDidUpdate, ComponentInterface, ComponentWillLoad, diff --git a/src/declarations/stencil-private.ts b/src/declarations/stencil-private.ts index b0bc0c2bd15..c9071cfc17a 100644 --- a/src/declarations/stencil-private.ts +++ b/src/declarations/stencil-private.ts @@ -693,7 +693,6 @@ export interface ComponentCompilerMeta extends ComponentCompilerFeatures { shadowDelegatesFocus: boolean; excludeFromCollection: boolean; isCollectionDependency: boolean; - isLegacy: boolean; docs: CompilerJsDoc; jsFilePath: string; listeners: ComponentCompilerListener[]; diff --git a/src/declarations/stencil-public-runtime.ts b/src/declarations/stencil-public-runtime.ts index 2b31713e837..664a1b8b0ba 100644 --- a/src/declarations/stencil-public-runtime.ts +++ b/src/declarations/stencil-public-runtime.ts @@ -363,14 +363,6 @@ export interface ComponentDidUpdate { componentDidUpdate(): void; } -export interface ComponentDidUnload { - /** - * The component did unload and the element - * will be destroyed. - */ - componentDidUnload(): void; -} - export interface ComponentInterface { connectedCallback?(): void; disconnectedCallback?(): void; diff --git a/test/karma/test-app/dom-reattach/cmp-root.tsx b/test/karma/test-app/dom-reattach/cmp-root.tsx index 830dacb744a..345c42e8499 100644 --- a/test/karma/test-app/dom-reattach/cmp-root.tsx +++ b/test/karma/test-app/dom-reattach/cmp-root.tsx @@ -1,13 +1,12 @@ import { Component, h, Host, Prop } from '@stencil/core'; @Component({ - tag: 'dom-reattach' + tag: 'dom-reattach', }) export class DomReattach { - - @Prop({mutable: true}) willLoad = 0; - @Prop({mutable: true}) didLoad = 0; - @Prop({mutable: true}) didUnload = 0; + @Prop({ mutable: true }) willLoad = 0; + @Prop({ mutable: true }) didLoad = 0; + @Prop({ mutable: true }) didUnload = 0; componentWillLoad() { this.willLoad++; @@ -17,7 +16,7 @@ export class DomReattach { this.didLoad++; } - componentDidUnload() { + disconnectedCallback() { this.didUnload++; } @@ -26,8 +25,8 @@ export class DomReattach {

componentWillLoad: {this.willLoad}

componentDidLoad: {this.didLoad}

-

componentDidUnload: {this.didUnload}

+

disconnectedCallback: {this.didUnload}

- ) + ); } } diff --git a/test/karma/test-app/lifecycle-unload/cmp-a.tsx b/test/karma/test-app/lifecycle-unload/cmp-a.tsx index b1a1aade18b..91266f20774 100644 --- a/test/karma/test-app/lifecycle-unload/cmp-a.tsx +++ b/test/karma/test-app/lifecycle-unload/cmp-a.tsx @@ -2,10 +2,9 @@ import { Component, Element, h } from '@stencil/core'; @Component({ tag: 'lifecycle-unload-a', - shadow: true + shadow: true, }) export class LifecycleUnloadA { - @Element() el!: HTMLElement; results?: HTMLDivElement | null; @@ -13,7 +12,7 @@ export class LifecycleUnloadA { this.results = this.el.ownerDocument!.body.querySelector('#lifecycle-unload-results') as HTMLDivElement; } - componentDidUnload() { + disconnectedCallback() { const elm = document.createElement('div'); elm.textContent = 'cmp-a unload'; this.results!.appendChild(elm); diff --git a/test/karma/test-app/lifecycle-unload/cmp-b.tsx b/test/karma/test-app/lifecycle-unload/cmp-b.tsx index 21aa77b7e28..660300ce992 100644 --- a/test/karma/test-app/lifecycle-unload/cmp-b.tsx +++ b/test/karma/test-app/lifecycle-unload/cmp-b.tsx @@ -2,10 +2,9 @@ import { Component, Element, h } from '@stencil/core'; @Component({ tag: 'lifecycle-unload-b', - shadow: true + shadow: true, }) export class LifecycleUnloadB { - @Element() el!: HTMLElement; results?: HTMLDivElement; @@ -13,7 +12,7 @@ export class LifecycleUnloadB { this.results = this.el.ownerDocument!.body.querySelector('#lifecycle-unload-results') as HTMLDivElement; } - componentDidUnload() { + disconnectedCallback() { const elm = document.createElement('div'); elm.textContent = 'cmp-b unload'; this.results!.appendChild(elm); @@ -22,8 +21,10 @@ export class LifecycleUnloadB { render() { return [
cmp-b - top
, -
, - +
+ +
, + , ]; } }