webpack实践指南(基础篇)

196 阅读4分钟

引言

前端工程化学习是前端进阶的必经之路,而webpack作为前端打包构建的优秀产物可以让我们更加清晰的学习和认识前端整体运行生命周期。同时基于工程化构建工具可以进阶学习性能监控,脚手架搭建,埋点工具等高级开发。

一:目录搭建

  1. 创建文件夹work2,初始化项目

     npm init -y
    
  2. 安装webpack

     npm install webpack webpack-cli --save-dev       
        
    
  3. 创建资源文件,webpack配置文件,打包输出文件

image.png

  • webpack.config.js:webpack配置文件
  • dist目录 :资源打包输出文件夹
  • src目录 :目标资源文件夹
  • public目录:静态htm模板文件

一:entry

entry作为webpack入口文件,告诉webpack从哪个文件开始打包构建

方式一:单入口不指定key

entry:'./src/index.js',

方式二:单入口指定key

指定入口文件,同时添加文件的key(可以在output配置的filename中作为输出文件名使用)

entry:{
    bundle:'./src/index.js'
}

二:output

output作为webpack的打包输出目录,告诉webpack打包后的产物存储的路径。

filename的配置

filename的名称配置通常有[name]和[contenthash]

  1. name: 根据entry配置的文件key决定,如果没有配置默认是main

  2. contenthash: 根据打包文件内容生成唯一hash值。

    module.exports = {
       entry:'./src/index.tsx',
       output:{
         path:path.resolve(__dirname,'dist'),//保存的目录
         filename:'[name].[contenthash].bundle.js',//打包后文件名称
         clean: true// 编译前清除输出的目录
       },
    }
    

三:mode

mode指定了webpack当前打包构建的环境,主要有:

  • development:开发环境

  • production:生产环境

      module.exports = {
        mode:'development',//开发环境
        entry:'./src/index.tsx',
        output:{
          path:path.resolve(__dirname,'dist'),//保存的目录
          filename:'[name].[contenthash].bundle.js',//打包后文件名称
          clean: true// 编译前清除输出的目录
        },
     }
    

四:resolve

resolve告诉webpack如何解析文件路径。

  • extensions字段告诉webpack解析文件后缀默认按tsx,ts,js顺序查找文件

  • alias可以为项目配置指定快捷路径

      resolve: {
          extensions: ['.tsx', '.ts', '.js'],
          alias:{
            '@':"./src", // @ 代表 src 路径
          }
        },
    

五:loader

webpack最核心的功能就是loader,loader可以将众多开发资源:css,less,sass,jpg,toff等非js文件进行打包构建,因此对于不同的资源文件需要借助对应的loader进行加载构建。

1. 图片资源

    module.exports = {
      mode:'development',//开发环境
      entry:'./src/index.tsx',
      output:{
        path:path.resolve(__dirname,'dist'),//保存的目录
        filename:'[name].[contenthash].bundle.js',//打包后文件名称
        clean: true// 编译前清除输出的目录
      },
      module:{
          rules:[
              {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: "asset/resource",
              },
          ]
      }
   }

src/index.js测试

测试发现图片可以被模块化导入使用

 import img1 from  "./assets/1.jpg";
 const oImg1 = document.createElement('img');
 oImg1.src = img1;
 document.body.appendChild(oImg1);
 

2.css资源

2.1 安装

 npm install --save-dev style-loader css-loader

2.2 配置

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

3.less资源

3.1 安装

 npm install --save-dev less-loader less

