从零开始一个前端脚手架(二)

445 阅读2分钟

上一节中,已经把基础环境搭建好了,这里就陆续实现各指令。首先我们从打包开始,毕竟能够打包编译js代码,这应该是一个脚手架工具最基础的功能。

webpack配置

webpack基础配置

新建文件src/webpack/config.com.js,该文件存放公用的webpack配置:

import jsLoader from '../babel/jsLoader'
import plugin from '../babel/plugin'
const path = require('path')
export default (props) => {
  const {
    entry = './index.js'
  } = props
  return {
    entry,
    output: {
      path: path.join(process.cwd(), 'dist'),  //输出路径
      filename: 'bundle.js'
    },
    resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.vue'],
    },
    module: {
      rules: [...jsLoader()]   // 解析文件的各种loader
    },
    plugins: [...plugin()]     // 配置一些常用的插件
  }
}

新建文件src/webpack/config.prod.js,存放打包时的配置信息

import commonConfig from './config.com.js'
export default (pkg) => {
  return {
    mode: 'production',            //设置开发模式
    ...commonConfig(pkg)          //各个模式下的公共配置
  }
}

配置loader

先配置babel-loader用以解析js代码 src/babel/jsLoader.js

export default () => {
  return [
    // babel-loader转义js  https://webpack.docschina.org/loaders/babel-loader/#root
    {
      test: /\.m?js$/,
      exclude: /node_modules/,     //不用编译 node_modules
      use: {
        loader: require.resolve('babel-loader'),
        options: {
          presets: [require.resolve('@babel/preset-env')]  
        }
      }
    }
  ]
}

配置plugin

plugin是一些辅助插件, 暂时以配置ProgressPlugin为例,其作用是实时输出打包信息: src/babel/plugin.js

import ProgressPlugin from "progress-bar-webpack-plugin"
export default () => {
  return [new ProgressPlugin()]    // 输出打包进度信息
}

打包配置

src/commander/build.js

import Webpack from 'webpack'
import webpackConfig from '../webpack/config.prod.js'
export default pkg => {
  const compiler = Webpack(webpackConfig(pkg))
  compiler.run((err, status) => {
    if (err) {
      console.log('build err', err)
      process.exit(1)
    }
  })
}

入口文件配置

src/index.js

import build from './commanders/build'
...
// 自定义指令 build
program
    .command('build')
    .description('build program')
    .action(() => {
        build(config)
    })
...

新建文件:demo/index.js,在此目录下执行

simple-cli build

就可以看到输出打包进度信息,并输出结果demo/dist/bundle.js。此时我们最基础的打包指令已经做好了。

优化

交互优化

现有的webpack关键配置,比如entry都是在工具内部写死的,但是一个合理的交互需要提给供用户自定义的能力。我们约定这些配置在用户项目的package.json文件的simple-cli字段下。

cli/src/index.js

...
const cwd = process.cwd()
// 定义默认值
let config = {
    port: 8000,
    entry: './index.js',
    cwd: process.cwd()
}

const userPkgPath = `${cwd}/package.json`   //用户目录下package.json文件路径

// 判断是否存在 package.json
if (fs.existsSync(userPkgPath)) {
    let userConfig = require(userPkgPath).simple_cli || {}
    // 优先使用用户自定义的配置
    config = Object.assign(config, userConfig)
}
...
program
    .command('build')
    .description('build program')
    .action(() => {
        build(config)
    })

打包优化

在生产环境下,我们都是遵循增量部署的原则。这就意味着,每次打包输出的js文件名称都是唯一的,webpack支持带哈希值的输出文件来满足这一要求。

更新src/webpack/config.com.js

...
  output: {
    path: path.join(process.cwd(), 'dist'),   // 输出路径
    filename: 'bundle.[hash].js'
  }
...

此时你会发现每次打包都会生成一个名称类似bundle.1ff2020b12189c7388ec.js的文件。

但是,这样又引入了另一个问题,你的dist目录下存储的文件越来越多,对于本地开发这显然没必要,保留最新的一份就够了。那么有没有一个办法在写入文件之前,先清空dist目录呢。

webpack告诉你,‘有’ 。 借助插件clean-webpack-plugin即可。

更新src/babel/plugin.js

import ProgressPlugin from "progress-bar-webpack-plugin"
import { CleanWebpackPlugin } from 'clean-webpack-plugin'
export default () => {
  return [
    new CleanWebpackPlugin(),   // 清空output目录
    new ProgressPlugin()        // 输出打包进度信息
  ]
}

到这里一个简单的打包js指令已经完成了。其他指令的具体实现,努力更新中。

未完待续

源码地址
从零开始一个前端脚手架(一)
从零开始一个前端脚手架(三)
从零开始一个前端脚手架(四)