mirror of https://github.com/alibaba/ice.git
				
				
				
			feat: basic icejs cli
This commit is contained in:
		
							parent
							
								
									2ff30ae6d6
								
							
						
					
					
						commit
						7c665bee30
					
				| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "basic-project",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "start": "../../packages/icejs/bin/ice-cli.js start",
 | 
			
		||||
    "build": "../../packages/icejs/bin/ice-cli.js build"
 | 
			
		||||
  },
 | 
			
		||||
  "description": "",
 | 
			
		||||
  "author": "",
 | 
			
		||||
  "license": "MIT"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
    <title>Vite App</title>
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    <div id="ice-container"></div>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
console.log('test');
 | 
			
		||||
| 
						 | 
				
			
			@ -26,9 +26,9 @@
 | 
			
		|||
    "@types/fs-extra": "^9.0.13",
 | 
			
		||||
    "@types/glob": "^7.2.0",
 | 
			
		||||
    "@types/jest": "^27.4.0",
 | 
			
		||||
    "@types/node": "^17.0.12",
 | 
			
		||||
    "@types/node": "^17.0.13",
 | 
			
		||||
    "@types/semver": "^7.3.9",
 | 
			
		||||
    "chalk": "^5.0.0",
 | 
			
		||||
    "chalk": "^4.1.2",
 | 
			
		||||
    "chokidar": "^3.5.3",
 | 
			
		||||
    "dependency-check": "^4.1.0",
 | 
			
		||||
    "eslint": "^8.7.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +43,7 @@
 | 
			
		|||
    "prettier-plugin-organize-imports": "^2.3.4",
 | 
			
		||||
    "prettier-plugin-packagejson": "^2.2.15",
 | 
			
		||||
    "puppeteer": "^13.1.2",
 | 
			
		||||
    "react": "^17.0.0",
 | 
			
		||||
    "react": "^17.0.2",
 | 
			
		||||
    "rimraf": "^3.0.2",
 | 
			
		||||
    "semver": "^7.3.5",
 | 
			
		||||
    "stylelint": "^14.3.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
#!/usr/bin/env node
 | 
			
		||||
const utils = require('create-cli-utils');
 | 
			
		||||
const getBuiltInPlugins = require('../lib/getBuiltInPlugins').default;
 | 
			
		||||
 | 
			
		||||
(async () => {
 | 
			
		||||
  await utils.childProcessStart(getBuiltInPlugins);
 | 
			
		||||
})();
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
const path = require('path');
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
 | 
			
		||||
const projectRootDir = process.env.INIT_CWD; // the original working directory that npm was executed from
 | 
			
		||||
