webpack从零开始-不断优化,从不止步

概念

webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler),分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用,类似于中间件,代处理模式。

在这里插入图片描述
中文文档:https://webpack.docschina.org/

学习webpack有4个重点内容:

  • 入口(entry)
  • 输出(output)
  • 加载器(loader)
  • 插件(plugins)

安装

npm install 包名称 --save-dev
后面加上 --save-dev 方式,代表只在开发dev使用

npm init -y
npm install --save-dev webpack webpack-cli

使用

代码目录结构:
在这里插入图片描述
注意一般的报错:
1.浏览器只识别基本的js,css,html
2.在引入的文件中使用了node方式的代码(require),而这种代码浏览器并不能识别
解决:
1.使用webpack打包,将浏览器不能识别的代码转换为浏览器可识别的代码
2.输入命令:webpack ./src/app.js,会自动将指定的app.js打包转换为./dist/main.js
3.在页面中引入打包转换后的main.js

02-webpack.config.js

使用webpack.config.js实现webpack的配置

添加一个webpack.config.js文件,注意文件名称绝对不能修改

  • entry:设置你的入口文件,说白了就是你想打包转换的文件路径

  • output:设置目标文件的全路径

    • path:设置目标文件的目录

    • filename:设置目标文件的文件名称

      var path = require('path')
      module.exports = {
          // 设置文件的入口:一开始就解析这个文件
          entry:'./src/app.js',
          // 将入口文件解析为目标文件的配置
          output:{
              // 目标文件的输出路径文件夹名称
              path:path.join(__dirname,"dist",),
              // 目标文件的文件名称
              filename:'main.js'
          }
      }
      
  • 输入命令:webpack

03-webpack-dev-server

自动打开浏览器,同时在修改源代码的时候页面实现自动刷新

实现:它会创建一个内存服务器,将入口文件解析转换之后放在这个服务器托管,我们所请求其实就是这个服务器上面的资源

1.每次修改代码,会自动的解析转换并托管,重新发起请求—所以可以实现自动刷新

2.如果调用webpack-dev-server的时候能够添加–open,它会自动打开浏览器

  • 下载包:npm i webpack-dev-server --save-dev

  • 在webpack.config.js中进行服务器开发的配置

    module.exports = {
        // 设置文件的入口:一开始就解析这个文件
        entry:'./src/app.js',
        // 将入口文件解析为目标文件的配置
        output:{
            // 目标文件的输出路径文件夹名称
            path:path.join(__dirname,"dist"),
    
            // publicPath: '/dist',
            // 目标文件的文件名称
            filename:'main.js'
        },
        // 建议使用这个配置,新版本建议这样配置,默认会生成main.js
        // 端口如果不设置,默认为8080
        devServer:{
            publicPath: '/dist',
            port:8080 
        }
    }
    
  • 运行 webpack-dev-server --open

04-webpack解析css

默认情况下,webpack不能打包转换css文件,在进行必要的配置之前,会报如下错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GvZs5T8g-1617515199958)(images\03-webpack-config-err.png)]

  • 这种错误信息一般就告诉我们你现在项目中的文件没有合适的解析器进行处理,所以你得去 下载+配置

  • 解决过程:

    • 下载:npm install css-loader style-loader --save-dev

      • css-loader:css解析器,将css解析为浏览器可以识别的类型
      • style-loader:自动的在指定文件中添加style标签,同时添加指定的样式代码
    • 在webpack.config.js文件中添加配置

      // 下面这个成员就是不同类型的文件的解析加载规则
      module: {
          rules: [
              // 配置的是用来解析.css文件的loader(style-loader和css-loader)
              {
                  // 用正则匹配当前可被处理的文件的后缀名是  .css
                  test: /\.css$/,
                  // css-loader:读取css代码并解析为浏览器可以识别的代码
                  // style-loader:把css代码添加到网页中
                  use: ['style-loader', 'css-loader'] //webpack底层调用这些包的顺序是从右到左
              }
          ]
      }
      
