webpack5学习,使用webpack搭建vue3项目

项目初始化

  1. 创建项目文件夹

  2. npm init 初始化

  3. 安装局部webpack、webpack-cli

  4. 在package.json中编写script脚本

      "scripts": {
        "build": "webpack"
      },
    // 这样就可以使用npm run build 打包了
    // 参考官方 https://www.webpackjs.com/guides/production/#npm-scripts
    
  5. 创建vue项目的目录及文件

image-20220614190410918.png

配置

在webpack.config.js文件中编写webpack配置,基础结构如下

// webpack.config.js
const path = require('path')
module.exports = {
  entry: ...,
  output: ...,
  module:[...],
  plugins:[...]
}

模式Mode

提供 mode 配置选项,告知 webpack 使用相应模式的内置优化,默认值时production

模式(Mode) | webpack 中文文档 (docschina.org)

module.exports = {
  mode: 'development',
};
image-20220616140824661.png

入口entry

entry用于配置入口,也是webpack管理的依赖关系的起点。

配置 | webpack 中文网 (webpackjs.com)

  entry:'./src/main.js'

出口output

output用于配置输出,也就是webpack打包后的文件存放在哪里。

配置 | webpack 中文网 (webpackjs.com)

  output: {
    path: path.resolve(__dirname, 'dist'), // 用path.resolve拼接得到一个绝对路径
    filename: 'js/bundle.js',
    clean: true, // 清空输出目录,webpack5开始可以直接配置清空,不再需要安装CleanWebpackPlugin
  },

配置loader

loader用于对模块源代码进行转换,loader遇到不知道如何加载的文件/模块时,就需要对应的loader来进行加载。loader存放在module.rules数组中,Rule的几个常用属性:test用于资源匹配;use是一个对象,用来设置loader及loader的options;loaderuse的简写

Loaders | webpack 中文文档 (docschina.org)

 module:{
    rules:[
     ... // loader规则Rule对象
    ]
  }
css相关的loader

css-loader

css-loader是用来处理.css文件的

先安装 npm install --save-dev css-loader

在rules数组中配置规则 ,这样就可以打包css文件了{test: /\.css$/,loader: 'css-loader',}

style-loader

用了css-loader虽然可以打包css文件了,但是现在的css样式还没效果,需要使用style-loader将css插入到页面中

安装npm install style-loader -D

在rules数组中配置规则,loader的加载顺序是由后往前的,style-loader需写在最前面

{
    test: /\.css$/,
    use: [
        { loader: 'style-loader' }, 
        { loader: 'css-loader' }
    ],
},

sass-loader

如果项目中用到了sass,就需要安装sass和sass-loader

安装npm install sass-loader sass webpack --save-dev

webpack5中使用sass+dart-sass 这样安装就可以了,不需要安装node-sass

在rules数组中配置规则

{
    test: /\.s[ac]ss$/i,
        use: [
            { loader: 'style-loader' },
            { loader: 'css-loader' },
            { loader: 'sass-loader' },
        ],
},

postcss-loader

postcss可以帮助我们自动添加浏览器前缀

安装npm install --save-dev postcss-loader postcss

安装postcss预设插件npm install postcss-preset-env -D,它包含了自动前缀等

postcss-loader | webpack 中文文档 (docschina.org)

{
    test: /\.s[ac]ss$/i,
        use: [
            { loader: 'style-loader' },
            { loader: 'css-loader' },
            {
                loader: 'postcss-loader',
                options: {
                    postcssOptions: {
                        plugins: [['postcss-preset-env']],
                    },
                },
            },
            { loader: 'sass-loader' },
        ],
},
asset module

项目中使用到了图片、文本等资源文件,打包时还是不能加载它们,因为还没有给它们配置loader,但从webpack5开始推出了asset module,不再需要为资源型文件配置loader,在rules数组中配置规则即可

资源模块 | webpack 中文文档 (docschina.org)

图片资源配置

{
        test: /\.(png|jpe?g|gif|webp)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
        // 配置资源输出位置和名称
        generator: {
          // 将图片文件输出到 imgs 目录中
          // 将图片文件命名 [name][hash:6][ext][query]
          // [name]: 之前的文件名称
          // [hash:6]: hash值取6位
          // [ext]: 使用之前的文件扩展名
          // [query]: 添加之前的query参数
          filename: 'imgs/[name][hash:6][ext][query]',
        },
      },
babel

babel可以帮助我们将ES6+的代码语法转换成ES5的代码

安装npm install -D babel-loader @babel/core @babel/preset-env

@babel/core是bable的核心,@babel/preset-env是bable的预设,因为bable的每个语法转换都需要独立的插件,如果一个个的安装,那就需要大量的插件,preset预设就直接帮我们来加载对应的插件列表

Babel 是什么? · Babel 中文网 (babeljs.cn) webpack 中文文档 (docschina.org)

{
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }

配置插件plugins

plugin用于对webpack功能的扩展,如打包优化

HtmlWebpackPlugin

用于生成html文件,生成的文件会把项目依赖的js文件打包后加载进去

安装npm install --save-dev html-webpack-plugin

配置,插件都是对象,需要new

HtmlWebpackPlugin可以不设置参数,它会有从默认模板生成html文件

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    ...
    plugins: [new HtmlWebpackPlugin()],
}

也可以进行配置,使用指定的模板生成html文件,指定页面title等

// webpack.config.js
  new HtmlWebpackPlugin({
      title: '这里是页面标题',
      template: './public/index.html',
    }),

在html模板中通过<%= htmlWebpackPlugin.options.title %>使用title


  
    
    
    
    <%= htmlWebpackPlugin.options.title %>
  
  
    
   
  

更多配置 jantimon/html-webpack-plugin: Simplifies creation of HTML files to serve your webpack bundles (github.com)

DefinePlugin

DefinePlugin 允许在 编译时 将你代码中的变量替换为其他值或表达式。就是说可以定义一些全局变量,在编译时使用。

DefinePlugin 是webpack的内置插件不需要安装,导入即可

 plugins: [
    new HtmlWebpackPlugin({
      title: '这里是页面标题',
      template: './public/index.html',
    }),
    new DefinePlugin({
      BASE_URL:'"./"'
    })
  ],

使用变量

 

DefinePlugin | webpack 中文文档 (docschina.org)

CopyWebpackPlugin

CopyWebpackPlugin可以帮助我们将public目录下的文件复制到dist目录下。

安装npm install copy-webpack-plugin --save-dev

导入const CopyPlugin = require('copy-webpack-plugin')

在patterns数组中配置规则,form复制的源,to复制到哪(可以省略,默认打包输出目录)

globOPtionspe进行额外配置,如ignore忽略哪些文件不复制

 new CopyPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    })

集成vue

安装vuenpm install vue@next

单文件组件还需安装@vue/compiler-sfc npm install -D @vue/compiler-sfc

安装处理.vue文件的vue-loader npm install vue-loader -D

      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }

配置Vue插件

const { VueLoaderPlugin } = require('vue-loader/dist/index')
...

module.exports = {
    ...
    plugins: [
        ...
        new VueLoaderPlugin()
    ]
    
}

现在就可以编写.vue文件了

处理两个警告,现在打包运行后可以发现控制台会有两个警告,在DefinePlugin中进行配置

    new DefinePlugin({
      BASE_URL: '"./"',
      __VUE_OPTIONS_API__: false, // 是否支持optionsApi
      __VUE_PROD_DEVTOOLS__: false // 在生成环境是否支持devtools
    }),

配置开发服务

每次进行了文件修改都需要重新build才能看到修改的效果,很麻烦,所以就需要开发服务webpack-dev-serverDevServer | webpack 中文文档 (docschina.org)

(当然也可以使用watch选项,watch 和 watchOptions | webpack 中文文档 (docschina.org))

安装npm install webpack-dev-server -D

添加scripts "serve": "webpack serve"

// package.js
"scripts": {
    "build": "webpack",
    "serve": "webpack serve"
  },

现在运行npm run serve 就可以通过开发服务启动项目了

基础配置

如果我们想指定端口等,就需要进行一些基础配置

