美文网首页vue
webpack5学习,使用webpack搭建vue3项目

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

作者: 天气不不错 | 来源:发表于2022-06-17 17:21 被阅读0次

    项目初始化

    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

    <html lang="">
      <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><%= htmlWebpackPlugin.options.title %></title>
      </head>
      <body>
        <noscript>
          <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
            properly without JavaScript enabled. Please enable it to
            continue.
          </strong>
        </noscript>
       </body>
      </html>
    

    更多配置 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:'"./"'
        })
      ],
    

    使用变量

     <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    

    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项目

        本文链接:https://www.haomeiwen.com/subject/xcdhvrtx.html