编写一个基于webpack的React打包工具(6)

218 阅读2分钟

buildpackagets.js

const { spawn } = require('child_process');
const path = require('path');
const { getEnv } = require('./util');

// 运行脚本的路径
const runtimePath = process.cwd();
// 脚本所在的路径
const codePath = __dirname;
const commandPath = path.join(codePath, 'node_modules', '.bin', path.sep);

// buildpackage生成的目录名称
const generateDirName = 'lib';
// buildpackage原始名称
const srcDirName = 'src';

// 代码输出路径
const outputPath = path.join(runtimePath, generateDirName);

// 代码编译路径
let compilePath;

let index = 0;
// buildpackage的所有任务
const tasks = [
  // 清除生成目录
  clearTask,
  // tsc转换,转换typescript
  tscTask,
  // 样式
  gulpTask,
];

/**
 * clearTask
 * 清除输出目录
 * @return {Promise}
 */
function clearTask() {
  return new Promise((resolve, reject) => {
    const command = process.platform === 'win32' ? `rimraf.cmd` : `rimraf`;
    const rimrafProcess = spawn(command, [outputPath], {
      cwd: codePath,
      encoding: 'utf-8',
      env: getEnv(commandPath),
    });

    rimrafProcess.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });

    rimrafProcess.stderr.on('data', (data) => {
      console.log(`stderr: ${data}`);
    });

    rimrafProcess.on('close', (code) => {
      console.log(`rimrafClose:${code}`);
      resolve();
    });
  });
}

/**
 * tscTask
 * 转换src到lib
 * @return {Promise}
 */
function tscTask() {
  return new Promise((resolve, reject) => {
    const command = process.platform === 'win32' ? `tsc.cmd` : `tsc`;
    const tscProcess = spawn(command, ['-p', runtimePath], {
      cwd: codePath,
      encoding: 'utf-8',
      env: getEnv(commandPath),
    });

    tscProcess.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });

    tscProcess.stderr.on('data', (data) => {
      console.log(`stderr: ${data}`);
    });

    tscProcess.on('close', (code) => {
      console.log(`tscClose:${code}`);
      resolve();
    });
  });
}

/**
 * gulpTask
 * @return {Promise}
 */
function gulpTask() {
  return new Promise((resolve, reject) => {
    const command = process.platform === 'win32' ? `gulp.cmd` : `gulp`;
    const gulpProcess = spawn(
      command,
      [
        '--outputpath',
        // 输出路径
        path.join(outputPath, path.sep),
        '--compilepath',
        // 编译目录
        path.join(compilePath, path.sep),
      ],
      {
        cwd: codePath,
        encoding: 'utf-8',
        env: getEnv(commandPath),
      },
    );

    gulpProcess.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });

    gulpProcess.stderr.on('data', (data) => {
      console.log(`stderr: ${data}`);
    });

    gulpProcess.on('close', (code) => {
      console.log(`gulpTaskClose:${code}`);
      resolve();
    });
  });
}

/**
 * loopTask
 * @return {Promise}
 */
function loopTask() {
  return new Promise((resolve, reject) => {
    if (index >= tasks.length) {
      resolve();
    } else {
      const task = tasks[index++];
      if (task) {
        task()
          .then(() => {
            loopTask().then(() => {
              resolve();
            });
          })
          .catch((error) => {
            reject(error);
          });
      } else {
        reject();
      }
    }
  });
}

module.exports = {
  /**
   * build
   * @param {String} - srcPath
   */
  build(srcPath) {
    if (srcPath) {
      // 指定了编译目录

      if (path.isAbsolute(srcPath)) {
        // 是绝对路径
        compilePath = srcPath;
      } else {
        // 是相对路径
        compilePath = path.join(runtimePath, srcPath);
      }
    } else {
      // 没有指定编译目录
      compilePath = path.join(runtimePath, srcDirName);
    }

    loopTask()
      .then(() => {
        console.log('finish');
        process.exit();
      })
      .catch((error) => {
        console.log(error);
      });
  },
};

和buildpackage.js差不多,只是buildpackage.js使用babel进行js和jsx文件的编译,而这里使用的是tsc命令进行js、jsx、ts和tsx文件的编译,tsc命令是typescript提供的,这里使用了-p参数指定了查找tsconfig.js文件的上下文路径,剩余的操作和buildpackage.js是一致的。为了让用户配置typescript方便,这里还提供了一个默认的typescript配置文件,宿主工程可以引用这个基础的配置文件

{
  "compilerOptions": {
    "declaration": true,
    "noImplicitAny": false,
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react",
    "paths": {
      "*": ["types/*"]
    }
  }
}

   github