3.2 配置

   rules:[
       {
        test: /.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
   ]

4.sass资源

4.1 安装

 npm install --save-dev sass-loader sass

4.2 配置

   rules:[
       {
        test: /.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
   ]

六:plugins

plugins主要用于webpack打包构建过程中起到辅助插件的作用。

6.1 HtmlWebpackPlugin

HtmlWebpackPlugin可以在打包构建资源时使用自定义html模板,将打包后的js动态的插入html中

安装

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

配置

plugins:[
    //自动创建html,并且导入打包的js文件
    new HtmlWebpackPlugin({
      //以当前目录下的index.html为模板
      template:'./public/index.html',
      //在body标签中生成script标签
      inject:'body',
      //文件名
      filename: '[name].html'
    }) 
  ],

七:devServer

webpack每次资源更新时都需要手动重新运行npm打包构建,借助devServer可以十分方便的监听资源的更新自动的执行打包构建。

    devServer:{
        static:{
          directory:path.resolve(__dirname,"./dist")
        }
  },

修改package.json

"scripts": {
    "dev": "npx webpack serve --open --config ./webpack.config.js",
    "build": "npx webpack serve --open --config ./webpack.config.js"
  },

八:代码映射soruce-map

当 webpack 打包源代码时,我们很难从打包后的代码文件中找到错误发生的具体位置,基于soruce-map可以很便捷的实现代码位置映射。通常为了考虑性能,我们只需为开发环境配置代码source-map

devtool:"eval-cheap-module-source-map",

九:react+ts环境搭建

9.1 下载

npm i react react-dom @types/react @types/react-dom typescript esbuild-loader -D

9.2 创建文件tsconfig.json

  {
    "compilerOptions": {
        "outDir": "./dist/",
        "noImplicitAny": true,
        "module": "es6",
        "target": "es5",
        "jsx": "react",
        "allowJs": true,
        "moduleResolution": "node",
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
      }
}

9.3 配置识别react文件的loader

   {
    test: /\.(js|ts|jsx|tsx)$/,
    // include: paths.appSrc,
    use: [
      {
        loader: 'esbuild-loader',
        options: {
          loader: 'tsx',
          target: 'es2015',
        },
      }
    ]
  },

十:环境拆分

开发环境和生产环境在部分目标下追求是不同的,例如我们在开发环境下会考虑开启source-map代码映射,开启devServer等,而生产环境为了考虑性能和体积是不需要这些配置的。因此我们可以借助webpack-merge完成配置拆分

10.1 安装

  npm i webpack-merge -D
  

10.2 创建webpack配置文件

  * webpack.common.js-共同配置
  * webpack.dev.js-开发配置
  * webpakc.prod.js-生产配置
  

10.3 webpack.common.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const {templateHtml,rootPath,input,rootPath} = require("./path");
const commonConfig = {
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    alias:{
      '@':rootPath, // @ 代表 src 路径
    }
  },
  entry:input,
  plugins:[
    //自动创建html,并且导入打包的js文件
    new HtmlWebpackPlugin({
      //以当前目录下的index.html为模板
      template:templateHtml,
      //在body标签中生成script标签
      inject:'body',
      //文件名
      filename: '[name].html'
    }) 
  ],
  module:{//loader的处理
    rules:[
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        // include: "/src",
        type: "asset/resource",
      },
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
      {
        test: /.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      {
        test: /\.(js|ts|jsx|tsx)$/,
        // include: paths.appSrc,
        use: [
          {
            loader: 'esbuild-loader',
            options: {
              loader: 'tsx',
              target: 'es2015',
            },
          }
        ]
      },
    ]
  },
}
module.exports = commonConfig;

10.4 webpack.dev.js

const common = require("./webpack.common");
const {devServerPath} = require("./path");
const { merge } = require('webpack-merge')
const devConfig = {
  mode: 'development',
  output:{
    path:output,
    filename:'[name].bundle.js',
    clean: true// 编译前清除输出的目录
  },
  devtool: 'eval-cheap-module-source-map',
  devServer:{
    static:{
      directory:devServerPath
    }
  },
}
module.exports = merge(common,devConfig);

10.5 webpack.prod.js

const common = require("./webpack.common");
const { merge } = require('webpack-merge')
const prodConfig = {
  mode: 'production',
  output:{
    path:output,
    filename:'[name].[contenthash].bundle.js',
    clean: true// 编译前清除输出的目录
  },
}
module.exports = merge(common,prodConfig);

10.6 修改package.json

   "scripts": {
    "dev": "npx webpack serve --open --config ./config/webpack.dev.js",
    "build": "npx webpack serve --open --config ./config/webpack.prod.js"
  },
  

参考资料

跟着清汤姐学滴 juejin.cn/post/699163…