基于 webpack 5 搭建 Vue 脚手架

对于基本项目来说,基本的开发依赖有:webpack、webpack-cli、vue-loader、vue-template-compiler、sass-loader、sass、css-loader、style-loader、babel-loader、@babel/core、@babel/preset-env

loader的作用是把代码中进行编译,转换。webpack-cli:这个cli提供了webpack的终端命令去调用webpack。vue-loader:把vue的代码转化成js代码,vue.loader里面有需要转化HTML,就需要vue-template-compiler,在代码中我们可能还需要使用sass或Less等其它的去快速书写css,处理sass代码需要sass-loader,它会把sass代码转化成css代码,处理css代码我们就需要css-loader,css处理好了之后我们需要把它通过style标签加入到我们的代码中去,所以就需要style-loader去吃力这个事情。css处理好了之后就需要处理我们的js啦。js呢,在开发过程中会用比较深得语法,为了避免老浏览器不兼容,我们就把新的语法转化成老的语法,如ES5语法,就需要bable-loader还需要bable的一个核心库,@bable/core ,还需要一个映射的配置集@babel/preset-env,

具体配置如下,通用的配置,得看不同的项目进行不同的配置,

const path = resolve('path')
const {VueLoaderPlugin} = require('vue-loader')
module.exports = {
  /**
   * entry
   * 文件打包的入口,注:这个是一个相对路径
   **/
  entry:'./scr/main.js',
  /**
   * output
   * path:打包后的文件存放路径 ,filename:打包后的文件名
   * '__dirname'这个属性是node内置的一个全局变量,它的值是一个当前文件所处在的绝对路径,和在终端数据pwd命令的结果一样
   * path.resolve()。path是node里面的内置模块,这个模块里面有个resolve()方法,这个方法用于拼接一个完整的路径
   **/
  output:{
    path:path.resolve(__dirname,'dist'),
    filename:'bunder.js' ,
  },
  /**
   * module
   * 存放loader,模块,在webpack中,一切文件皆为模块,rules里面放的是一个对象,每个对象是一个Loader配置选项
   * 一个文件使用一个loader去处理的时候可以写成如:{test:/.vue$/,use:'vue-loader'},
   * 需要两个loader及以上,配置如:{test:/.vue$/,use:['vue-loader',xxx,xxx]},
   * 需要对这个loader选项进行配置的话,写成如:{test:/.vue$/,use:[{loader:'vue-loader',options:{}}]},
   **/
  module:{
    rules:[
      {test:/.vue$/,use:'vue-loader'},//处理vue文件
      {test:/.s[ca]ss$/,use:['style-loader','css-loader','scss-loader']}, //处理css,注意这三个loader的顺序
      {//处理js文件
        test: /.m?js$/,
        use:{
          loader:'bable-loader',
          options:{
            presets:['@bable/preset-env']
          }
        }
      },
      //处理开发中常见的几种图片,下面这个是以前老式的配置方法,是webpack5之前的
      // {test: /\.(png|jpe?g|gif|svg|webp)$/,use: {loader: 'file-loader',options: {esModule:false}}}
      {test: /\.(png|jpe?g|gif|svg|webp)$/,type:'asset/resource'}
    ]
  },
  plugins: [//存放插件
     //VueLoaderPlugin: 来补充vue-loader在处理vue的时候,它处理了模板里面的HTML,但是它不知道怎么处理里面的js,
    // 和css,就需要这个插件来补充,所以就通过这个插件告诉vue-loader,当遇到这些文件时,让我们之前配置过得loader去处理相应的文件
    new VueLoaderPlugin()
  ]
}
发现,经过了上面的配置,然后直接在控制台输入命令webpack,发现报错的,虽然我们安装了webpack-cli提供了这个命令,但是它安装到了node_modules文件中的.bin文件中webpack。如果想要执行这个命令,可以在终端控制台通过输入./node_modules/bin/webpack来执行,但是每次我们开发完代码,还输入这么长的命令,有点烦,可以通过这配置减少我们的命令,在package.json文件中,在scripts对象里面,加入"serve": "webpack --mode=development --watch",没必要加相对路径,如写成"serve": "./node_modules/bin/webpack"。我们在script中写入node_modules中的命令时,不用写路径,它会自动去找。--watch的命令是:当webpack发现我们开发中的代码修改保存时,它自动帮我们编译运行,不需要我们手动去执行

