webpack 萌新研究入门全过程(1)

1,122 阅读5分钟

老司机直接×
都是经验之谈

一.安装

安装webpack工具

 npm install webpack -D
 npm install webpack-cli -D

-D/--save-dev 开发依赖
-S/--save 运行依赖

二.多入口

entry:{ // 对象方式--多入口
    homepage:"./src/homepage.js",
    list:"./src/list.js"
    ...
}
output:{ //使用占位符,path必须是绝对路径
    filename:[name].js,
    path:path.resolve(__dirname,"dist")
}

使用 npx webpack 命令进行测试 成功生成构建好的目录
然而每次构建 目录不会清除 因此引入 clean-webpack-plugin

npm install clean-webpack-plugin 
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
plugins: [new CleanWebpackPlugin()]
}

使用插件生成html 模版 需考虑多页应用

const path require("path");
const HtmlWebpackPlugin require("html-webpack-plugin");
const pageConfig = {
  homepage: "./src/js/homepage.js",
  list"./src/js/list.js",
};
module.exports = {
  entry: pageConfig,
  output: {
    filename: "[name]_[contenthash:8].js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename"homepage.html",
      template: path.resolve(__dirname, "src/html/homepage.html"),
      chunks: ["homepage"],
    }),
    new HtmlWebpackPlugin({
      filename"list.html",
      template: path.resolve(__dirname, "src/html/list.html"),
      chunks: ["list"],
    }),
  ],
};

有几个入口就有几个出口,有几个出口就有几个HtmlWebpackPlugin

三.处理多种格式

1.css/scss

npm install style-loader --save-dev 
npm install css-loader --save-dev
npm install sass-loader sass --save-dev
module.exports = {
...
 module: {
    rules: [
      {
        test: /\.scss$/, 
        use: ["style-loader""css-loader""sass-loader"],
      },
    ],
  },
...
}

使用多个loader 从右到左,先使用sass-loader 在使用css-loader,最后使用style-loader

关于正则 "\": 转义字符 
".": 特殊字符 
"\.": 表示"."
"|" :表示或者

增加兼容前缀

npm install --save-dev postcss-loader postcss
npm install --save-dev postcss-preset-env

新建 postcss.config.js postcss-loader会自动寻找这个配置文件

postcss.config.js

module.exports = {
  plugins: [
    [
      "postcss-preset-env",
      {
        // Options
      },
    ],
  ],
};

postcss-preset-env使用browserslist来配置目标环境 postcss-preset-env集成了autoprefixer

mini-css-extract-plugin

提取css,创建单独的css文件 安装

npm i mini-css-extract-plugin -D

在webpack.config.js中

const MiniCssExtractPlugin=require("mini-css-extract-plugin")
...

module.exports = {
  ...
  module: {
    rules: [
    ...
    {
            test/\.(css|scss)$/// \:转移字符 .:特殊字符 \. 表示.
            use: [
            {
            loader:MiniCssExtractPlugin.loader,
            options:{
              publicPath:'../'  //因为生成的css文件在css目录中(下面filename中配置),css文件中的代码找到其他资源则需要向上跳出一个目录
            }
          }, "css-loader""postcss-loader""sass-loader"],
     },
     ...
     ]
 ]

  plugins: [
    ...
    new MiniCssExtractPlugin({
      filename"css/[name][contenthash:8].css"  //打包后css文件在css目录中
    }),
    ...
    ]
    ...
}

mini-css-extract-plugin有自己的loader

2.js/es6

npm i babel-loader @babel/core @babel/preset-env -D

  •  babel-loader是webpack 与 babel的通信桥梁梁,
  • @babel/preset-env 把es6转成es5
module: {
    rules: [
      {
        test:/\.js$/,
        use:{
          loader:"babel-loader",
          options: {
            presets: ["@babel/preset-env"]
          }
        }
      }
    ],
  },

还需要使用 @babel/polyfill 处理es新特性特有的方法,相当于用老方式实现新特性并挂载到全局变量中(语法糖)

 npm install --save @babel/polyfill

在需要使用的polyfill的文件上 使用import "@babel/polyfill" 引入polyfill 此时会把 polyfill库完全打包到出口js,生成的js会非常大,因此使用按需引入的方式,之后生成的js会减小很多

删除import “@babel/polyfill” 在配置中增加

{
    test:/\.js$/,
    exclude: /node_modules/,
    use:{
      loader:"babel-loader",
      options: {
        presets: [
          [
            "@babel/preset-env",
            {
              corejs: 2,
              useBuiltIns: "usage"
            }
          ]
        ]
      }
    }
}

注意presets:[[]] 在新的方案中已经废弃了polyfill 使用 import "core-js/stable"; import "regenerator-runtime/runtime"; 代替 同时配置应改为 corejs:3 注意 core-js 和 regenerator-runtime 需要安装

参考 babel7 全套 @ babel / polyfill

将babel-loader的配置放入单独的文件

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "corejs"3,
        "useBuiltIns""usage"
      }
    ]
  ]
}

配置修改为

{
    test:/\.js$/,
    exclude/node_modules/,
    loader:"babel-loader"
}

3.图片资源(包括字体)

直接图片资源

使用url-loader 包括file-loader同时可以将图片转base64 安装:

npm install url-loader -D

在入口js中 import “../css/homepage.css" 在homepage.css 中 使用background引入png , npx webpack 后报错 找不到对应loader。

由此可知不管有没有使用样式,通过入口文件引入的module/文件 都需要有loader进行处理。webpack默认只能处理js

