diff --git a/packages/react/import-component/mixin.core.js b/packages/react/import-component/mixin.core.js index 2582c6594..b46527c91 100644 --- a/packages/react/import-component/mixin.core.js +++ b/packages/react/import-component/mixin.core.js @@ -2,10 +2,10 @@ const { Mixin } = require('hops-mixin'); class ImportComponentCoreMixin extends Mixin { configureBuild(webpackConfig, { jsLoaderConfig }) { - jsLoaderConfig.options.plugins.push([ - require.resolve('../lib/babel'), - { module: 'hops' }, - ]); + // jsLoaderConfig.options.plugins.push([ + // require.resolve('../lib/babel'), + // { module: 'hops' }, + // ]); } } diff --git a/packages/template-react/src/app.js b/packages/template-react/src/app.js index f9534993f..759c363c0 100644 --- a/packages/template-react/src/app.js +++ b/packages/template-react/src/app.js @@ -1,8 +1,9 @@ -import { Miss, render } from 'hops'; +import { importComponent, Miss, render } from 'hops'; import React from 'react'; import { Link, Route, Switch } from 'react-router-dom'; -import Counter from './counter'; -import Home from './home'; + +const Home = importComponent(() => import('./home')); +const Counter = importComponent(() => import('./counter')); const App = () => (
diff --git a/packages/webpack/lib/configs/build.js b/packages/webpack/lib/configs/build.js index b08aa470b..5b0c362a6 100644 --- a/packages/webpack/lib/configs/build.js +++ b/packages/webpack/lib/configs/build.js @@ -8,6 +8,7 @@ const { const TerserPlugin = require('terser-webpack-plugin'); const { join, trimSlashes } = require('pathifist'); const getModules = require('../utils/modules'); +const ImportComponentPlugin = require('../plugins/import-component'); const { ModuleConcatenationPlugin } = optimize; @@ -138,6 +139,7 @@ module.exports = function getConfig(config, name) { new (isProduction ? HashedModuleIdsPlugin : NamedModulesPlugin)(), new ModuleConcatenationPlugin(), new EnvironmentPlugin({ NODE_ENV: 'development' }), + new ImportComponentPlugin(), ], performance: { hints: false, diff --git a/packages/webpack/lib/plugins/import-component.js b/packages/webpack/lib/plugins/import-component.js new file mode 100644 index 000000000..31c2153ad --- /dev/null +++ b/packages/webpack/lib/plugins/import-component.js @@ -0,0 +1,94 @@ +const BasicEvaluatedExpression = require('webpack/lib/BasicEvaluatedExpression'); +const Dependency = require('webpack/lib/Dependency'); +const { builders } = require('ast-types'); + +/** @typedef {import('webpack').Compiler} Compiler */ +/** @typedef {import('webpack').javascript['JavascriptParser']} JavascriptParser */ + +class ImportComponentDependency extends Dependency { + constructor(range) { + super(); + this.range = range; + } + + updateHash(hash) { + hash.update('ImportComponentDependency'); + } +} + +ImportComponentDependency.Template = class ImportComponentDependencyTemplate { + apply(dep, source, runtime) { + console.log({ dep, source, runtime }); + // const moduleId = runtime.moduleId({ + // module: dep._module, + // request: dep._request, + // }); + source.replace( + dep.range[0], + dep.range[1], + 'importComponent({ load() {} })' + ); + } +}; + +module.exports = class ImportComponentPlugin { + apply(/** @type {Compiler} */ compiler) { + const pluginName = this.constructor.name; + + compiler.hooks.compilation.tap(pluginName, (compilation) => { + compilation.dependencyTemplates.set( + ImportComponentDependency, + new ImportComponentDependency.Template() + ); + }); + + compiler.hooks.normalModuleFactory.tap(pluginName, (factory) => { + factory.hooks.parser.for('javascript/auto').tap(pluginName, ( + /** @type {InstanceType} */ parser + ) => { + parser.hooks.evaluate + .for('Identifier') + .tap({ name: pluginName, before: 'Parser' }, (node) => { + if (node.name === 'importComponent') { + console.log(node); + const expression = new BasicEvaluatedExpression(); + expression.setRange(node.range); + expression.setExpression(node); + expression.setIdentifier(node.name); + + return expression; + } + }); + + parser.hooks.evaluateIdentifier + .for('imported var') + .tap({ name: pluginName, before: 'Parser' }, (node) => { + if (node.name === 'importComponent') { + const expression = new BasicEvaluatedExpression(); + expression.setRange(node.range); + expression.setExpression(node); + expression.setIdentifier(node.name); + + return expression; + } + }); + + parser.hooks.call + .for('importComponent') + .tap({ name: pluginName, before: 'Parser' }, (node) => { + if (node.type === 'CallExpression') { + parser.state.module.addDependency( + new ImportComponentDependency(node.range) + ); + // node.arguments[0] = builders.objectExpression([ + // builders.objectProperty( + // builders.identifier('load'), + // builders.stringLiteral('testhelloworld') + // ), + // ]); + } + }); + }); + }); + } +}; diff --git a/packages/webpack/package.json b/packages/webpack/package.json index 1d1542b96..60c6b0346 100644 --- a/packages/webpack/package.json +++ b/packages/webpack/package.json @@ -8,6 +8,7 @@ "@babel/core": "^7.9.0", "@babel/preset-env": "^7.9.5", "babel-loader": "^8.1.0", + "ast-types": "^0.14.2", "caniuse-lite": "^1.0.30000898", "chalk": "^4.0.0", "core-js": "^3.2.1", diff --git a/yarn.lock b/yarn.lock index 0280b051c..e770c817f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3696,6 +3696,13 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-types@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" + integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== + dependencies: + tslib "^2.0.1" + astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -13465,7 +13472,7 @@ tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@~2.1.0: +tslib@^2.0.1, tslib@^2.0.3, tslib@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==