从零搭建webpack4打包工具

webpack

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。

四大核心概念
  • entry(入口)
  • output(输出)
  • loader(用于对模块的源代码进行转换)
  • plugins(插件)

dev.server

  // https://webpack.js.org/configuration/dev-server/#devserver
  module.exports = {
    devServer: {
      open: false, // 是否自动开启
      hot: true, // 开启热更新
      compress: false, // 是否开启压缩
      host: process.env.HOST || 'localhost',
      port: process.env.PORT || 8088,
      // contentBase: './src',
      proxy: {
        '/api': {
          target: targets[PROXY_ENV],
          changeOrigin: true // 默认值:false,为true时发送请求头中host会设置成target
        }
      }
    }
  }

webpack.base

使用更快的loader、使用多线程happypack、fast-sass-loader替代sass-loader

css文件打包
css文件的打包需要用到css-loader和style-loader两个loader
  css-loader:只是用于加载css文件(并没有添加到页面)。
  style-loader:则是将打包后的css代码以<style>标签形式添加到页面头部。
  module: {
    rules: [  
      {
        test: /\.css$/,   // 正则表达式,表示.css后缀的文件
        use: ['style-loader', 'css-loader']   // 针对css文件使用的loader,注意有先后顺序,数组项越靠后越先执行
      }
    ]
  }
happyPack

happypack可以将任务分解给多个子进程,最后将结果发给主进程,js是单线程模型,通过这种多线程的方式提高性能。

// 在module的rules中
{
  test: /\.js$/,
  use: [
    isProduction ? 'happypack/loader?id=happyBabel' : 'babel-loader'
  ],
  exclude: '/node_modules/',
  include: path.resolve('../src')
}

// 在plugins中
// https://github.com/amireh/happypack
new HappyPack({
  id: 'happyBabel', // loader?后面指定的id
  loaders: [{
    loader: 'babel-loader',
    options: {
      cacheDirectory: true // 利用缓存,提高性能
    }
  }],
  threadPool: HappyPack.ThreadPool({ size: 4 }), // 代表共享进程池,(查看电脑cpu核数,require('os').cpus().length)
  verbose: true, // 是否允许 HappyPack 输出日志,默认是 true
}),

webpack.dev

  const devWebpackConfig = merge(baseConfig, devServer, {
    mode: 'development', // 开发模式配置,默认production
    stats: 'errors-only', // errors-only:只在发生错误时输出【该配置可处理webpack服务启动时,去掉多余的打印信息】
    devtool: 'cheap-module-eval-source-map',
    // watch: true, // 开启监视模式,此时webpack指令进行打包会监视文件变化自动打包
    plugins: [
      // DefinePlugin会解析定义的环境变量表达式,当成JS执行
      new webpack.DefinePlugin({
        IS_DEV: 'true'
      }),
      // https://github.com/ampedandwired/html-webpack-plugin
      new HtmlWebpackPlugin({
        filename: 'index.html',
        template: `./src/${PROJECT_PATH}/public/index.html`,
        inject: true
      })
    ]
  })

webpack.dll

  • 作用:使用DllPlugin可以减少基础模块编译次数,动态链接库插件。
  • 原理是:把依赖的基础模块抽离出来打包到dll文件中,当需要导入的模块存在于某个dll中时,这个模块不再被打包,而是去dll中获取。
    在dll中大多包含的是常用的第三方模块,只要这些模块版本不升级,就只需要被编译一次。
  • 注意:DllPlugin参数中的name必须要和output.library值保持一致,并且生成的mainfest文件中会引用output.library值
module.exports = {
  mode: 'production',  // 开发模式配置,默认production || development
  stats: {
    modules: false, // 默认true,是否添加构建模块信息
  },
	entry: {
		rplib: ['vue/dist/vue.runtime.esm.js', 'vue-router', 'lodash']
	},
	output: {
		path: path.resolve(__dirname, '../dll'),
		filename: '[name].dll.[chunkhash].js',
		library: '[name]' // 最终会在全局暴露出一个[name].dll.[chunkhash]的对象
	},
	plugins: [
		new webpack.DllPlugin({
			name: '[name]',
			path: path.resolve(__dirname, '../dll/[name]-manifest.json'),
    }),
    // 不打包moment的语言包
    new webpack.IgnorePlugin(/\.\/locale/, /moment/),
	]
}

