-
Notifications
You must be signed in to change notification settings - Fork 394
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: dynamic imports (experimental flag) (#1397)
* refactor(engine): base api changes to support dynamic components * feat: add compiler integration * chore: minor lint whitelisting * feat: add karma test * chore: fix copyright * fix(engine): fixing tests for PR #1397 * fix(engine): fixing unit tests for PR #1397 * fix(engine): fixing tests for PR #1397 * Update packages/@lwc/errors/src/compiler/error-info/template-transform.ts Co-Authored-By: Pierre-Marie Dartus <p.dartus@salesforce.com> * fix: option name * fix: minor refactor for dynamic plugin * fix: missing error type
- Loading branch information
Diego Ferreiro Val
committed
Jul 10, 2019
1 parent
cdf851b
commit 969d124
Showing
41 changed files
with
803 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ lib/ | |
coverage/ | ||
fixtures/ | ||
public/ | ||
__benchmarks_results__/ |
126 changes: 126 additions & 0 deletions
126
packages/@lwc/babel-plugin-component/src/__tests__/dynamic-imports.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* | ||
* Copyright (c) 2018, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
const pluginTestFactory = require('./utils/test-transform').pluginTest; | ||
const testFunction = require('../index'); | ||
const pluginNoop = pluginTestFactory(testFunction); | ||
const pluginTestStrict = pluginTestFactory(testFunction, { | ||
dynamicImports: { loader: null, strictSpecifier: true }, | ||
}); | ||
const pluginTestLoader = pluginTestFactory(testFunction, { | ||
dynamicImports: { loader: '@custom/loader', strictSpecifier: true }, | ||
}); | ||
|
||
describe('Dynamic imports', () => { | ||
pluginNoop( | ||
'passthough with no config', | ||
` | ||
export async function test() { | ||
const id = "foo"; | ||
const x = await import(id); | ||
return x + "yay"; | ||
} | ||
`, | ||
{ | ||
output: { | ||
code: ` | ||
export async function test() { | ||
const id = "foo"; | ||
const x = await import(id); | ||
return x + "yay"; | ||
} | ||
`, | ||
}, | ||
} | ||
); | ||
|
||
pluginTestStrict( | ||
'check validation for strict', | ||
` | ||
export async function test() { | ||
const id = "foo"; | ||
const x = await import(id); | ||
return x + "yay"; | ||
} | ||
`, | ||
{ | ||
error: { | ||
message: | ||
'Invalid import. The argument "id" must be a stringLiteral for dynamic imports when strict mode is enabled.', | ||
loc: { | ||
line: 3, | ||
column: 23, | ||
length: 2, | ||
start: 72, | ||
}, | ||
}, | ||
} | ||
); | ||
|
||
pluginTestStrict( | ||
'unchanged dynamic import in strict mode', | ||
` | ||
export async function test() { | ||
const x = await import("foo"); | ||
return x + "yay"; | ||
} | ||
`, | ||
{ | ||
output: { | ||
code: ` | ||
export async function test() { | ||
const x = await import("foo"); | ||
return x + "yay"; | ||
} | ||
`, | ||
}, | ||
} | ||
); | ||
|
||
pluginTestLoader( | ||
'test custom loader', | ||
` | ||
export async function test() { | ||
const x = await import("foo"); | ||
return x + "yay"; | ||
} | ||
`, | ||
{ | ||
output: { | ||
code: ` | ||
import { load as _load } from "@custom/loader"; | ||
export async function test() { | ||
const x = await _load("foo"); | ||
return x + "yay"; | ||
} | ||
`, | ||
}, | ||
} | ||
); | ||
|
||
pluginTestLoader( | ||
'test custom loader multiple imports', | ||
` | ||
export async function test() { | ||
const x = await import("foo"); | ||
const y = await import("bar"); | ||
return x + y + "yay"; | ||
} | ||
`, | ||
{ | ||
output: { | ||
code: ` | ||
import { load as _load } from "@custom/loader"; | ||
export async function test() { | ||
const x = await _load("foo"); | ||
const y = await _load("bar"); | ||
return x + y + "yay"; | ||
} | ||
`, | ||
}, | ||
} | ||
); | ||
}); |
71 changes: 71 additions & 0 deletions
71
packages/@lwc/babel-plugin-component/src/dynamic-imports.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright (c) 2018, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
const moduleImports = require('@babel/helper-module-imports'); | ||
const { generateError } = require('./utils'); | ||
const { LWCClassErrors } = require('@lwc/errors'); | ||
|
||
function getImportSource(path) { | ||
return path.parentPath.get('arguments.0'); | ||
} | ||
|
||
function validateImport(sourcePath) { | ||
if (!sourcePath.isStringLiteral()) { | ||
throw generateError(sourcePath, { | ||
errorInfo: LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT, | ||
messageArgs: [String(sourcePath)], | ||
}); | ||
} | ||
} | ||
/* | ||
* Expected API for this plugin: | ||
* { dynamicImports: { loader: string, strictSpecifier: boolean } } | ||
*/ | ||
module.exports = function() { | ||
function getLoaderRef(path, loaderName, state) { | ||
if (!state.loaderRef) { | ||
state.loaderRef = moduleImports.addNamed(path, 'load', loaderName); | ||
} | ||
return state.loaderRef; | ||
} | ||
|
||
function addDynamicImportDependency(dependency, state) { | ||
if (!state.dynamicImports) { | ||
state.dynamicImports = []; | ||
} | ||
|
||
if (!state.dynamicImports.includes(dependency)) { | ||
state.dynamicImports.push(dependency); | ||
} | ||
} | ||
|
||
return { | ||
Import(path, state) { | ||
const { dynamicImports } = state.opts; | ||
if (!dynamicImports) { | ||
return; | ||
} | ||
|
||
const { loader, strictSpecifier } = dynamicImports; | ||
const sourcePath = getImportSource(path); | ||
|
||
if (strictSpecifier) { | ||
validateImport(sourcePath); | ||
} | ||
|
||
if (loader) { | ||
const loaderId = getLoaderRef(path, loader, state); | ||
path.replaceWith(loaderId); | ||
} | ||
|
||
if (sourcePath.isStringLiteral()) { | ||
addDynamicImportDependency(sourcePath.node.value, state); | ||
} else { | ||
state.unknownDynamicDependencies = true; | ||
} | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
packages/@lwc/compiler/src/__tests__/dynamic-components.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (c) 2018, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
import { compile } from '../index'; | ||
import { readFixture, pretify } from './utils'; | ||
|
||
describe('dynamic imports', () => { | ||
it('external dynamic import works', async () => { | ||
const compilerResult = await compile({ | ||
name: 'dynamic_imports', | ||
namespace: 'x', | ||
files: { | ||
'dynamic_imports.js': readFixture('dynamic_imports/dynamic_imports.js'), | ||
'dynamic_imports.html': readFixture('dynamic_imports/dynamic_imports.html'), | ||
}, | ||
outputConfig: { | ||
compat: false, | ||
format: 'es', | ||
}, | ||
experimentalDynamicComponent: { | ||
loader: '@custom/loader', | ||
strictSpecifier: false, | ||
}, | ||
}); | ||
const { result } = compilerResult; | ||
|
||
expect(pretify(result.code)).toBe(pretify(readFixture('expected-dynamic-component.js'))); | ||
}); | ||
}); |
3 changes: 3 additions & 0 deletions
3
packages/@lwc/compiler/src/__tests__/fixtures/dynamic_imports/dynamic_imports.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<template> | ||
<x-foo lwc:dynamic={customCtor}></x-foo> | ||
</template> |
13 changes: 13 additions & 0 deletions
13
packages/@lwc/compiler/src/__tests__/fixtures/dynamic_imports/dynamic_imports.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { LightningElement, track } from "lwc"; | ||
export default class DynamicCtor extends LightningElement { | ||
@track customCtor; | ||
|
||
connectedCallback() { | ||
this.loadCtor(); | ||
} | ||
|
||
async loadCtor() { | ||
const ctor = await import("foo"); | ||
this.customCtor = ctor; | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
packages/@lwc/compiler/src/__tests__/fixtures/expected-dynamic-component.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { registerTemplate, registerComponent, LightningElement, registerDecorators } from 'lwc'; | ||
import { load } from '@custom/loader'; | ||
|
||
function tmpl($api, $cmp, $slotset, $ctx) { | ||
const { | ||
dc: api_dynamic_component, | ||
f: api_flatten | ||
} = $api; | ||
return api_flatten([api_dynamic_component("x-foo", $cmp.customCtor, { | ||
context: { | ||
lwc: {} | ||
}, | ||
key: 0 | ||
}, [])]); | ||
} | ||
var _tmpl = registerTemplate(tmpl); | ||
tmpl.stylesheets = []; | ||
tmpl.stylesheetTokens = { | ||
hostAttribute: "x-dynamic_imports_dynamic_imports-host", | ||
shadowAttribute: "x-dynamic_imports_dynamic_imports" | ||
}; | ||
class DynamicCtor extends LightningElement { | ||
constructor(...args) { | ||
super(...args); | ||
this.customCtor = void 0; | ||
} | ||
connectedCallback() { | ||
this.loadCtor(); | ||
} | ||
async loadCtor() { | ||
const ctor = await load("foo"); | ||
this.customCtor = ctor; | ||
} | ||
} | ||
registerDecorators(DynamicCtor, { | ||
track: { | ||
customCtor: 1 | ||
} | ||
}); | ||
var dynamic_imports = registerComponent(DynamicCtor, { | ||
tmpl: _tmpl | ||
}); | ||
export default dynamic_imports; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.