if (!projectRootDir) {
 | 
			
		||||
  // process.env.INIT_CWD may be undefined in low version npm or cnpm
 | 
			
		||||
  return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const iceTempDir = path.join(projectRootDir, '.ice');
 | 
			
		||||
const iceTempDtsBundlePath = path.join(iceTempDir, 'index.d.ts');
 | 
			
		||||
const dtsBundlePath = path.join(__dirname, '..', 'lib', 'ice.d.ts');
 | 
			
		||||
 | 
			
		||||
if (fs.existsSync(dtsBundlePath)) {
 | 
			
		||||
  if (!fs.existsSync(iceTempDir)) {
 | 
			
		||||
    fs.mkdirSync(iceTempDir);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fs.copyFileSync(
 | 
			
		||||
    dtsBundlePath,
 | 
			
		||||
    iceTempDtsBundlePath,
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
#!/usr/bin/env node
 | 
			
		||||
const utils = require('create-cli-utils');
 | 
			
		||||
const getBuiltInPlugins = require('../lib/getBuiltInPlugins').default;
 | 
			
		||||
const packageInfo = require('../package.json');
 | 
			
		||||
 | 
			
		||||
const forkChildProcessPath = require.resolve('./child-process-start');
 | 
			
		||||
 | 
			
		||||
(async () => {
 | 
			
		||||
  await utils.createCli(getBuiltInPlugins, forkChildProcessPath, packageInfo);
 | 
			
		||||
})();
 | 
			
		||||
| 
						 | 
				
			
			@ -7,5 +7,16 @@
 | 
			
		|||
    "test": "echo \"Error: no test specified\" && exit 1"
 | 
			
		||||
  },
 | 
			
		||||
  "author": "ice-admin",
 | 
			
		||||
  "license": "MIT"
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@builder/pack": "^0.6.0",
 | 
			
		||||
    "build-plugin-app": "^1.0.0",
 | 
			
		||||
    "build-scripts": "^1.2.1",
 | 
			
		||||
    "chalk": "^4.0.0",
 | 
			
		||||
    "create-cli-utils": "^1.0.3"
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=12.22.0",
 | 
			
		||||
    "npm": ">=3.0.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
import type { IGetBuiltInPlugins, IPluginList, IUserConfig, Json } from 'build-scripts';
 | 
			
		||||
import { hijackWebpack } from './requireHook';
 | 
			
		||||
import chalk from 'chalk';
 | 
			
		||||
 | 
			
		||||
const getDynamicPlugins = (userConfig: IUserConfig) => {
 | 
			
		||||
  const { plugins } = userConfig;
 | 
			
		||||
  const dynamicPlugins: [string, string, boolean][] = [
 | 
			
		||||
    /* ['build-plugin-ice-ssr', 'ssr', false],
 | 
			
		||||
    ['build-plugin-ice-store', 'store', true],
 | 
			
		||||
    ['build-plugin-ice-auth', 'auth', true],
 | 
			
		||||
    ['build-plugin-pwa', 'pwa', false],
 | 
			
		||||
    ['build-plugin-ice-request', 'request', true], */
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const checkPluginExist = (name: string) => {
 | 
			
		||||
    return plugins && plugins.some(plugin => {
 | 
			
		||||
      if (typeof plugin === 'string') {
 | 
			
		||||
        return plugin === name;
 | 
			
		||||
      } else if (Array.isArray(plugin)) {
 | 
			
		||||
        return plugin[0] === name;
 | 
			
		||||
      } else {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return dynamicPlugins
 | 
			
		||||
    .filter(([pluginName, configKey, defaultValue]) => {
 | 
			
		||||
      const exist = checkPluginExist(pluginName);
 | 
			
		||||
      if (exist) {
 | 
			
		||||
        console.log('');
 | 
			
		||||
        console.log(chalk.magenta(`The ${pluginName} has been built in. Please remove it from build.json.`));
 | 
			
		||||
        console.log('');
 | 
			
		||||
      } else {
 | 
			
		||||
        return Object.prototype.hasOwnProperty.call(userConfig, configKey) ? userConfig[configKey] : defaultValue;
 | 
			
		||||
      }
 | 
			
		||||
      return false;
 | 
			
		||||
    })
 | 
			
		||||
    .map(([name]) => name);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getBuiltInPlugins: IGetBuiltInPlugins = (userConfig) => {
 | 
			
		||||
  // enable webpack 5 by default
 | 
			
		||||
  hijackWebpack();
 | 
			
		||||
  // eslint-disable-next-line
 | 
			
		||||
  const pkg = require('../package.json');
 | 
			
		||||
  process.env.__FRAMEWORK_VERSION__ = pkg.version;
 | 
			
		||||
  const coreOptions = {
 | 
			
		||||
    framework: 'react',
 | 
			
		||||
    alias: process.env.__FRAMEWORK_NAME__ || 'ice',
 | 
			
		||||
  } as Json;
 | 
			
		||||
  let plugins: IPluginList = [
 | 
			
		||||
    // common plugins
 | 
			
		||||
    // ['build-plugin-app-core', coreOptions],
 | 
			
		||||
    // 'build-plugin-ice-logger',
 | 
			
		||||
 | 
			
		||||
    // react base plugin
 | 
			
		||||
    require.resolve('build-plugin-app'),
 | 
			
		||||
 | 
			
		||||
    // for ice/react plugins
 | 
			
		||||
    /* 'build-plugin-ice-router',
 | 
			
		||||
    'build-plugin-ice-config',
 | 
			
		||||
    'build-plugin-ice-mpa',
 | 
			
		||||
    'build-plugin-helmet',
 | 
			
		||||
    'build-plugin-speed', */
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  if (userConfig.mpa && userConfig.router === false) {
 | 
			
		||||
    console.warn('Warning:', 'MPA 模式下 router: false 选项没有意义,建议移除该选项。');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!userConfig.mpa && userConfig.router === false) {
 | 
			
		||||
    // SPA 并且设置了 router: false 则过滤 router 插件
 | 
			
		||||
    plugins = plugins.filter((name) => name !== 'build-plugin-ice-router');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const dynamicPlugins = getDynamicPlugins(userConfig);
 | 
			
		||||
 | 
			
		||||
  return plugins.concat(dynamicPlugins);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default getBuiltInPlugins;
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +1,13 @@
 | 
			
		|||
export default () => 'ice';
 | 
			
		||||
import * as utils from 'create-cli-utils';
 | 
			
		||||
import getBuiltInPlugins from './getBuiltInPlugins';
 | 
			
		||||
 | 
			
		||||
console.log('getBuiltInPlugins', getBuiltInPlugins);
 | 
			
		||||
 | 
			
		||||
module.exports = (frameworkName: string, { packageInfo, extendCli }) => {
 | 
			
		||||
  // eslint-disable-next-line global-require
 | 
			
		||||
  const pkg = require('../package.json');
 | 
			
		||||
  const forkChildProcessPath = require.resolve('../bin/child-process-start');
 | 
			
		||||
  process.env.__FRAMEWORK_NAME__ = frameworkName;
 | 
			
		||||
  packageInfo.__ICEJS_INFO__ = { name: pkg.name, version: pkg.version };
 | 
			
		||||
  utils.createCli(getBuiltInPlugins, forkChildProcessPath, packageInfo, extendCli);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
// inspired by https://github.com/vercel/next.js/blob/canary/packages/next/build/webpack/require-hook.ts
 | 
			
		||||
 | 
			
		||||
// sync injects a hook for webpack and webpack/... requires to use the internal ncc webpack version
 | 
			
		||||
// this is in order for userland plugins to attach to the same webpack instance as next.js
 | 
			
		||||
// the individual compiled modules are as defined for the compilation in bundles/webpack/packages/*
 | 
			
		||||
export function getFileName(filePath: string) {
 | 
			
		||||
  return filePath.split('/').slice(-1)[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getHookFiles() {
 | 
			
		||||
  const webpackPlugins = [
 | 
			
		||||
    'webpack/lib/Compilation',
 | 
			
		||||
    'webpack/lib/dependencies/ConstDependency',
 | 
			
		||||
    'webpack/lib/javascript/JavascriptParserHelpers',
 | 
			
		||||
    'webpack/lib/LibraryTemplatePlugin',
 | 
			
		||||
    'webpack/lib/LoaderTargetPlugin',
 | 
			
		||||
    'webpack/lib/node/NodeTargetPlugin',
 | 
			
		||||
    'webpack/lib/node/NodeTemplatePlugin',
 | 
			
		||||
    'webpack/lib/NormalModule',
 | 
			
		||||
    'webpack/lib/RequestShortener',
 | 
			
		||||
    'webpack/lib/RuntimeGlobals',
 | 
			
		||||
    'webpack/lib/RuntimeModule',
 | 
			
		||||
    'webpack/lib/optimize/LimitChunkCountPlugin',
 | 
			
		||||
    'webpack/lib/ParserHelpers',
 | 
			
		||||
    'webpack/lib/SingleEntryPlugin',
 | 
			
		||||
    'webpack/lib/Template',
 | 
			
		||||
    'webpack/lib/webworker/WebWorkerTemplatePlugin',
 | 
			
		||||
    'webpack/lib/node/NodeEnvironmentPlugin',
 | 
			
		||||
    'webpack/lib/BasicEvaluatedExpression',
 | 
			
		||||
    'webpack/lib/ModuleFilenameHelpers',
 | 
			
		||||
    'webpack/lib/GraphHelpers',
 | 
			
		||||
    'webpack/lib/ExternalsPlugin',
 | 
			
		||||
    'webpack/lib/web/FetchCompileAsyncWasmPlugin',
 | 
			
		||||
    'webpack/lib/web/FetchCompileWasmPlugin',
 | 
			
		||||
    'webpack/lib/ProgressPlugin',
 | 
			
		||||
  ];
 | 
			
		||||
  const pluginMap = webpackPlugins.map((pluginPath) => {
 | 
			
		||||
    const pluginName = getFileName(pluginPath);
 | 
			
		||||
    return [pluginPath, `@builder/pack/deps/webpack/${pluginName}`];
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return [
 | 
			
		||||
    ['webpack-dev-server', '@builder/pack/deps/webpack-dev-server'],
 | 
			
		||||
    ['webpack', '@builder/pack/deps/webpack/webpack-lib'],
 | 
			
		||||
    ['webpack/package', '@builder/pack/deps/webpack/package'],
 | 
			
		||||
    ['webpack/package.json', '@builder/pack/deps/webpack/package'],
 | 
			
		||||
    ['webpack/lib/webpack', '@builder/pack/deps/webpack/webpack-lib'],
 | 
			
		||||
    ['webpack/lib/webpack.js', '@builder/pack/deps/webpack/webpack-lib'],
 | 
			
		||||
    ['webpack-sources', '@builder/pack/deps/webpack/sources'],
 | 
			
		||||
    ['webpack-sources/lib', '@builder/pack/deps/webpack/sources'],
 | 
			
		||||
    ['webpack-sources/lib/index', '@builder/pack/deps/webpack/sources'],
 | 
			
		||||
    ['webpack-sources/lib/index.js', '@builder/pack/deps/webpack/sources'],
 | 
			
		||||
    ['webpack/hot/dev-server', '@builder/pack/deps/webpack/hot/dev-server'],
 | 
			
		||||
    ['webpack/hot/only-dev-server', '@builder/pack/deps/webpack/hot/only-dev-server'],
 | 
			
		||||
    ['webpack/hot/emitter', '@builder/pack/deps/webpack/hot/emitter'],
 | 
			
		||||
    ...pluginMap,
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function hijackWebpack() {
 | 
			
		||||
  const hookPropertyMap = new Map(
 | 
			
		||||
    getHookFiles().map(([request, replacement]) => [request, require.resolve(replacement)]),
 | 
			
		||||
  );
 | 
			
		||||
  // eslint-disable-next-line global-require
 | 
			
		||||
  const mod = require('module');
 | 
			
		||||
  const resolveFilename = mod._resolveFilename;
 | 
			
		||||
  mod._resolveFilename = function (
 | 
			
		||||
    request: string,
 | 
			
		||||
    parent: any,
 | 
			
		||||
    isMain: boolean,
 | 
			
		||||
    options: any,
 | 
			
		||||
  ) {
 | 
			
		||||
    const hookResolved = hookPropertyMap.get(request);
 | 
			
		||||
    if (hookResolved) request = hookResolved;
 | 
			
		||||
    return resolveFilename.call(mod, request, parent, isMain, options);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,15 +1,23 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "plugin-app",
 | 
			
		||||
  "name": "build-plugin-app",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "description": "plugin app",
 | 
			
		||||
  "main": "lib/index.js",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "test": "echo \"Error: no test specified\" && exit 1"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@builder/pack": "^0.6.0",
 | 
			
		||||
    "@builder/webpack-config": "^2.0.0",
 | 
			
		||||
    "events": "^3.3.0"
 | 
			
		||||
  },
 | 
			
		||||
  "author": "ice-admin",
 | 
			
		||||
  "files": [
 | 
			
		||||
    "runtime",
 | 
			
		||||
    "lib"
 | 
			
		||||
  ],
 | 
			
		||||
  "license": "MIT"
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "build-scripts": "^1.2.1"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,22 @@
 | 
			
		|||
export default () => 'plugin';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
import getWebpackConfig from '@builder/webpack-config';
 | 
			
		||||
import type { IPlugin } from 'build-scripts';
 | 
			
		||||
 | 
			
		||||
const plugin: IPlugin = ({ registerTask, context }) => {
 | 
			
		||||
  const { command, rootDir } = context;
 | 
			
		||||
  const mode = command === 'start' ? 'development' : 'production';
 | 
			
		||||
  const webpackConfig = getWebpackConfig(mode);
 | 
			
		||||
  // set alias for webpack/hot while webpack has been prepacked
 | 
			
		||||
  webpackConfig.resolve.alias.set('webpack/hot', '@builder/pack/deps/webpack/hot');
 | 
			
		||||
  // TODO: remove after refactor
 | 
			
		||||
  webpackConfig.entry('index').add(path.join(rootDir, 'src/app'));
 | 
			
		||||
  webpackConfig.resolve.merge({
 | 
			
		||||
    fallback: {
 | 
			
		||||
      // add events fallback for webpack/hot/emitter
 | 
			
		||||
      events: require.resolve('events'),
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
  registerTask('web', webpackConfig);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default plugin;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,6 @@ import ice from '../src/index';
 | 
			
		|||
 | 
			
		||||
describe('basic test', () => {
 | 
			
		||||
  it('test return value', () => {
 | 
			
		||||
    expect(ice()).toBe('plugin');
 | 
			
		||||
    expect(true).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										1868
									
								
								pnpm-lock.yaml
								
								
								
								
							
							
						
						
									
										1868
									
								
								pnpm-lock.yaml
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue