手摸手:webpack 3秒打包一个three.js项目(有物证)

关于 webpack 相关的文章太多了,何不一块儿从零开始手写一个配置呢?css

真的3秒能打包一个three.js项目吗?真的,后面会提供源文件地址哦。html

要打包的项目是这个样子的。 前端

从零开始

关于 three.js 的安装和使用部分都省略。node

首先是最基础的。咱们须要安装webpack

  1. cross-env 目前最流行的运行跨平台设置和使用环境变量的脚本
  2. webpack + webpack-cli + webpack-dev-server:三'贱'客,项目必备

参考常规webpack配置结构须要3个最基础文件:git

  1. webpack 基础配置文件,暂命名为 webpack.base.js
  2. webpack 开发配置文件,暂命名为 webpack.dev.js
  3. webpack 打包配置文件,暂命名为 webpack.prod.js

固然,须要把 devprod 中的配置和 base 的配置合并起来,安装个webpack-merge 吧。github

而后配置一下最熟悉的脚本运行环节吧。经过--config来对标配置文件,通cross-env 设置环境变量web

"dev": "cross-env NODE_ENV=dev webpack-dev-server --config script/webpack.dev.js",
"build": "cross-env NODE_ENV=prod webpack --config script/webpack.prod.js"
复制代码

好的,初期准备工做都OK开始配置环节。npm

开始配置

首先是webpack的出入口。出口设置为 dist 环节简单直接上代码。json

{
    entry: './src/index.js',
    output: {
      filename: '[name].[hash:8].js',
      path: rootResolve('dist'),
      publicPath: '/'
    },
  }
复制代码

顺便配置下别名。依然能够直接上代码

resolve: {
    extensions: ['.js', '.json'],
    alias: {
      '@': rootResolve('src'),
      '@assets': rootResolve('src/assets'),
    }
  }
复制代码

而后是关键环节:loaderplugins

关于 loader:

  • 样式上使用 less
    • 须要经过less-loader 解析 less 由于 webpack 只能读懂js
    • 解析完成再经过 postcss-loader 加上浏览器前缀
    • 再经过css-loader 解析css代码中的 url@import语法
    • 最后,经过MiniCssExtractPlugin.loader 生成 .css文件
  • JS 文件使用 babel-loader,关于 babel 文章太多了,暂略
    • 顺便使用 HappyPack 进行优化加速
    • 为何不选 thread-loader 呢? (由于名字很差听 - -! 怪我咯)
  • 其余文件,用 url-loader 咯。

而后 loader 配置就是这样的

{
  test: /\.less$/,
  exclude: /(node_modules|bower_components)/,
  loaders: [{
    loader: MiniCssExtractPlugin.loader,
    options: {
      esModule: true,
      hmr: process.env.NODE_ENV === 'dev', // 热更新
      // publicPath: '../',
    }
  }, 'css-loader', 'postcss-loader', 'less-loader']
},
{
  test: /\.m?js$/,
  exclude: /(node_modules|bower_components)/,
  loader: 'happypack/loader',
  options: {
    id: 'babel',
  }
},
{
  test: /\.(png|jpe?g|gif)(\?.*)?$/,
  use: [{
    loader: 'url-loader',
    options: {
      limit: 8192,
      name: 'assets/img/[hash:8].[ext]'
    }
  }]
}
复制代码

关于插件部分,首先是配合上面 loader的相关插件:HappyPackMiniCssExtractPlugin

new MiniCssExtractPlugin({
  filename: "css/[name].[hash:8].css", // css 路径
}),
new HappyPack({
  id: 'babel',
  loaders: [{
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env'],
      cacheDirectory: true
    }
  }]
})
复制代码

固然,我想知道运行和打包的进度: ProgressPlugin,顺便弄个 DefinePlugin 工程化必备插件。最后webpack生成后的代码注入不能少了 HtmlWebpackPlugin

而后 base 文件的插件结构是这样的