05-webpack解析less和scss

在开发的时候,我们一般会根据需要使用less或者scss来创建样式,默认情况下,webpack并不能解析这两种预处理器,所以需要进行单独的下载和配置

  • 下载 +引入

    • 安装less解析loader

      npm i less less-loader --save-dev 
      
    • 安装scss解析loader

      npm i sass-loader node-sass --save-dev
      
  • 添加配置

    // webpack.config.js文件中
    // 配置less解析
    {
        test: /\.less$/,
            use: [{
                loader: 'style-loader'
            }, {
                loader: 'css-loader'
            }, {
                loader: 'less-loader'
            }]
    },
    // 配置scss解析
    {
    	test: /\.scss$/,
    		use: [{
    			loader: 'style-loader'
    		}, {
    			loader: 'css-loader'
    		}, {
    			loader: 'sass-loader'
    		}]
    }
    
06-提取 css
如果用编辑器打开bundle.js文件会发现内容有document.createElement("style")字样,其实css被打包到bundle.js中了。

假如 css 的内容很多,会让 bundle.js 文件变得很大,加载变慢,性能和体验都很差,所以我们需要把 css 的内容单独拆分到一个样式文件中,使用 webpack插件ExtractTextWebpackPlugin
  • 安装依赖包

    npm install extract-text-webpack-plugin@next --save-dev
    

注意:@next是下载最新版本

  • 添加配置

    //  导入提取样式的webpack插件
    const ExtractTextPlugin = require("extract-text-webpack-plugin");
    
    
    module.exports = {
        // 其他配置...
    
        // 模块加载器配置项
        module: {
            rules: [
                // {
                //     test: /\.css$/,			// 匹配css扩展名文件
                //     use:[					// 配置loader加载器
                //         'style-loader',		// 把css代码写入到网页中
                //         'css-loader'		// 读取css的代码
                //     ]
                // },
                {
                    test: /\.css$/,
                    use: ExtractTextPlugin.extract({	// 提取css
                        // 编译后用什么loader来提取css文件
                        fallback: "style-loader",
                        // 需要什么样的loader去编译文件
                        use: ["css-loader"]
                      })
                },
                // {
                //     test: /\.less$/,		// 匹配less扩展名文件
                //     use:[
                //         'style-loader',		// 把less代码写入到网页中
                //         'css-loader',		// 读取less的代码
                //         'less-loader'		// 解释编译less代码
                //     ]
                // },
                {
                    test: /\.less$/,
                    use: ExtractTextPlugin.extract({	// 提取less
                        fallback: "style-loader",
                        use: ["css-loader", "less-loader"]
                      })
                },
                
                // 其他配置...
            ]
        },
    
        plugins: [
            new ExtractTextPlugin('style/style.css') // 提取到dist的style文件夹中
        ]
    };
    
07-清除dist

使用 clean-webpack-plugin插件 在每次打包前清除下dist文件夹。

安装依赖包

npm install --save-dev clean-webpack-plugin 

配置

// 其他代码:webpack.config.js

// 导入清除插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    // 其他配置

    plugins: [
        new ExtractTextPlugin("style/style.css"),
		
        // 调用清除打包目录插件
        new CleanWebpackPlugin(),
        
        new HtmlWebpackPlugin({
            template: "public/index.html"
        }),
    ]
};

08-webpack-图标+图片

在项目中导入图片或者图标的时候,默认情况下也不能被正确的解析,需要我们对webpack进行单独的配置

在项目根目录下添加images文件夹,并拷贝一张图片进来进行测试

  • 演示代码

    // app.js
    mport logo from "../images/border.jpg"
    
    var element = document.createElement("div");
    // 添加显示图片
    element.innerHTML =  `<img src="${logo}" />`
    document.body.appendChild(element)
    
  • 下载:npm install file-loader --save-dev

  • 添加配置:

    {
        test: /\.(png|jpg|gif|eot|svg|ttf|woff)/,
        use: [{
            // file-loader处理文件后会返回一个链接
            loader: 'file-loader',
            options: {
                publicPath: "./dist/images/", // 引入图片时会在路径前面加上该选项
                outputPath: "images" // 输出到dist下的images目录
            }
        }]
    }
    
09-webpack-babel

一些老版的浏览器可能不支持ES6,这个babel的作用就是能够将ES6转换ES5,达到兼容的目的

  • 下载:npm install babel-loader @babel/core @babel/preset-env --save-dev

  • 配置

    {
        test: /\.js$/,
    	// Webpack2建议尽量避免exclude,更倾向于使用include
    	// exclude: /(node_modules)/, // node_modules下面的.js文件会被排除
    	include: [path.resolve(__dirname, 'src')],
    		use: {
    			loader: 'babel-loader',
    			// options里面的东西可以放到.babelrc文件中去
    			options: {
    				presets: ['@babel/preset-env']
    			}
    		}
    }
    
10-html-webpack-plugin
目前我们都是在 index.html 中手动引入打包后的资源,这种引入方式有很多缺点,比如文件名依赖问题,假如 webpack 配置中的输出文件名修改了,需要及时在 index.html 中同步修改,再者每次新增文件都要引入一遍很繁琐
我们可以使用 HtmlWebpackPlugin插件 自动引入打包后的资源文件到html文件,该插件需要指定一个html模板文件,并且会生成一个 index.html 文件到 dist 目录中
如果没有指定默认的模板文件,这个插件可以帮助我们自动的生成一个模板文件,并实现资源的自动的引入
  • 下载安装

    npm i --save-dev html-webpack-plugin
    
  • 添加配置

    // 1. 引入
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    
    module.exports = {
       	// 其他配置 ....
        
        plugins: [
            // + 新增配置
            new HtmlWebpackPlugin({
                template: "index.html",	// template指定默认html模板
                filename:'index.html', // 指定生成的目标文件
                inject:'head' // 指定js文件的注入位置
            })
        ]
    };
    
  • 细节

    • 由于会自动的生成页面文件,且这个页面文件会放置到dist文件夹中,所以之前图片设置的publicPath需要修改为:"./images/"
    • 添加了这个插件后,不再需要设置webpack-dev-server了
11-错误追踪

我们先来做一个错误追踪的测试,新建一个error.js

src/error.js

const error = function(){
    var a = 123;
    a.push(456);
}

export default error;

注意: 上面的代码运行会报错,a没有push方法。

src/index.js

import './style.css';
import './style.less'
import logo from "../images/logo.jpg"

// + 导入错误的模块
import error from "./error"

// 执行会报错的函数
error();

// 其他

执行打包命令

npm run start

刷新dist/index.html,可以看到以下的错误信息。

Uncaught TypeError: 123.push is not a function										bundle.js:1 
    at bundle.js:1
    at Module.<anonymous> (bundle.js:1)
    at t (bundle.js:1)
    at bundle.js:1
    at bundle.js:1

上面我们写了一个错误的函数,但是浏览器的在报错的时候提示的错误文件是bundle.js,这当然是正常的,因为这是我们最后打包出来的文件,但是我们可以通过webpack的source map准确地知道错误来自于哪个源文件。

webpack.config.js