webpack.prod

生产环境的一些常用的基础、优化配置

  • html优化
    • 压缩:html-webpack-plugin
  • css优化
    • 提取到单独文件:mini-css-extract-plugin
    • 压缩:optimize-css-assets-webpack-plugin
  • js优化
    • 代码分离:手动配置多入口,抽取公用代码、懒加载、SplitChunksPlugin参数详解
    • 依赖库分离:optimization.splitChunks
    • 压缩:terser-webpack-plugin
module.exports = merge(baseConfig, {
  // https://www.webpackjs.com/configuration/stats/#stats
  stats: {
    children: false, // 默认true,是否添加children信息(设置为false,解决webpack4打包时出现:Entrypoint undefined = index.html)
    modules: false, // 默认true,是否添加构建模块信息
  },
  output: {
    // path.resolve:解析当前相对路径的绝对路径
    // path.join(path1,path2...) 将路径片段使用特定的分隔符(window:\)连接起来形成路径,并规范化生成的路径
		path: path.resolve(__dirname, '..', outputDir),
    filename: assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: assetsPath('js/[name].[chunkhash].js')
  },
}

webpack.smp打包速度分析


const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()

// 打包速度分析,查看每个loader和插件执行耗时
module.exports = smp.wrap(prodConfig)

webpack.analyse打包分析

在这里插入图片描述

// 打包分析
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = merge(prodConfig, {
	plugins: [
		new BundleAnalyzerPlugin()
	]
})

使用koa开启打包后的dist文件

const path = require('path')
const devConf = require('../dev.server')
const { spawn } = require('child_process')

// 开启服务
const startService = () => {
  const Koa = require('koa')
  const Router = require('koa-router')
  const Static = require('koa-static')
  const proxy = require('koa-server-http-proxy')  // https://github.com/eugeneCN/koa-server-http-proxy
  const app = new Koa()
  const router = new Router()

  // 导入代理设置
  Object.keys(devConf.devServer.proxy).forEach(key => {
    app.use(proxy(key, devConf.devServer.proxy[key]))
  })
  
  app.use(Static(path.join(__dirname, '..', '..', 'dist')))

  router.get('*', async (ctx, next) => {
    ctx.redirect('/')
  })
  
  app.use(router.routes()).use(router.allowedMethods())

  app.listen(4002, () => {
    console.log('Server start at: http://localhost:4002/')
  })
}

/**
 * @param 当没有安装依赖包的时,可以开启子进程安装依赖包
 * http://nodejs.cn/api/child_process.html
 * 使用npm的时候spawn('npm', ['install'], {})
 * **/
const _yarn = spawn('yarn', {cwd: './build/start'})
// stdout 获取标准输出
_yarn.stdout.on('data', data => {
  console.log(`stdout: ${data}`)
})
// stderr 获取标准错误输出
_yarn.stderr.on('data', data => {
  console.error(`stderr: ${data}`)
})
_yarn.on('close', code => {
  console.log(`子进程退出,退出码: ${code}`)
  startService()
})

外部扩展externals配置

配置externals选项提供了「从输出的 bundle 中排除依赖」的方法。

vue.config.js

const externals = ['vue', 'vuex', 'vue-router', 'vant']
const isProduction = process.env.NODE_ENV === 'production'
module.exports = {
	configureWebpack: {
    externals: isProduction ? externals : []
  },
}

webpack.config.js

module.exports = {
  ...
  output: {
    ...
  },
  externals : {
    vue: 'vue',
    vuex: 'vuex'
  }
  ...
}

index.html

<script src="https://cdn.bootcss.com/vue/2.6.10/vue.runtime.min.js"></script>

项目地址

如有不对,请指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值