webpack5.0工程化实战(1)搭建vue开发环境

前言

随着前端技术发展,掌握前端工程化越发成为前端工程师必要的条件。日常开发者中,我们常在用例如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-loader  css-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开发环境

  1. 不需要压缩代码

  2. 需要热更新

  3. css不需要提取到css文件

  4. devtool使用source-map

  5. ...

 2.4.2 生产环境

  1. 压缩代码

  2. 不需要热更新

  3. 提取css,压缩css文件

  4. sourceMap

  5. 构建前清除上一次构建的内容

  6. ...

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({//压缩js          cache: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配置》,看完文章,同学们可以搭建一下,搭建过程中会遇到许多的坑,同学可以在后台留言,或者微信私信我都可以,好了这一期就到这里了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值