diff --git a/.eslintrc.json b/.eslintrc.json index 140148c1..29eea0b7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -7,5 +7,7 @@ "browser": true, "es6": true }, - "extends": "airbnb" + "extends": "airbnb", + "rules": { + } } diff --git a/.gitignore b/.gitignore index 2e6b97bc..ca01ff03 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ index.js corsImport.js polyfill.js react.js +utils.js yarn-error.log diff --git a/.travis.yml b/.travis.yml index 97400d65..cb5ef48b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,5 @@ jobs: script: npx travis-github-status name: Linting script: npm run lint - name: Snyk - script: snyk -#after_success: -# - npm run semantic-release +after_success: + - npm run semantic-release diff --git a/package.json b/package.json index e8a4d2ff..664a287e 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "scripts": { "compile": "babel src -d .", "test": "yarn lint && yarn tsc-test && yarn jest", - "lint": "eslint --ext .js,.ts,.tsx --ignore-pattern dist,node_modules . --fix", + "lint": "eslint --ext .js,.ts,.tsx src --fix", "jest": "NODE_ENV=test jest", "jest:ci": "cross-env NODE_ENV=development jest", "demo:one": "cd manual/Website1; yarn && yarn link webpack-external-import && yarn manual:dev", diff --git a/src/index.js b/src/index.js index 6b1f3cfb..560a7856 100644 --- a/src/index.js +++ b/src/index.js @@ -30,7 +30,7 @@ export const getChunkDependencies = (basePath, nameSpace, module) => { && window?.entryManifest[nameSpace][module].dependencies) { window.entryManifest[nameSpace][module].dependencies.forEach((file) => { if (!__webpack_modules__[file.id]) { - file.sourceFiles.forEach(chunkFile => dependencyPaths.push(basePath + chunkFile)); + file.sourceFiles.forEach((chunkFile) => dependencyPaths.push(basePath + chunkFile)); } }); } else if (window?.entryManifest[nameSpace] @@ -38,7 +38,7 @@ export const getChunkDependencies = (basePath, nameSpace, module) => { && window?.entryManifest[nameSpace][`${module}.js`].dependencies) { window.entryManifest[nameSpace][`${module}.js`].dependencies.forEach((file) => { if (!__webpack_modules__[file.id]) { - file.sourceFiles.forEach(chunkFile => dependencyPaths.push(basePath + chunkFile)); + file.sourceFiles.forEach((chunkFile) => dependencyPaths.push(basePath + chunkFile)); } }); } @@ -47,8 +47,8 @@ export const getChunkDependencies = (basePath, nameSpace, module) => { function getInSequence(array, asyncFunc) { return array.reduce((previous, current) => ( - previous.then(accumulator => ( - asyncFunc(current).then(result => accumulator.concat(result)) + previous.then((accumulator) => ( + asyncFunc(current).then((result) => accumulator.concat(result)) )) ), Promise.resolve([])); } diff --git a/src/react.js b/src/react.js index a92deb84..b485f058 100644 --- a/src/react.js +++ b/src/react.js @@ -1,67 +1,54 @@ -import React, { Component } from 'react'; +import React, { + Component, useCallback, useEffect, useState, +} from 'react'; import PropTypes from 'prop-types'; import './polyfill'; -import { importWithDependencies, importDependenciesOf } from './index'; -class ExternalComponent extends Component { - constructor(props) { - super(props); - - this.state = { - loaded: false, - }; - this.importPromise = this.importPromise.bind(this); - this.Component = null; - } - - importPromise(src) { - if (!src) { - return new Promise((resolve, reject) => { - reject(); +const ExternalComponent = (props) => { + const { + src, module, export: exportName, cors, ...rest + } = props; + let Component = null; + const [loaded, setLoaded] = useState(false); + const importPromise = useCallback( + () => { + if (!src) return Promise.reject(); + if (cors) { + return require('./corsImport').default(src); + } + return new Promise((resolve) => { + resolve(new Function(`return import("${src}")`)()); }); - } - if (this.props.cors) { - return require('./corsImport').default(src); - } + }, + [src, cors], + ); - return new Promise((resolve) => { - resolve(new Function(`return import("${src}")`)()); - }); - } - - componentDidMount() { + useEffect(() => { require('./polyfill'); - - const { src, module, export: exportName } = this.props; if (!src) { - throw new Error(`dynamic-import: no url ${JSON.stringify(this.props, null, 2)}`); + throw new Error(`dynamic-import: no url ${JSON.stringify(props, null, 2)}`); } - this.importPromise(src).then(() => { + importPromise(src).then(() => { const requiredComponent = __webpack_require__(module); - this.Component = requiredComponent.default ? requiredComponent.default : requiredComponent[exportName]; - this.setState({ loaded: true }); + Component = requiredComponent.default ? requiredComponent.default : requiredComponent[exportName]; + setLoaded(true); }).catch((e) => { throw new Error(`dynamic-import: ${e.message}`); }); - } + }, []); - render() { - const { Component } = this; - const { loaded } = this.state; - if (!loaded) return null; - - const { src, module, ...rest } = this.props; - return ( - - ); - } -} + if (!loaded) return null; + return ( + + ); +}; ExternalComponent.propTypes = { src: PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.string]).isRequired, - module: PropTypes.string, + module: PropTypes.string.isRequired, cors: PropTypes.bool, + export: PropTypes.string, }; export default ExternalComponent; diff --git a/src/webpack/index.js b/src/webpack/index.js index a729f290..ebd2f55d 100644 --- a/src/webpack/index.js +++ b/src/webpack/index.js @@ -5,7 +5,7 @@ const fs = require('fs'); function mergeDeep(...objects) { - const isObject = obj => obj && typeof obj === 'object'; + const isObject = (obj) => obj && typeof obj === 'object'; return objects.reduce((prev, obj) => { Object.keys(obj).forEach((key) => { @@ -60,10 +60,9 @@ function hasExternalizedModule(module) { return false; } -const interleaveConfig = test => ({ +const interleaveConfig = (test) => ({ test(module) { if (module.resource) { - console.log(test, module.resource.includes(test), !!hasExternalizedModule(module)); return module.resource.includes(test) && !!hasExternalizedModule(module); } }, @@ -97,7 +96,7 @@ class URLImportPlugin { ); } - this.opts = Object.assign({ + this.opts = { publicPath: null, debug: debug || false, testPath: 'src', @@ -115,12 +114,13 @@ class URLImportPlugin { context: null, sort: null, hashFunction: 'md4', - serialize: manifest => `if(!window.entryManifest) {window.entryManifest = {}}; window.entryManifest["${opts.manifestName}"] = ${JSON.stringify( + serialize: (manifest) => `if(!window.entryManifest) {window.entryManifest = {}}; window.entryManifest["${opts.manifestName}"] = ${JSON.stringify( manifest, null, 2, )}`, - }, opts || {}); + ...opts || {}, + }; } getFileType(str) { @@ -281,7 +281,6 @@ class URLImportPlugin { if (module && module.files) { if (dependencyChains[chunk.id]) { - // console.log({ files: module.files }); dependencyChainMap.sourceFiles = dependencyChainMap?.sourceFiles?.concat?.(module.files) || null; } else { // Object.assign(dependencyChains, { [chunk.id]: module.files }); diff --git a/utils.js b/utils.js new file mode 100644 index 00000000..15c0de64 --- /dev/null +++ b/utils.js @@ -0,0 +1,113 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.importDependenciesOf = exports.importWithDependencies = exports.getChunkDependencies = exports.getChunkPath = void 0; + +var _isUrlSuperb = _interopRequireDefault(require("is-url-superb")); + +var _corsImport = _interopRequireDefault(require("./corsImport")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +var getChunkPath = function getChunkPath(basePath, nameSpace, module) { + var _window, _window2, _window3, _window4, _window5, _window6; + + if (!window.entryManifest) return; + if (!nameSpace) return; + if (!window.entryManifest[nameSpace]) return; + var pathString = []; + + if (((_window = window) === null || _window === void 0 ? void 0 : _window.entryManifest[nameSpace]) && ((_window2 = window) === null || _window2 === void 0 ? void 0 : _window2.entryManifest[nameSpace][module]) && ((_window3 = window) === null || _window3 === void 0 ? void 0 : _window3.entryManifest[nameSpace][module].path)) { + pathString = [basePath, window.entryManifest[nameSpace][module].path]; + } else if (((_window4 = window) === null || _window4 === void 0 ? void 0 : _window4.entryManifest[nameSpace]) && ((_window5 = window) === null || _window5 === void 0 ? void 0 : _window5.entryManifest[nameSpace]["".concat(module, ".js")]) && ((_window6 = window) === null || _window6 === void 0 ? void 0 : _window6.entryManifest[nameSpace]["".concat(module, ".js")].path)) { + pathString = [basePath, window.entryManifest[nameSpace]["".concat(module, ".js")].path]; + } + + return pathString.join(''); +}; + +exports.getChunkPath = getChunkPath; + +var getChunkDependencies = function getChunkDependencies(basePath, nameSpace, module) { + var _window7, _window8, _window9, _window11, _window12, _window13; + + if (!window.entryManifest) return; + if (!nameSpace) return; + if (!window.entryManifest[nameSpace]) return; + var dependencyPaths = []; + + if (((_window7 = window) === null || _window7 === void 0 ? void 0 : _window7.entryManifest[nameSpace]) && ((_window8 = window) === null || _window8 === void 0 ? void 0 : _window8.entryManifest[nameSpace][module]) && ((_window9 = window) === null || _window9 === void 0 ? void 0 : _window9.entryManifest[nameSpace][module].dependencies)) { + window.entryManifest[nameSpace][module].dependencies.forEach(function (file) { + if (!__webpack_modules__[file.id]) { + file.sourceFiles.forEach(function (chunkFile) { + var _window10; + + return dependencyPaths.push(basePath + ((_window10 = window) === null || _window10 === void 0 ? void 0 : _window10.entryManifest[nameSpace][chunkFile].path)); + }); + } + }); + } else if (((_window11 = window) === null || _window11 === void 0 ? void 0 : _window11.entryManifest[nameSpace]) && ((_window12 = window) === null || _window12 === void 0 ? void 0 : _window12.entryManifest[nameSpace]["".concat(module, ".js")]) && ((_window13 = window) === null || _window13 === void 0 ? void 0 : _window13.entryManifest[nameSpace]["".concat(module, ".js")].dependencies)) { + window.entryManifest[nameSpace]["".concat(module, ".js")].dependencies.forEach(function (file) { + if (!__webpack_modules__[file.id]) { + file.sourceFiles.forEach(function (chunkFile) { + var _window14; + + return dependencyPaths.push(basePath + ((_window14 = window) === null || _window14 === void 0 ? void 0 : _window14.entryManifest[nameSpace][chunkFile].path)); + }); + } + }); + } + + return Array.from(new Set(dependencyPaths)); +}; + +exports.getChunkDependencies = getChunkDependencies; + +function getInSequence(array, asyncFunc) { + return array.reduce(function (previous, current) { + return previous.then(function (accumulator) { + return asyncFunc(current).then(function (result) { + return accumulator.concat(result); + }); + }); + }, Promise.resolve([])); +} + +var nativeImport = function nativeImport(src) { + return new Promise(function (resolve, reject) { + if ((0, _isUrlSuperb["default"])(src)) { + resolve(new Function("return import(\"".concat(src, "\")"))()); + } else { + reject('webpack-external-import: nativeImport - invalid URL'); + } + }); +}; + +var importWithDependencies = function importWithDependencies(basePath, nameSpace, module) { + var cors = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + if (!window.entryManifest) return; + if (!nameSpace) return; + if (!window.entryManifest[nameSpace]) return; + var importFunction = cors ? nativeImport : _corsImport["default"]; + return getInSequence(getChunkDependencies(basePath, nameSpace, module), importFunction).then(function () { + return importFunction(getChunkPath(basePath, nameSpace, module)); + }); +}; + +exports.importWithDependencies = importWithDependencies; + +var importDependenciesOf = function importDependenciesOf(basePath, nameSpace, module) { + var cors = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + if (!window.entryManifest) return; + if (!nameSpace) return; + if (!window.entryManifest[nameSpace]) return; + var importFunction = cors ? nativeImport : _corsImport["default"]; + return getInSequence(getChunkDependencies(basePath, nameSpace, module), importFunction).then(function () { + return getChunkPath(basePath, nameSpace, module); + }); // window.entryManifest[nameSpace][module] + // console.log('import with deps:') +}; + +exports.importDependenciesOf = importDependenciesOf; \ No newline at end of file