// 其他代码
module.exports = {
    // 其他配置

    devtool: "source-map", // + 生成映射源代码文件

    // 模块加载器配置项
    module: {
        // 其他代码
    },
    
    // 其他配置 

注意: 上面的 devtool:“source-map” 配置会在dist目录中生成一个bundle.js.map文件,该文件主要的作用是把打包后的bundle.js映射到源文件上,这样就可以准确的追踪报错的源代码的位置了。

bundle.js.map文件也会加载到页面中,并且文件体积很大,所以此模式只适用于开发环境。

再次执行打包命名,查看错误提示

Uncaught TypeError: 123.push is not a function										error.js:3 
    at error.js:3
    at Module.<anonymous> (index.js:9)
    at t (bootstrap:19)
    at bootstrap:83
    at bundle.js:1

此时错误就很精确了,error.js 第3行。

12-生产环境
1.生产环境和开发环境刚好相反,开发环境在本地运行,而生产环境是要产出运行在线上服务器面向用户使用的代码,因此两者的构建目标差异很大,比如打包后的文件在生产环境中要尽可能的小,逻辑代码分离,优化静态资源(压缩图片),去除 source map文件等。

2.因此开发环境和生产环境不能共用一份webpack配置文件,需要分别指定

3.但是两个环境还是有很多配置可以共用的,比如entry、output、module等,因此可以把公共部分的配置抽离出来放到一个独立的文件然后进行合并,我们可以使用webpack-merge工具来进行合并。

注意:entry、output、module这些配置在我们当前示例可以通用,但未必适合所有项目。
  • 安装依赖

    npm install --save-dev webpack-merge
    
  • 开始拆分webpack.config.js文件,拆分后该文件可废弃。

    // 新建config文件夹:
    
    - webpack-demo
    	- config 				// 存放配置文件的文件夹
    		- webpack.base.js	// 公共的配置
    		- webpack.dev.js	// 开发环境的配置
    		- webpack.pro.js	// 生成环境的配置
    
    	- // 其他文件
    

进阶

多入口和输出

多入口需要修改entry配置,理由很简单,**我们一个页面往往需要引入多个js文件。**在这之前我们都是把src/index.js打包成dist/bundle.js引入到项目中,那如果有多个index.js类型的文件呢?

为了演示方便,我们先清空下src文件夹,再添加新文件:

- webpack-demo
	- src
		- index.js
		- about.js

**注意:**index.js和about.js没有任何关系,都是独立的不相互引用。

src/index.js

var element = document.createElement("span");
element.innerHTML =  `hello`;
document.body.appendChild(element);

src/about.js

var element = document.createElement("div");
element.innerHTML =  `about`;
document.body.appendChild(element);

config/webpack.base.js

// 其他代码

module.exports = {
    // 用对象的方式配置多个入口
    entry: {
        index: "./src/index.js",
        about: "./src/about.js"
    },
    output: {
        // 修改输出路径和文件名,[name]是动态的,读取entry的属性
        filename: "js/[name].bundle.js",			
        path: path.resolve(__dirname, "../dist")
    },
    
    // 其他代码
}

为了方便查看代码,我们执行npm run build命令,可以看到 dist 的结构如下

- webpack-demo
	- dist
		- js
			- index.bundle.js
			- about.bundle.js
		- index.html

在浏览器中打开index.html可以看到同时引入两个 js 文件,使用开发服务器 npm run dev 打开效果一致。

提取公共模块

我们来做一个测试,把一个 jquery.js 作为公共文件放到src/utils目录中。

- webpack-demo
	- src
		- utils 		// + 公共的模块
			- jquery.js 	// + 测试用的公共文件
		- index.js
		- about.js

然后把src/utils/jquery.js分别引入到 index.js 和 about.js 中。

import jquery from "./utils/jquery";

// 其他代码

执行构建命令

npm run build

查看打包后的 about.bundle.jsindex.bundle.js 文件源码,会发现它们都把 jquery.js 打包进去了,这样做的后果不敢想象。所以我们需要使用 CommonsChunkPlugin 插件把类似公共的依赖模块提取到一个单独的文件中。

config/webpack.base.js

// 其他代码

module.exports = {
    
    // 其他代码
    
    // + 提取公共模块配置
    optimization: {
        // 分割的块
        splitChunks: {
            chunks: 'all'	// 提取所有文件的共同模块
        }
    },
    
    module: {
        // 其他代码
    },
    
    // 其他代码
}

再次执行打包

npm run build

可以看到当前项目的公共模块 jquery 的内容已经被打包到一个 独立的 about~index.bundle.js文件中了,当然这个文件名可以通过配置修改的。

**注意:**公共模块的大小必须大于 30kb才会被独立打包,jquery 的大小是 87kB

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值