// webpack.config.js
  devServer: {
    host: "10.10.0.99", // 启动服务器域名,可以不配置或改成0.0.0.0 这样在其他ip下也可以运行
    port: "3000", // 启动服务器端口号
    open: true, // 是否自动打开浏览器
    compress: true, // 启用gzip压缩
  },

HMR

现在使用开发服务后模块内容的改变是会使打开的页面改变的了,但是它是使整改页面重新加载,而不是局部更新。使用HMR在模块改变的时候进行局部的替换更新。

模块热替换(hot module replacement) | webpack 中文文档 (docschina.org)

配置hot: true(默认好像是开启的)

devServer: {
    ...
    hot: true
  },

这时你会发现修改vue文件、scss文件时已经实现了热更新,但是js文件却没有实现;这是因为vue-loaderstyle-loader已经帮我们实现了HMR接口,而babel-loader没有实现HMR,需要我们在导入时去判断是否开启热更新,并编写热更新发生时的回调。

// main.js
import './utils/comm.js'
if (module.hot) {
  //判断是否有热加载
  module.hot.accept('./utils/comm.js', function () {
    //热加载的模块路径
    console.log('aaa bbb!') //热加载的回调,即发生了模块更新时,执行什么 callback
  })
}
代理proxy

在开发中为了解决跨域问题就需要使用proxy代理

 proxy: {
      '/api': {
        // 匹配规则
        target: 'https://other-server.example.com', // 代理目标地址
        secure: false, // 接受在 HTTPS 上运行且证书无效的后端服务器
        changeOrigin: true, // 服务器源跟踪
        pathRewrite: { '^/api': '' } // 路径重写
      }
    }

解析resolve

在项目中我们导入文件的时候,发现有.js结尾的文件在导入时可以不写后缀,而.vue、.scss的不行,这些都是由webpack的解析选项设置决定的

后缀名简写的查找,当有多个同名的时候,以第一个

  resolve: {
    extensions: ['.js', '.json', '.vue', '.scss',...]
  },

配置别名alias,比如常见的@/

  resolve: {
    extensions: ['.js', '.json', '.vue', '.scss'],
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  },

最终的配置文件

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require('webpack')
const CopyPlugin = require('copy-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader/dist/index')
const path = require('path')

module.exports = {
  mode: 'development',
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'), // 用path.resolve拼接得到一个绝对路径
    filename: 'js/bundle.js',
    clean: true
  },
  resolve: {
    extensions: ['.js', '.json', '.vue', '.scss'],
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  },
  devServer: {
    host: '10.10.0.134', // 启动服务器域名,可以不配置或改成0.0.0.0 这样在其他ip下也可以运行
    port: '3000', // 启动服务器端口号
    open: true, // 是否自动打开浏览器
    compress: true, // 启用gzip压缩
    hot: true,
    proxy: {
      '/api': {
        // 匹配规则
        target: 'https://other-server.example.com', // 代理目标地址
        secure: false, // 接受在 HTTPS 上运行且证书无效的后端服务器
        changeOrigin: true, // 服务器源跟踪
        pathRewrite: { '^/api': '' } // 路径重写
      }
    }
  },
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: [
          { loader: 'style-loader' },
          { loader: 'css-loader' },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [['postcss-preset-env']]
              }
            }
          },
          { loader: 'sass-loader' }
        ]
      },
      {
        test: /\.(png|jpe?g|gif|webp)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
          }
        },
        // 配置资源输出位置和名称
        generator: {
          // 将图片文件输出到 imgs 目录中
          // 将图片文件命名 [name][hash:6][ext][query]
          // [name]: 之前的文件名称
          // [hash:6]: hash值取6位
          // [ext]: 使用之前的文件扩展名
          // [query]: 添加之前的query参数
          filename: 'imgs/[name][hash:6][ext][query]'
        }
      },
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: '这里是页面标题',
      template: './public/index.html'
    }),
    new DefinePlugin({
      BASE_URL: '"./"',
      __VUE_OPTIONS_API__: false, // 是否支持optionsApi
      __VUE_PROD_DEVTOOLS__: false // 在生成环境是否支持devtools
    }),
    new CopyPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    }),
    new VueLoaderPlugin()
  ]
}

你可能感兴趣的:(webpack5学习,使用webpack搭建vue3项目)