对于webpack命令编译启动后,我们配置了--watch,但是官网提供了更好的方式,webpack-dev-server,开发服务
第一步,下载
npm -D install webpack-dev-server
第二步,只要下载好了这个包,不用引入,直接使用,"serve": "webpack server --mode=development",然后在webpack文件中配置如下
  plugins: [//存放插件
     //VueLoaderPlugin: 来补充vue-loader在处理vue的时候,它处理了模板里面的HTML,但是它不知道怎么处理里面的js,
    // 和css,就需要这个插件来补充,所以就通过这个插件告诉vue-loader,当遇到这些文件时,让我们之前配置过得loader去处理相应的文件
    new VueLoaderPlugin()
  ],
  devServer: {
    static:'./dist' //打包后的静态资源文件,指向这个目录,
    open:true,//自动打开浏览器
    host: 'local-ip',//使用内网IP,使用ip代替localhost
    onListening({server}){//在终端打印访问地址
      const {address:addr,port} = server.address()
      console.log(`服务启动了:http://${addr}:${port}`)
    }
  },
  devtool:'inline-source-map' //报错对应到源代码

当然,上面的配置,只是webpack的基本配置,它还有一些优化,比如:HMR  source-map  缓存  tree shaking  lazy loading  externals,

HMR: hot module replacement 热模块替换 / 模块热替换
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度。样式文件可以使用HMR功能:因为style-loader内部实现了。 js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码,注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了~ (不用做HMR功能)解决:修改entry入口,将html文件引入

source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)
1、source-map:外部:错误代码准确信息 和 源代码的错误位置
2、inline-source-map:内联:只生成一个内联source-map,错误代码准确信息 和 源代码的错误位置
3、hidden-source-map:外部:错误代码错误原因,但是没有错误位置,不能追踪源代码错误,只能提示到构建后代码的错误位置
4、eval-source-map:内联:每一个文件都生成对应的source-map,都在eval错误代码准确信息 和 源代码的错误位置
5、nosources-source-map:外部:错误代码准确信息, 但是没有任何源代码信息
6、 cheap-source-map:外部:错误代码准确信息 和 源代码的错误位置,只能精确的行
7、cheap-module-source-map:外部:错误代码准确信息 和 源代码的错误位置,module会将loader的source map加入
内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
开发环境:速度快,调试更友好
      速度快(eval>inline>cheap>...)
        eval-cheap-souce-map
        eval-source-map
      调试更友好  
        souce-map
        cheap-module-souce-map
        cheap-souce-map
      --> eval-source-map  / eval-cheap-module-souce-map
    生产环境:源代码要不要隐藏? 调试要不要更友好,内联会让代码体积变大,所以在生产环境不用内联
      nosources-source-map 全部隐藏
      hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
      --> source-map / cheap-module-souce-map

缓存:babel缓存,cacheDirectory: true,让第二次打包构建速度更快
文件资源缓存有一下几种方式:
1、hash: 每次wepack构建时会生成一个唯一的hash值。 问题: 因为js和css同时使用一个hash值。如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)
2、chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样问题: js和css的hash值还是一样的
因为css是在js中被引入的,所以同属于一个chunk
3、contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样    
让代码上线运行缓存更好使用

tree shaking:去除无用代码。前提:1. 必须使用ES6模块化  2. 开启production环境。作用: 减少代码体积
在package.json中配置。"sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)。问题:可能会把css / @babel/polyfill (副作用)文件干掉,"sideEffects": ["*.css", "*.less"]

lazy loading懒加载

console.log('index.js文件被加载了~');
// import { mul } from './test';
document.getElementById('btn').onclick = function() {
  // 懒加载~:当文件需要使用时才加载~
  // 预加载 prefetch:会在使用之前,提前加载js文件 
  // 正常加载可以认为是并行加载(同一时间加载多个文件)  
  // 预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
  import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
    console.log(mul(4, 5));
  });
};

externals

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'production',
  externals: {
    // 拒绝jQuery被打包进来
    jquery: 'jQuery'
  }
};

你可能感兴趣的:(vue.js,webpack,前端)