plugins: [
  new webpack.ProgressPlugin(),
  new webpack.DefinePlugin({
    NODE_ENV: JSON.stringify(process.env.NODE_ENV), // 当前使用环境
    VERSION: JSON.stringify('0.1.0'),
  }),
  new MiniCssExtractPlugin({
    filename: "css/[name].[hash:8].css", // css 路径
    // chunkFilename: "[id].css",
  }),
  new HappyPack({
    id: 'babel',
    loaders: [{
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env'],
        cacheDirectory: true
      }
    }]
  }),
  new HtmlWebpackPlugin({ template: './src/index.html' })
]
复制代码

开发环境配置

首先开发环境 api 代理必不可少。那么就是 devServer.proxy了,顺便再定义下开发环境端口号。

devServer: {
  contentBase: path.join(__dirname, "dist"),
  compress: true,
  port: 3333
}
复制代码

目前也没有太多事情,那么 merge 下再配个 HotModuleReplacementPlugin

merge(base, {
  mode: 'development',
  plugins: [
  ],
  devServer: {
    contentBase: rootResolve("src"),
    compress: true,
    port: 3333
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
})
复制代码

打包环境

打包环境主要作了这几件事情

  1. 打包优化
  2. 分类文件
  3. 删除冗余

首先是 dll

  1. 定义 dll 配置文件。 好比:webpack.dll.config.js
    1. 须要定义要打包的库和打包的出口
    2. 命名生成后的dll模块的详细要点文件 manifest.dll.json

那么 webpack.dll.config.js 内容应该是这样的

{
	// 你想要打包的模块的数组
	entry: {
		vendor: ['three']
	},
	output: {
		filename: '[name].dll.js',
		path: distResolve('dll'), // 打包后文件输出的位置
		library: '[name]_library'
		// 这里须要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
	},
	plugins: [
		new webpack.DllPlugin({
			name: '[name]_library',
			path: distResolve('dll/manifest.dll.json'),
			context: __dirname
		})
	]
}
复制代码
  1. 经过 DllReferencePlugin + json文件 把 dll模块的详细要点告诉 webpack

prod 文件中添加 plugins

new webpack.DllReferencePlugin({
  context: __dirname,
  manifest: require(distResolve('./dll/manifest.dll.json'))
})
复制代码
  1. 添加脚本运行配置
"dll": "webpack --config script/webpack.dll.config.js",
复制代码

运行下 npm run dll,在 dist/dll 目录下生成dll相关文件,那么 dll 配置也完成了。顺便作一些清理工做,用下 CleanWebpackPlugin

new CleanWebpackPlugin({
  cleanOnceBeforeBuildPatterns: [
    'assets', 'js', 'css', 'index.html', '*.js',
    '!manifest.dll.json', '!vendor.dll.js' // 不删除 dll 文件
  ],
})
复制代码

而后是代码优化,其实当 mode: 'production' 时已经作了不少代码优化相关的事情了。(我无论,我就是要优化 - -!

作一下 js的并行压缩吧

optimization: {
  minimizer: [
    new TerserWebpackPlugin({
      parallel: true,  // 启用并行压缩
      cache: true,    // 启用缓存
    }),
    new OptimizeCssAssetsPlugin({ // 压缩css
      cssProcessorOptions: {
        safe: true
      }
    })
  ],
  runtimeChunk: true, // 自动拆分runtime文件
  splitChunks: {
    chunks: 'async',
    minSize: 30000,
    automaticNameDelimiter: '~',
    automaticNameMaxLength: 30,
    cacheGroups: {
      defaultVendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  },
}
复制代码

欧耶,再配置下js的打包后路径就行了

output: { // JS 路径
  path: distResolve(),
  filename: 'js/[id].[chunkhash].js',
  chunkFilename: 'js/[name].[chunkhash].js'
},
复制代码

最后 mergebase 配置。在 dev 时作过了... 省略。

至此,Webpack配置已经大部分完成了,运行npm run build打包代码,一、二、3。 3秒打包完成了。

为何只须要3秒呢?虽然上面的配置确实作了不少优化,可是大部分事情都被表象迷惑了,具体为什么下一章见。

最后

  1. 源码地址 github.com/zhongmeizhi…
  2. 更多实战项目:github.com/zhongmeizhi…
  3. 一个字一个字码出来的文章,原创不易,点个赞呗。
  4. 欢迎关注公众号「前端进阶课」认真学前端,一块儿进阶。

相关文章
相关标签/搜索