-
Notifications
You must be signed in to change notification settings - Fork 785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(www): fix an inconsistency between www builds #4983
Conversation
|
Path | Error Count |
---|---|
src/dev-server/index.ts | 37 |
src/mock-doc/serialize-node.ts | 36 |
src/dev-server/server-process.ts | 32 |
src/compiler/build/build-stats.ts | 27 |
src/compiler/output-targets/dist-lazy/generate-lazy-module.ts | 25 |
src/compiler/style/test/optimize-css.spec.ts | 23 |
src/testing/puppeteer/puppeteer-element.ts | 23 |
src/compiler/prerender/prerender-main.ts | 22 |
src/runtime/vdom/vdom-render.ts | 20 |
src/runtime/client-hydrate.ts | 19 |
src/screenshot/connector-base.ts | 19 |
src/compiler/config/test/validate-paths.spec.ts | 16 |
src/dev-server/request-handler.ts | 15 |
src/compiler/prerender/prerender-optimize.ts | 14 |
src/compiler/sys/stencil-sys.ts | 14 |
src/compiler/transpile/transpile-module.ts | 14 |
src/runtime/vdom/vdom-annotations.ts | 14 |
src/sys/node/node-sys.ts | 14 |
src/compiler/build/build-finish.ts | 13 |
src/compiler/prerender/prerender-queue.ts | 13 |
Our most common errors
Typescript Error Code | Count |
---|---|
TS2345 | 418 |
TS2322 | 398 |
TS18048 | 310 |
TS18047 | 100 |
TS2722 | 38 |
TS2532 | 34 |
TS2531 | 23 |
TS2454 | 14 |
TS2352 | 13 |
TS2769 | 10 |
TS2790 | 10 |
TS2538 | 8 |
TS2344 | 5 |
TS2416 | 4 |
TS2493 | 3 |
TS18046 | 2 |
TS2684 | 1 |
TS2488 | 1 |
TS2430 | 1 |
Unused exports report
There are 12 unused exports on this PR. That's the same number of errors on main, so at least we're not creating new ones!
Unused exports
File | Line | Identifier |
---|---|---|
src/runtime/bootstrap-lazy.ts | 21 | setNonce |
src/screenshot/screenshot-fs.ts | 18 | readScreenshotData |
src/testing/testing-utils.ts | 198 | withSilentWarn |
src/utils/index.ts | 145 | CUSTOM |
src/compiler/app-core/app-data.ts | 25 | BUILD |
src/compiler/app-core/app-data.ts | 115 | Env |
src/compiler/app-core/app-data.ts | 117 | NAMESPACE |
src/compiler/fs-watch/fs-watch-rebuild.ts | 123 | updateCacheFromRebuild |
src/compiler/types/validate-primary-package-output-target.ts | 62 | satisfies |
src/compiler/types/validate-primary-package-output-target.ts | 62 | Record |
src/testing/puppeteer/puppeteer-declarations.ts | 485 | WaitForEventOptions |
src/compiler/sys/fetch/write-fetch-success.ts | 7 | writeFetchSuccessSync |
76cb26e
to
383bfe5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some notes
const orgImportPaths: string[] = []; | ||
const tsSourceFile = ts.createSourceFile('module.ts', code, ts.ScriptTarget.Latest); | ||
ts.transform(tsSourceFile, [readImportPaths(orgImportPaths)]); | ||
const orgModulePaths = readModulePaths(code); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a change here because I don't think it's actually necessary to use ts.transform
here, we were doing so purely to gather information about the source code, not to actually run a transformer and then emit code from it. So instead we can just create a ts.SourceFile
and then iterate through the statements
on it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - I can't think of/see a reason to use transform
here 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about doing the lean-more-into-TypeScript refactor to actually emit the code but I think that's a lot more overhead actually
function isImportOrExportDecl(stmt: ts.Statement): stmt is ts.ImportDeclaration | ts.ExportDeclaration { | ||
return ts.isExportDeclaration(stmt) || ts.isImportDeclaration(stmt); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is I think necessary because I don't think TS is smart enough (yet!) to know that ts.isExportDeclaration(foo) || ts.isImportDeclaration(foo)
evaluating to true
means it must be one of those two types - instead when I inlined the usage of these two functions it was inferring a type of ts.Statement
:/
it('should update both an import and an export statement', () => { | ||
const input = `import './p-010101.js'; export { foo } from './p-010101.js'`; | ||
const o = updateImportPaths(input, newAbsDir); | ||
expect(o.code).toBe(`import '/build/p-010101.js'; export { foo } from '/build/p-010101.js'`); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a regression test for the bug, I confirmed that it fails on main
383bfe5
to
698e2c8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One possible change, but not a blocker
code = code.replace(new RegExp(`"${orgImportPath}"`, 'g'), `"${newPath}"`); | ||
code = code.replace(new RegExp(`'${orgImportPath}'`, 'g'), `'${newPath}'`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to keep the same quotation style that the file originally had? Otherwise we could instantiate a single regex to match the import with either quotation style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I suppose we don't - I kept the same quotation-style-preserving logic that was already present, but I really just did so because that was the precedent and not for any real reason
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't think we need it, but I'm not opposed to keeping it either. The only thing I can think if is that different quote styles can be used to allow another quote style to be used in a string:
const foo = "We are 'the' champions";
which I don't think would be allowed in module paths (otherwise that'd be very confusing for users!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok maybe out of an abundance of caution I'll just leave it as-is for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - I had one tiny ask that's not blocking
* @param code the code to transform | ||
* @returns a list of the module specifiers present in the code | ||
*/ | ||
function readModulePaths(code: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we throw a return type on this function please?
const orgImportPaths: string[] = []; | ||
const tsSourceFile = ts.createSourceFile('module.ts', code, ts.ScriptTarget.Latest); | ||
ts.transform(tsSourceFile, [readImportPaths(orgImportPaths)]); | ||
const orgModulePaths = readModulePaths(code); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - I can't think of/see a reason to use transform
here 🤔
code = code.replace(new RegExp(`"${orgImportPath}"`, 'g'), `"${newPath}"`); | ||
code = code.replace(new RegExp(`'${orgImportPath}'`, 'g'), `'${newPath}'`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't think we need it, but I'm not opposed to keeping it either. The only thing I can think if is that different quote styles can be used to allow another quote style to be used in a string:
const foo = "We are 'the' champions";
which I don't think would be allowed in module paths (otherwise that'd be very confusing for users!)
698e2c8
to
bf86233
Compare
This fixes a bug where subsequent `www` builds would not always produce working output. In particular, prior to this change a 'clean' `www` build (i.e one done after deleting all previous output) would produce a working build but subsequent builds would not. This had to do with an optimization that Stencil attempts to do during the `www` build where it will attempt to inline the JS code for the main entry point into the `index.html` that it produces. As part of doing this it needs to rewrite some relative paths for any module specifiers that are part of that entry point, since the HTML file is found at `www/index.html` while the JS entry point will be typically found at `www/build/project-name.js`. Thus if that entry point has an import like `import foo from './bar.js'` that will need to be rewritten to `import foo from '/build/bar.js'` in order for the import to resolve once its inlined into the HTML. This inlining optimization was previously broken because the path rewrite code did not account for the presence of more than one instance of a given module specifier in the soon-to-be-inlined code. However, by default we have both `import` and `export` declarations in that code, so the inlined code would end up non-functional. To give an example, the problematic excerpt of the inlined code would look typically like this: ```js import { p as e, b as t } from "/build/p-71aeae62.js"; export { s as setNonce } from "./p-71aeae62.js"; ``` so the first `import` declaration is being correctly rewritten to begin with `/build/` but the `export` declaration is not. The code should look like this: ```js import { p as e, b as t } from "/build/p-71aeae62.js"; export { s as setNonce } from "/build/p-71aeae62.js"; ``` This commit fixes the issue by transforming all instances of a given module specifier in the text, and additionally adds a regression test that tests for this specific case.
bf86233
to
5e28022
Compare
This fixes a bug where subsequent
www
builds would not always produce working output. In particular, prior to this change a 'clean'www
build (i.e one done after deleting all previous output) would produce a working build but subsequent builds would not.This had to do with an optimization that Stencil attempts to do during the
www
build where it will attempt to inline the JS code for the main entry point into theindex.html
that it produces.As part of doing this it needs to rewrite some relative paths for any module specifiers that are part of that entry point, since the HTML file is found at
www/index.html
while the JS entry point will be typically found atwww/build/project-name.js
. Thus if that entry point has an import likeimport foo from './bar.js'
that will need to be rewritten toimport foo from '/build/bar.js'
in order for the import to resolve once its inlined into the HTML.This inlining optimization was previously broken because the path rewrite code did not account for the presence of more than one instance of a given module specifier in the soon-to-be-inlined code. However, by default we have both
import
andexport
declarations in that code, so the inlined code would end up non-functional.To give an example, the problematic excerpt of the inlined code would look typically like this:
so the first
import
declaration is being correctly rewritten to begin with/build/
but theexport
declaration is not. The code should look like this:This commit fixes the issue by transforming all instances of a given module specifier in the text, and additionally adds a regression test that tests for this specific case.
What is the current behavior?
You can reproduce the issue by doing the following:
stencil.config.ts
to only do thewww
build (just for simplicity)build/index.html
. It should look something like this:www
directory locally, for instance:<my-component>
tag should work properly.www/
and check outbuild/index.html
again. It should now have inlined JS in the<script>
tag, like so:./p-71aeae62.js
module specifier can't be resolved (it should be/build/p-71aeae62.js
instead).What is the new behavior?
If you build and install this in the same project as above you should be able to rebuild without producing a non-working build.
Does this introduce a breaking change?
Testing
See above. I also expanded the unit tests for this bit of code a bit.