{
    test:/\.(png|jpe?g|gif)$/,
    use:[
      {
        loader:"url-loader",
        options: {
          name"[name]_[contenthash:8].[ext]",
          outputPath"images/", //生成后存放的路径
          limit10000 //1024为1kb 小于10000(8kb),才转换成base64 
        }
      }
    ]
}

此时会报错 Error: Cannot find module 'file-loader' url-loader内部会使用file-loader 补充安装 npm i file-loader -D

iconfont图标

iconfont-图标库

  • Symbol

第一步:引入项目下面生成的 symbol 代码:

<script src="./iconfont.js"></script>

第二步:加入通用 CSS 代码(引入一次就行):

<style>
.icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
 }
 </style>

第三步:挑选相应图标并获取类名,应用于页面html:

<svg class="icon" aria-hidden="true">
  <use xlink:href="#icon-xxx"></use></svg>

iconfont.js处理svg不需要使用loader进行处理 如果入口js中使用了 svg文件呢?(todo)

  • Font class 、Unicode

在js中引入iconfont.css 同时增加rule

{
    test: /\.(eot|ttf|woff|woff2|svg)$/,
    use: {
      loader:"file-loader",
      options:{
        name: "[name]_[contenthash:8].[ext]",
        outputPath:"font/"
      }
    }
},

html页面中引入

  <span class="iconfont icon-tupian"></span>

此时会将font文件打包到指定位置,同时css中的路径会自动更改

四.webpack-dev-server

webpack-dev-server文档 安装  npm install webpack-dev-server -D

此时调用webpack-dev-server时 报错 Error: Cannot find module 'webpack-cli/bin/config-yargs' 各项版本为 "webpack": "^5.0.0", "webpack-cli": "^4.0.0", "webpack-dev-server": "^3.11.0" 可能webpack-dev-server还没有与最新的webpack-cli兼容 修改版本降级为如下 "webpack": "4.44.2", "webpack-cli": "3.3.12", "webpack-dev-server": "^3.11.0" 成功执行 执行后是查看不了dist目录的,代码在内存中

Proxy 解决跨域使用本地mock

创建本地serve 端口3000 http://localhost:3000/api/homepage

本地项目端口8080 在项目中直接使用

axios.get('http://localhost:3000/api/homepage').then(res=>{
console.log(res)
})

会出现跨域报错 Access to XMLHttpRequest at 'xxx' from origin '###' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

在devServer中配置proxy

module.exports = {
  ...
 devServer: {
    contentBase: path.join(__dirname, "dist"),
    openPage:"homepage.html",
    open:true,
    proxy: {
      "/api": {
        target: "http://localhost:3000"
      }
    }
  },
  ...
}

再把代码中的 请求前缀去掉 如下

axios.get('/api/homepage').then(res=>{
console.log(res)
})

即可成功获取数据

模块热替换(HMR)

devServer字段 hot:true 开启 hotOnly:true 开启失败也不会刷新浏览器

css 热替换

  • 不能使用contenthash和chunkhash会报错
  • 使用mini-css-extract-plugin分离后的css不生效

js 热替换(todo)

五.sourceMap

dev模式默认打开 推荐配置  devtool:"cheap-module-eval-source-map",//开发环境配置 //线上不不推荐开启 devtool:"cheap-module-source-map", // 线上⽣生成配置

六.优化配置

在production环境下会自动开启 css/js/html压缩

loader配置

include: path.resolve(__dirname, "./src"),//只在此目录查找处理

resolve

module.exports = {
    resolve:{
        alias:{
          '@':path.resolve(__dirname,"./src"//别名,在编码中 使用@代替快速定位src
        },
        extensions:['.js'], //扩展名省略的配置
        modules: ["node_modules")], //指定第三方库查询路径 否则会向上查询
        
      },
 }

externals配置cdn

externals: {
          //配置之后可以使用import的方式引入jQuery 同时 在打包时不会打包jquery的库进入项目
          'jquery''jQuery'
 }

七.区分环境配置

1.安装

npm install webpack-merge -D

用来合并配置

const { merge } = require("webpack-merge")
const baseConfig = require("./webpack.base.js") //新建的公共部分配置文件
module.exports = merge(baseConfig,{

})

2.安装

npm install cross-env -D

用来创建一个变量(NODE_ENV)可以使用process.env访问 即process.env.NODE_ENV
cross-env主要解决了追加环境变量不同系统配置时的兼容问题

"build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js", 
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js"

--config 指定webpack的配置文件,默认为webpack.config.js NODE_ENV=production :创建了NODE_ENV的环境变量,在node中可以通过process.env.NODE_ENV 取得其值,为production 因此在代码里面可以添加逻辑

cross-env 和 webpack-merge是无关连的。使用process.env.NODE_ENV也可以使用逻辑代码修改配置文件的导出

之前我进入误区 一直想,有了process.env.NODE_ENV为啥还需要--config 或者webpack-merge都可以省略了。 从实现的角度,的确可以。还是两者结合搭配写配置更容易维护

3.在改完配置后,构建时报了一堆目录错误。因为此时配置文件的位置改变了。
因此理解了path.resolve这个方法。 path.resolve(__dirname,'../src') 第二个参数的路径。相当于在当前位置(代码文件的位置)找到src在项目中的相对路径

此时代码位置 为config/webpack.base.js 找到src则需要 ../src

 八.tree shaking 和 code Splitting (todo)

终.现阶段完整配置代码

github.com/woccsang/le…