前言
随着前端技术发展,掌握前端工程化越发成为前端工程师必要的条件。日常开发者中,我们常在用例如vue-cli 、 create-react-app等脚手架构建我们项目。但是如果你想在团队脱颖而出,那就需要花费一部分时间去学习webpack

本文各插件版本将在文章末尾为大家呈现
1.初始化项目
新建目录,初始化npm
npm init
1.1安装webpack包(建议将三个包同时安装)
npm i -D webpack webpack-cli webpack-dev-server
-
npm i -D 为npm install --save-dev的缩写
-
npm i -S 为npm install --save的缩写

1.2配置webpack.config.js
新建webpack.config.js,实现更多的自定义配置
//webpack.config.jsconst path = require('path')module.export = {entry:path.resolve(__dirname,'./src/index.js') //入口文件output:{filename:'bundle.js', //打包后的文件名称path:path.resolve(__dirname,'./build') //打包后的目录}}
配置完webpack.config.js之后可以尝试着新建文件打包一下
1.3安装各插件
html-webpack-plugin//使用html-webpack-plugin创建html页面,并将打包后的js文件需要引入到html中 使用该插件引入对应的js文件npm i -D html-webpack-plugin//新建build同级的文件夹public 新建一个index.html
clean-webpack-pluginnpm i -D clean-webpack-plugin将dist文件夹残留上次打包的文件清空
1.4 引入css
在引入css时也需要一些loader来解析我们的css
npm i -D style-loader css-loadercss-loader 的作用是将 CSS 模块转换为一个 JS 模块,但不会使用这个模块style-loader 就可以把css-loader转化的模块通过style标签追加到页面上使用less构建样式npm i -D less less-loader
配置文件如下
// webpack.config.jsmodule.exports = {// ...省略其他配置module:{rules:[{test:/\.css$/,use:['style-loader','css-loader'] // 切记从右向左解析原则},{test:/\.less$/,use:['style-loader','css-loader','less-loader'] // 从右向左解析原则}]}}
1.5 为css添加浏览器前缀
npm i -D postcss-loader autoprefixer//为了兼容各浏览器 添加此插件
需要在根目录创建postcss.config.js 文件
module.exports = {plugins: [require('autoprefixer')] // 引用该插件}
1.6 把css样式从js文件中提取到单独的css文件中
npm i -D mini-css-extract-pluginconst MiniCssExtractPlugin = require("mini-css-extract-plugin");module.exports = {//...省略其他配置module: {rules: [{test: /\.less$/,use: [MiniCssExtractPlugin.loader,'css-loader','less-loader'],}]},plugins: [new MiniCssExtractPlugin({filename: "[name].[hash].css",chunkFilename: "[id].css",})]}需要配置 MiniCssExtractPlugin 插件 一起使用
1.7 babel转义js文件
需要注意版本对应的关系
ES6/7/8 转 ES5代码
npm i -D babel-loader @babel/preset-env @babel/core @babel/plugin-proposal-decoratorsnpm i -D @babel/plugin-transform-arrow-functions @babel/plugin-transform-runtime
1.8 打包 图片 字体等
在webpack5中 svg属于inline asset,内置loader
图片字体等文件在webpack5中内置了loader,按照如下配置即可无需引入依赖,路径自己定义即可。
//以上配置省略module:{rules:[{test: /\.vue$/,loader: 'vue-loader'},{// 用正则去匹配要用该 loader 转换的 CSS 文件test: /\.css$/,exclude: path.resolve(__dirname, 'node_modules'),use: [ 'style-loader', 'css-loader','postcss-loader']},{test: /\.m?js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {// 缓存,加快babel-loader编译速度cacheDirectory: true,// 一系列插件的集合,包括处理箭头函数等,配置后是否需要配置plugins? 后面再看// 2021/5/12 结论:不需要配置其他plugins// useBuiltIns corejs 解决es6新增api无法编译问题(只能编译语法,例如箭头函数)presets: [// ['@babel/preset-env', { targets: 'defaults' }]['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3, targets: 'defaults' }]],plugins: [// 编译箭头函数'@babel/plugin-transform-arrow-functions',// 编译装饰器['@babel/plugin-proposal-decorators', { legacy: true }],// 编译类,loose true时是赋值法定义属性,false时是使用Object.defineProperty定义属性,后者是默认['@babel/plugin-proposal-class-properties', { loose: false }]]}}},{test:/\.svg$/,type:'asset/inline',generator:{filename:"icons/[name]--[hash].[ext]"}},{test:/\.(png|jpe?g|gif)(\?.*)?$/,type:'asset/resource',generator: {filename: 'imgs/[name]--[hash].[ext]'}},{test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,type: 'asset/resource',generator: {filename: 'media/[name]--[hash].[ext]'}},{test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,type: 'asset/resource',generator: {filename: 'fonts/[name]--[hash].[ext]'}}]},
2搭建vue开发环境
结合上面例子的依赖,还需要以下几种配置
2.1解析vue文件
npm i -D vue-loader vue-template-compiler vue-style-loadernpm i -S vue
vue-loader 用于解析.vue文件
vue-template-compiler 用于编译模板
具体配置见后文完整配置
2.2 配置webpack-dev-server进行热更新
devServer: {contentBase: path.join(__dirname, './dist'),compress: true,port: 3000,hot: true,open: true},
2.3 配置打包命令
"scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack --watch --config webpack.config.js","dev": "webpack serve"},
2.3.1在src下新建index.js
import Vue from 'vue'import App from './App.vue'new Vue({render: h => h(App)}).$mount('#app')if (module.hot) {module.hot.accept('./App.vue', function () {})module.hot.accept('./show.js', function () {})}
新建App.vue
<template><div id="app">{{str}}</div></template><script>console.log('app 加载了')export default {name: 'App',data () {return {str: 'hello3'}},mounted () {console.log(Math.trunc(12.1))},methods: {}}</script>
新建 index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><!-- <p id="app"></p><img id="testimg" src="" alt=""><div>bfg</div> --><div id="app"></div></body></html>
新建完各页面 执行npm run dev如果浏览器出现Vue开发环境成功,那么一个基础的基于vue的webpack打包工具就完成了
完整配置
const path = require('path');const htmlWebpackPlugin = require('html-webpack-plugin') //引入对应文件const webpack = require('webpack')const { VueLoaderPlugin } = require('vue-loader')const {CleanWebpackPlugin} = require('clean-webpack-plugin')//将css样式从js文件中提取到单独css文件// const MiniCssExtractPlugin = require('mini-css-extract-plugin')module.exports = {// 默认路径,将entry的前置路径放到这个字段// context:path.resolve(__dirname,'src'),entry:path.resolve(__dirname,'./src/index.js'),output:{// 把所有依赖的模块合并输出到一个 bundle.js 文件filename:'[name].[hash:8].js',path:path.resolve(__dirname,'./build')},devServer: {contentBase: path.join(__dirname, './dist'),compress: true,port: 3000,hot: true,open: true},devtool: 'source-map',module:{rules:[{test: /\.vue$/,loader: 'vue-loader'},{// 用正则去匹配要用该 loader 转换的 CSS 文件test: /\.css$/,exclude: path.resolve(__dirname, 'node_modules'),use: [ 'style-loader', 'css-loader','postcss-loader']},{test: /\.m?js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {// 缓存,加快babel-loader编译速度cacheDirectory: true,// 一系列插件的集合,包括处理箭头函数等,配置后是否需要配置plugins? 后面再看// 2021/5/12 结论:不需要配置其他plugins// useBuiltIns corejs 解决es6新增api无法编译问题(只能编译语法,例如箭头函数)presets: [// ['@babel/preset-env', { targets: 'defaults' }]['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3, targets: 'defaults' }]],plugins: [// 编译箭头函数'@babel/plugin-transform-arrow-functions',// 编译装饰器['@babel/plugin-proposal-decorators', { legacy: true }],// 编译类,loose true时是赋值法定义属性,false时是使用Object.defineProperty定义属性,后者是默认['@babel/plugin-proposal-class-properties', { loose: false }]]}}},{test:/\.svg$/,type:'asset/inline',generator:{filename:"icons/[name]--[hash].[ext]"}},{test:/\.(png|jpe?g|gif)(\?.*)?$/,type:'asset/resource',generator: {filename: 'imgs/[name]--[hash].[ext]'}},{test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,type: 'asset/resource',generator: {filename: 'media/[name]--[hash].[ext]'}},{test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,type: 'asset/resource',generator: {filename: 'fonts/[name]--[hash].[ext]'}}]},plugins:[new htmlWebpackPlugin({filename:'index.ejc',template:path.resolve(__dirname,'./src/index.html')}),new CleanWebpackPlugin(),new webpack.HotModuleReplacementPlugin(),new VueLoaderPlugin()]}
2.4区分开发环境与生产环境
实际运用到项目时, 需要区分开发环境与生产环境的关系
新建两个文件夹
-
webpack.dev.js开发环境使用 -
webpack.prod.js生产环境使用 -
webpack.config.js公用配置
2.4.1开发环境
-
不需要压缩代码
-
需要热更新
-
css不需要提取到css文件
-
devtool使用source-map
-
...
2.4.2 生产环境
-
压缩代码
-
不需要热更新
-
提取css,压缩css文件
-
sourceMap
-
构建前清除上一次构建的内容
-
...
2.4.3安装所需依赖
npm i optimize-css-assets-webpack-plugin mini-css-extract-plugin clean-webpack-plugin webpack-merge copy-webpack-plugin -D
-
webpack-merge合并配置 -
copy-webpack-plugin拷贝静态资源 -
optimize-css-assets-webpack-plugin压缩css -
uglifyjs-webpack-plugin压缩js
开发环境配置
// 开发环境// webpack中引入的path[require('path')]是node.js内置的package,用来处理路径的。const webpackConfig = require('./webpack.config.js')const WebpackMerge = require('webpack-merge')const webpack = require('webpack')// Webpack-merge 提供了一个函数,该函数将数组串联并合并创建新对象的对象。如果遇到函数,它将执行它们,通过算法运行结果,然后再次将返回的值包装在函数中。module.exports = WebpackMerge.merge(webpackConfig,{mode:'development',devtool:'source-map',devServer:{port:3000,hot:true,contentBase:'./build'},plugins:[new webpack.HotModuleReplacementPlugin()]})
生产环境配置
const path = require('path')const webpackConfig = require('./webpack.config.js')const WebpackMerge = require('webpack-merge')const CopyWebpackPlugin = require('copy-webpack-plugin')const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') //压缩cssconst UglifyJsPlugin = require('uglifyjs-webpack-plugin') //压缩jsmodule.exports = WebpackMerge.merge(webpackConfig,{mode:'production',devtool:'cheap-module-source-map',plugins:[new CopyWebpackPlugin({patterns:[{from:path.resolve(__dirname,'src'),to:path.resolve(__dirname,'build')}]}),],optimization:{minimizer:[new UglifyJsPlugin({//压缩jscache:true,parallel:true,sourceMap:true}),new OptimizeCssAssetsPlugin({})],splitChunks:{chunks:'all',cacheGroups:{libs: {name: "chunk-libs",test: /[\\/]node_modules[\\/]/,priority: 10,chunks: "initial" // 只打包初始时依赖的第三方}}}}})
修改package.json 配置
{"name": "webpack-new","version": "1.0.0","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack --watch --config webpack.prod.js","dev": "webpack-dev-server --config webpack.dev.js"},"author": "","license": "ISC","keywords": [],"description": "","devDependencies": {"@babel/core": "^7.14.6","@babel/plugin-proposal-decorators": "^7.14.5","@babel/plugin-transform-arrow-functions": "^7.14.5","@babel/plugin-transform-runtime": "^7.14.5","@babel/preset-env": "^7.14.7","autoprefixer": "^10.2.6","babel-loader": "^8.2.2","clean-webpack-plugin": "^3.0.0","copy-webpack-plugin": "^9.0.1","css-loader": "^5.2.6","html-webpack-plugin": "^5.3.2","mini-css-extract-plugin": "^1.6.2","optimize-css-assets-webpack-plugin": "^6.0.1","postcss-loader": "^6.1.0","style-loader": "^2.0.0","uglifyjs-webpack-plugin": "^2.2.0","vue": "^2.6.14","vue-loader": "^15.9.7","vue-router": "^3.5.2","vue-template-compiler": "^2.6.14","vuex": "^3.6.2","webpack": "^5.40.0","webpack-cli": "^3.3.12","webpack-dev-server": "^3.11.2","webpack-merge": "^5.8.0"}}
watch的原理是:watch开启后,webpack会隔一段时间(poll)轮训一次要打包的文件,监听到变化,会缓存一下第一次,在一段时间时候后(aggregateTimeout设置的),检测所有修改的文件。这时候把所有修改文件一起编译打包。
交流讨论
到目前为止,我们已经成功的自己搭建了一个基础vue 开发环境,不过想要获取更好的offer、更高的薪水,还需要继续深入学习,在此来一波预告吧《webpack工程化实战(2)优化webpack配置》,看完文章,同学们可以搭建一下,搭建过程中会遇到许多的坑,同学可以在后台留言,或者微信私信我都可以,好了这一期就到这里了。
723

被折叠的 条评论
为什么被折叠?



