资讯专栏INFORMATION COLUMN

从基础到实战 手摸手带你掌握新版Webpack4.0详解 一起读文档

王军 / 2642人阅读

摘要:构建构建就是把源代码转换成发布到线上的可执行代码,包括如下内容。自动刷新监听本地源代码的变化,自动重新构建刷新浏览器。自动发布更新完代码后,自动构建出线上发布代码并传输给发布系统。将文件放入到项目中,在中新建一个放字体图标的文件夹。

项目地址 github.com/wudiufo/Web…

知识点概览:

Loader,HMR ,Create React App, Caching, Plugin, SourceMap,Vue Cli 3.0 ,Shimming, WebpackDevServer,TreeShaking, CodeSplitting, Babel, React , Library, Eslint ,PWA, Vue, Mode,性能优化,多页应用,原理, PreLoading, PreFetching ,环境变量,TypeScript

收获:

彻底学会Webpack的配置 理解 Webpack的作用及原理 上手项目的打包过程配置 拥有工程化的前端思维 步入高级前端工程师行列

一:初识Webpack

官网图镇楼:

1. 1 什么是WebPack

webpack 是一个现代 JavaScript 应用程序的静态模块打包工具:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并生成一个或多个 bundle,将其打包为合适的格式以供浏览器使用。

webpack构建:

构建就是把源代码转换成发布到线上的可执行 JavaScrip、CSS、HTML 代码,包括如下内容。

1.代码转换:TypeScript 编译成 JavaScript、SCSS或Less 编译成 CSS 等。

2.文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。

3.代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。

4.模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。

5.自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器,nodemon。

6.代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。

7.自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。

构建其实是工程化、自动化思想在前端开发中的体现,把一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。 构建给前端开发注入了更大的活力,解放了我们的生产力,更加方便了我们的开发。

1.2 什么是 webpack 模块

ES2015 import 语句

CommonJS require() 语句

AMD definerequire 语句

css/sass/less 文件中的 @import 语句。

样式(url(...))或 HTML 文件()中的图片链接

详细请看官网文档:Modules MODULES

1.3 搭建Webpack环境

去官网下载node

// 查看node版本号
node -v
// 查看npm版本号
npm -v

1.4 初始化项目
mkdir webpack-productname
cd webpack-productname 
//初始化webpack配置清单package.json
npm init -y   
1.5 安装webpack
//全局安装(不推荐),因为如果有两个项目用了webpack不同版本,就会出现版本不统一运行不起来的情况。只有卸了当前版本安装对应版本非常麻烦。
npm install webpack webpack-cli -g
//查看版本
webpack -v
//全局卸载
npm uninstall webpack webpack-cli -g
//在项目里安装webpack(推荐使用)。可以在不同项目中使用不同的webpack版本。
cd webpack-productname
npm install webpack webpack-cli -D
//查看版本
npx webpack -v
//查看对应包的详细信息
npm info webpack
//安装指定版本包
npm install webpack@4.16.1 webpack-cli -D

注意:

由于npm安装走的是国外的网络,比较慢容易出现安装失败的现象。

可以用yarn安装,首先得全局安装yarn,npm install yarn -g

或使用nrm快速切换npm源,首先得全局安装nrm, npm install -g nrm

nrm 使用:

nrm ls 查看可选源。

nrm test npm 测试速度。看哪个快就use哪个。

nrm use cnpm 使用cnpm 。

webpack-cli:使我们们可以在命令行里正确的使用webpack

1.6 webpack的配置文件

webpack 开箱即用,可以无需使用任何配置文件。然而,webpack 会假定项目的入口起点为 src/index,然后会在 dist/main.js 输出结果,并且在生产环境开启压缩和优化。通常,你的项目还需要继续扩展此能力,为此你可以在项目根目录下创建一个 webpack.config.js 文件,webpack 会自动使用它。

在项目根目录下创建 webpack.config.js 文件,这是webpack默认配置文件

const path = require("path")

module.exports = {
    //默认是production,打包的文件默认被压缩。开发时可以设置为development,不被压缩
    mode:"production", 
    //打包项目的入口文件
    entry: "./index.js",
    //打包项目的输出文件
    output: {
        //自定义打包输出文件名
        filename:"bundle.js",
        //输出文件的绝对路径
        path: path.resolve(__dirname,"bundle")
    }
}

也可以自己指定配置文件来完成webpack的打包:

npx webpack --config + 自定义配置文件

详细请看官方文档:概念 配置

1.7 webpack打包输出内容
执行 `npm run build` 后,在控制台输出

Hash:1b245e275a547956bf52 //本次打包对应唯一一个hash值
Version:webpack 4.29.6 //本次打包对应webpack版本
Time:162ms Built at:2019-4-11 23:13:43 //本次打包耗时,及打包的时间
Asset Size Chunks Chunk Names //打包后的文件名,大小,id,入口文件名
bundle.js 1.36 KiB 0 [emitted] main 
Entrypoint main=bundle.js
[0]./src/index.js 159 bytes {0}[built]
[1]./src/header.js 187 bytes {e}[built]
[2]./src/sidebar.js 193 bytes {e}[built]
[3]./src/content.js 193 bytes {e} [built]

二:Webpack核心概念 LOADER 2.1 什么是Loader

webpack可以使用 loader 来预处理文件,就是通过使用不同的Loader,webpack可以把不同的静态文件都编译成js文件,比如css,sass,less,ES6/7,vue,JSX等。

使用Loader打包静态资源

支持加载图片文件

需要安装 file-loader:解决CSS等文件中的引入图片路径问题

 npm install file-loader -D

webpack.config.js 里添加 loader 配置

module.exports = {
    //配置模块,主要用来配置不同文件的加载器
  module: {
      //配置模块规则
    rules: [
      {
        test: /.(png|jpg|gif)$/, //正则匹配要使用相应loader的文件
        use: [
          {
            loader: "file-loader", //要用到的loader
              options: {
                  //palceholder占位符
                  name:"[name].[ext]", //打包后的图片名字,后缀和打包的之前的图片一样
                  outputPath: "images/" //图片打包后的地址
              },
          },
        ],
      },
    ],
  },
};

详细请看官方文档:file-loader

将小图片转换成base64格式

需要安装 url-loader:当图片小于limit的时候会把图片BASE64编码,大于limit参数的时候还是使用file-loader 进行拷贝

npm install url-loader -D

webpack.config.js 里添加 loader 配置

module.exports = {
  module: {
    rules: [
      {
        test: /.(png|jpg|gif|bmp/)$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              name:"[name].[ext]",
              outputPath: "images/",
              limit: 8192 //小于8192b,就可以转化成base64格式。大于就会打包成文件格式
            }
          }
        ]
      }
    ]
  }
}

详细请看官方文档:url-loader


支持加载样式CSS文件

需要安装 css-loader style-loader:

npm install css-loader style-loader -D

webpack.config.js 里添加 loader 配置

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/, //匹配以css为后缀的文件
        use: ["style-loader", "css-loader"],//loader的执行顺序是从右向左,从下到上。css-loader:分析几个css文件之间的关系,最终合并为一个css。style-loader:在得到css生成的内容时,把其挂载到html的head里,成为内联样式。
      },
    ],
  },
};

支持加载样式SASS文件

需要安装 sass-loader node-sass:

npm install sass-loader node-sass -D

webpack.config.js 里添加 loader 配置

module.exports = {
    ...
    module: {
        rules: [{
            test: /.scss$/,
            use: [
                "style-loader", // 将 JS 字符串生成为 style 节点
                "css-loader", // 将 CSS 转化成 CommonJS 模块
                "sass-loader" // 将 Sass 编译成 CSS,默认使用 Node Sass
            ]
        }]
    }
};

为 css 样式属性加不同浏览器的前缀

为了浏览器的兼容性,有时候我们必须加入-webkit,-ms,-o,-moz这些前缀

Trident内核:主要代表为IE浏览器, 前缀为-ms

Gecko内核:主要代表为Firefox, 前缀为-moz

Presto内核:主要代表为Opera, 前缀为-o

Webkit内核:产要代表为Chrome和Safari, 前缀为-webkit

npm i postcss-loader autoprefixer -D

在项目跟目录下创建 postcss.config.js

module.exports = {
    plugins: [
        require("autoprefixer")
    ]
}

webpack.config.js

module.exports = {
    ...
    module: {
        rules: [{
            test: /.scss$/,
            use: [
                "style-loader", // 将 JS 字符串生成为 style 节点
                "css-loader", // 将 CSS 转化成 CommonJS 模块
                "postcss-loader",//配置在css-loader后,在sass|less|stylus-loader 之前。
                "sass-loader" // 将 Sass 编译成 CSS,默认使用 Node Sass
                
            ]
        }]
    }
};

给loader加一些配置项:

webpack.config.js

module.exports = {
    ...
    module: {
        rules: [{
            test: /.scss$/,
            use: [
                "style-loader", 
                {
                 	loader: "css-loader",
                    options:{
                        importLoaders:2 ,//如果sass文件里还引入了另外一个sass文件,另一个文件还会从sass-loader向上解析。如果不加,就直接从css-loader开始解析。// 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
                        modules: true //开启css的模块打包。css样式不会和其他模块发生耦合和冲突
                    }
                }, 
                "postcss-loader",
                "sass-loader", 
                
            ]
        }]
    }
};

为字体图标文件配loader

在 阿里巴巴矢量图标库中,把需要的字体图标下载到本地,解压。将iconfont.eot iconfont.svg iconfont.ttf iconfont.woff 文件放入到项目中,在src中新建一个放字体图标的文件夹font。将iconfont.css文件拷贝到项目中,自己改一下引入字体图标的路径。

需要安装 file-loader:

npm i file-loader -D

webpack.config.js

module.exports = {
    ...
    module: {
        rules: [{
            test: /.(eot|ttf|svg|woff)$/,
            use:{
                loader:"file-loader"
            }
        },
            ]
        }]
    }
};

详细请看官方文档:asset-management


plugin : 可以在webpack运行到某个时刻的时候,帮你做一些事情

使用plugins让打包更便捷

HtmlWebpackPlugin :htmlWebpackPlugin 会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中

安装:npm i html-webpack-plugin -D

基本用法:在 webpack.config.js 中:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "index.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "index_bundle.js"
  },
    plugins: [new HtmlWebpackPlugin({
        template: "src/index.html" //以index.html为模板,把打包生成的js自动引入到这个html文件中
    })]
};

CleanWebpackPlugin :自动清除上一次打包的dist文件

安装:npm i clean-webpack-plugin -D

基本用法:在 webpack.config.js 中:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const path = require("path");

module.exports = {
  entry: "index.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "index_bundle.js"
  },
    plugins: [
        new HtmlWebpackPlugin({
        template: "src/index.html" //在打包之后,以.html为模板,把打包生成的js自动引入到这个html文件中
    }),
        new CleanWebpackPlugin(["dist"]), // 在打包之前,可以删除dist文件夹下的所有内容
    
    ]
};

Entry与Output的基础配置

在打包多入口文件时的配置

基本用法:在 webpack.config.js 中:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const path = require("path");

module.exports = {
  entry: {
   	main: "./src/index.js",
    sub: "./src/index.js"
  },
  output: {
    publicPath: "http://cdn.com.cn", //将注入到html中的js文件前面加上地址
    path: path.resolve(__dirname, "dist"),
    filename: "[name].js"
  },
    plugins: [
        new HtmlWebpackPlugin({
        template: "src/index.html" //在打包之后,以.html为模板,把打包生成的js自动引入到这个html文件中
    }),
        new CleanWebpackPlugin(["dist"]), // 在打包之前,可以删除dist文件夹下的所有内容
    
    ]
};

详细请看官网:Output output-management


SourceMap 的配置

sourcemap:打包编译后的文件和源文件的映射关系,用于开发者调试用。

source-map 把映射文件生成到多带带的文件,最完整但最慢

cheap-module-source-map 在一个多带带的文件中产生一个不带列映射的Map

eval-source-map 使用eval打包源文件模块,在同一个文件中生成完整sourcemap

cheap-module-eval-source-map sourcemap和打包后的JS同行显示,没有映射列

development环境推荐使用: devtool: "cheap-module-eval-source-map", production环境推荐使用: devtool: "cheap-module-source-map",

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");

module.exports = {
	mode: "development",
    devtool: "cheap-module-eval-source-map",
	//devtool:"none",//在开发者模式下,默认开启sourcemap,将其关闭
    //devtool:"source-map"//开启映射打包会变慢
    //devtool:"inline-source-map"//不多带带生成.map文件,会将生成的映射文件以base64的形式插入到打包后的js文件的底部
    //devtool:"cheap-inline-source-map"//代码出错提示不用精确显示第几行的第几个字符出错,只显示第几行出错,会提高一些性能
    //devtool:"cheap-module-inline-source-map"//不仅管自己的业务代码出错,也管第三方模块和loader的一些报错
    //devtool:"eval"//执行效率最快,性能最好,但是针对比较复杂的代码的情况下,提示内容不全面
	//devtool: "cheap-module-eval-source-map",//在开发环境推荐使用,提示比较全,打包速度比较快
    //devtool: "cheap-module-source-map",//在生产环境中推荐使用,提示效果会好一些
	
	
	entry: {
		main: "./src/index.js"
	},
	module: {
		rules: [{
			test: /.(jpg|png|gif)$/,
			use: {
				loader: "url-loader",
				options: {
					name: "[name]_[hash].[ext]",
					outputPath: "images/",
					limit: 10240
				}
			} 
		}, {
			test: /.(eot|ttf|svg)$/,
			use: {
				loader: "file-loader"
			} 
		}, {
			test: /.scss$/,
			use: [
				"style-loader", 
				{
					loader: "css-loader",
					options: {
						importLoaders: 2
					}
				},
				"postcss-loader",
				"sass-loader",
				
			]
		}]
	},
	plugins: [new HtmlWebpackPlugin({
		template: "src/index.html"
	}), new CleanWebpackPlugin(["dist"])],
	output: {
		filename: "[name].js",
		path: path.resolve(__dirname, "dist")
	}
}

详细请看官网:devtool


使用WebpackDevServer 提升开发效率

解决每次在src里编写完代码都需要手动重新运行 npm run dev

1.在 package.json 中配置

{
  "name": "haiyang",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "bundle": "webpack",
    "watch": "webpack --watch",// 加--watch自动监听代码的变化
    
  },
  
}

2.在 webpack.config.js 中,加 devServer

安装 npm i webpack-dev-server –D

contentBase :配置开发服务运行时的文件根目录

open :自动打开浏览器

host:开发服务器监听的主机地址

compress :开发服务器是否启动gzip等压缩

port:开发服务器监听的端口

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");

module.exports = {
	mode: "development",
	devtool: "cheap-module-eval-source-map",
	entry: {
		main: "./src/index.js"
	},
+	devServer: {
		contentBase: "./dist",
		open: true,
		port: 8080,
    	proxy: {//配置跨域,访问的域名会被代理到本地的3000端口
      		"/api": "http://localhost:3000"
    	}
	},
	module: {
		rules: []
	},
	plugins: [],
	output: {
		filename: "[name].js",
		path: path.resolve(__dirname, "dist")
	}
}

在 package.json 中:

{
  "name": "haiyang",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "bundle": "webpack",
    "watch": "webpack --watch",// 加--watch自动监听代码的变化
    "start": "webpack-dev-server",//配置热更新
	
  },
 
}

详细请看官网 :dev-server

扩充知识:自己写一个类似webpackdevserver的工具

了解即可,功能不全,自行扩展。

在 package.json 中:

{
  "name": "haiyang",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "bundle": "webpack",
    "watch": "webpack --watch",// 加--watch自动监听代码的变化
    "start": "webpack-dev-server",//配置热更新
+	"server" : "node server.js" //自己写一个类似webpackdevserver的工具
  },
 
}

安装 :npm i express webpack-dev-middleware -D

在 项目根目录下创建 server.js 文件

在 server.js 中

const express = require("express");
const webpack = require("webpack");
const webpackDevMiddleware = require("webpack-dev-middleware");
const config = require("./webpack.config.js");
const complier = webpack(config);

const app = express();

app.use(webpackDevMiddleware(complier, {}));

app.listen(3000, () => {
	console.log("server is running");
});

模块热替换(hot module replacement)

在 package.json 中:

{
  "name": "haiyang",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server" //将文件打包到内存中,有助于开发
  },
}

在 webpack.config.js 中

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");

module.exports = {
	mode: "development",
	devtool: "cheap-module-eval-source-map",
	entry: {
		main: "./src/index.js"
	},
	devServer: {
		contentBase: "./dist",
		open: true,
		port: 8080,
+		hot: true,//开启热更新
+		hotOnly: true//尽管html功能没有实现,也不让浏览器刷新
	},
	module: {
		rules: [{
			test: /.(jpg|png|gif)$/,
			use: {
				loader: "url-loader",
				options: {
					name: "[name]_[hash].[ext]",
					outputPath: "images/",
					limit: 10240
				}
			} 
		}, {
			test: /.(eot|ttf|svg)$/,
			use: {
				loader: "file-loader"
			} 
		}, {
			test: /.scss$/,
			use: [
				"style-loader", 
				{
					loader: "css-loader",
					options: {
						importLoaders: 2
					}
				},
				"postcss-loader",
				"sass-loader",
				
			]
		}, {
			test: /.css$/,
			use: [
				"style-loader",
				"css-loader",
				"postcss-loader"
			]
		}]
	},
	plugins: [
		new HtmlWebpackPlugin({
			template: "src/index.html"
		}), 
		new CleanWebpackPlugin(["dist"]),
+		new webpack.HotModuleReplacementPlugin() //使用模块热更新插件
	],
	output: {
		filename: "[name].js",
		path: path.resolve(__dirname, "dist")
	}
}

index.js

//如果模块启用了HMR,就可以用 module.hot.accept(),监听模块的更新。
if (module.hot) {
  module.hot.accept("./library.js", function() {
    // 使用更新过的 library 模块执行某些操作...
  })
}

注意点:

引入css,用框架Vue,React 时,不需要写 module.hot.accept(),因为在使用css-loader,vue-loader,babel-preset时,就已经配置好了HMR,不需要自己写

详细请看官方文档:hot-module-replacement api/hot-module-replacement concepts/hot-module-replacement


使用 Babel 处理 ES6/7 语法 转义为ES5

BABEL官网:babeljs.io/setup

安装依赖包:

npm i babel-loader @babel/core @babel/preset-env -D
//生产依赖,兼容低版本浏览器
npm install --save @babel/polyfill

在 webpack.config.js 中

module: {
  rules: [
    {
        test: /.js$/,
     	exclude: /node_modules/,//不需要对第三方模块进行转换,耗费性能
     	loader: "babel-loader" ,
        options:{
            "presets": [["@babel/preset-env",{
                targets: {//这个项目运行在大于什么版本的浏览器上,已经支持es6的语法的高版本浏览器就不需要转义成es5了
                    edge: "17",
                    firefox: "60",
                    chrome: "67",
                    safari: "11.1",
                  },
                useBuiltIns:"usage" //按需添加polyfill,把用到的代码都转成低版本浏览器兼容的
            }]]
        }
    }
  ]
}

在 index.js 中:

//在业务代码运行之前最顶部导入
import "@babel/polyfill";
注意:在开发类库,第三方模块或组件库时不能用 @babel/polyfill 这种方案,因为会把声明的变量变成全局变量,会污染全局环境。

安装:

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
npm install --save @babel/runtime-corejs2

在 webpack.config.js 中

module: {
  rules: [
    {
        test: /.js$/,
     	exclude: /node_modules/,//不需要对第三方模块进行转换,耗费性能
     	loader: "babel-loader" ,
        options:{
            "plugins": [["@babel/plugin-transform-runtime",{
                "corejs": 2,
                "helpers": true,
                "regenerator": true,
                "useESModules": false
            }]]
        }
    }
  ]
}

由于babel需要配置的内容非常多,我们需要在项目根目录下创建一个 .babelrc 文件。

就不需要在 webpack.config.js 中写 babel 的配置了。

.babelrc 中:

{
            "plugins": [["@babel/plugin-transform-runtime",{
                "corejs": 2,
                "helpers": true,
                "regenerator": true,
                "useESModules": false
            }]]
        }

配置 React 代码的打包

业务代码:

.babelrc 中:

	{ 
            "presets": [
                ["@babel/preset-env",{
                targets: {
                    edge: "17",
                    firefox: "60",
                    chrome: "67",
                    safari: "11.1",
                  },
                useBuiltIns:"usage" 
            		}
                ],
                "@babel/preset-react"
            ]
        }
//执行顺序:从下往上,从右向左的顺序

安装:

npm i react react-dom --save
npm install --save-dev @babel/preset-react

详细内容请看官网:babel-loader


三:Webpack进阶 Tree Shaking:只支持 ES Module 例如 importexport 的静态结构特性的引入。当引入一个模块时,不引入所有的代码,只引入需要的代码

在 webpack.config.js 中:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");

module.exports = {
	mode: "development",
	devtool: "cheap-module-eval-source-map",
	entry: {
		main: "./src/index.js"
	},
	devServer: {
		contentBase: "./dist",
		open: true,
		port: 8080,
		hot: true,
		hotOnly: true
	},
	module: {
		rules: []
	},
	plugins: [],
+	optimization: { //在开发环境中加,生产环境不加
		usedExports: true
	},
	output: {
		filename: "[name].js",
		path: path.resolve(__dirname, "dist")
	}
}

在 package.json 中:

{
+ "sideEffects": ["*.css"], //对 所有的css文件 不使用Tree shaking。如果填 false,就是都需要用到Tree shaking
}

详细内容请看官网:tree-shaking


Develoment 和Production模式的区分打包

在项目根目录下创建两个文件,webpack.dev.js,webpack.prod.js

webpack.dev.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");

module.exports = {
	mode: "development",
	devtool: "cheap-module-eval-source-map",
	entry: {
		main: "./src/index.js"
	},
	devServer: {
		contentBase: "./dist",
		open: true,
		port: 8080,
		hot: true,
		hotOnly: true
	},
	module: {
		rules: [{ 
			test: /.js$/, 
			exclude: /node_modules/, 
			loader: "babel-loader",
		}, {
			test: /.(jpg|png|gif)$/,
			use: {
				loader: "url-loader",
				options: {
					name: "[name]_[hash].[ext]",
					outputPath: "images/",
					limit: 10240
				}
			} 
		}, {
			test: /.(eot|ttf|svg)$/,
			use: {
				loader: "file-loader"
			} 
		}, {
			test: /.scss$/,
			use: [
				"style-loader", 
				{
					loader: "css-loader",
					options: {
						importLoaders: 2
					}
				},
				"postcss-loader",
				"sass-loader",
				
			]
		}, {
			test: /.css$/,
			use: [
				"style-loader",
				"css-loader",
				"postcss-loader"
			]
		}]
	},
	plugins: [
		new HtmlWebpackPlugin({
			template: "src/index.html"
		}), 
		new CleanWebpackPlugin(["dist"]),
		new webpack.HotModuleReplacementPlugin()
	],
	optimization: {
		usedExports: true
	},
	output: {
		filename: "[name].js",
		path: path.resolve(__dirname, "dist")
	}
}

webpack.prod.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");

module.exports = {
	mode: "production",
	devtool: "cheap-module-source-map",
	entry: {
		main: "./src/index.js"
	},
	
	module: {
		rules: [{ 
			test: /.js$/, 
			exclude: /node_modules/, 
			loader: "babel-loader",
		}, {
			test: /.(jpg|png|gif)$/,
			use: {
				loader: "url-loader",
				options: {
					name: "[name]_[hash].[ext]",
					outputPath: "images/",
					limit: 10240
				}
			} 
		}, {
			test: /.(eot|ttf|svg)$/,
			use: {
				loader: "file-loader"
			} 
		}, {
			test: /.scss$/,
			use: [
				"style-loader", 
				{
					loader: "css-loader",
					options: {
						importLoaders: 2
					}
				},
				"postcss-loader",
				"sass-loader",
				
			]
		}, {
			test: /.css$/,
			use: [
				"style-loader",
				"css-loader",
				"postcss-loader"
			]
		}]
	},
	plugins: [
		new HtmlWebpackPlugin({
			template: "src/index.html"
		}), 
		new CleanWebpackPlugin(["dist"]),
		
	],
	
	output: {
		filename: "[name].js",
		path: path.resolve(__dirname, "dist")
	}
}

在 package.json 中:

{
  "scripts": {
    "dev": "webpack-dev-server --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
}

解决 webpack.dev.js,webpack.prod.js 存在大量重复代码,在项目根目录下创建一个 webpack.common.js 文件,把公共代码提取出来

安装 :

npm i webpack-merge -D 

webpack.common.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");

module.exports = {

	entry: {
		main: "./src/index.js"
	},
	
	module: {
		rules: [{ 
			test: /.js$/, 
			exclude: /node_modules/, 
			loader: "babel-loader",
		}, {
			test: /.(jpg|png|gif)$/,
			use: {
				loader: "url-loader",
				options: {
					name: "[name]_[hash].[ext]",
					outputPath: "images/",
					limit: 10240
				}
			} 
		}, {
			test: /.(eot|ttf|svg)$/,
			use: {
				loader: "file-loader"
			} 
		}, {
			test: /.scss$/,
			use: [
				"style-loader", 
				{
					loader: "css-loader",
					options: {
						importLoaders: 2
					}
				},
				"postcss-loader",
				"sass-loader",
				
			]
		}, {
			test: /.css$/,
			use: [
				"style-loader",
				"css-loader",
				"postcss-loader"
			]
		}]
	},
	plugins: [
		new HtmlWebpackPlugin({
			template: "src/index.html"
		}), 
        new CleanWebpackPlugin(["dist"],{
            root:path.resolve(__dirname,"../")
        }),
		
	],
	
	output: {
		filename: "[name].js",
		path: path.resolve(__dirname, "../dist")
	}
}

webpack.dev.js

const webpack = require("webpack");
const merge = require("webpack-merge")
const commenConfig = require("./webpack.commin.js")

const devConfig = {
	mode: "development",
	devtool: "cheap-module-eval-source-map",
	
	devServer: {
		contentBase: "./dist",
		open: true,
		port: 8080,
		hot: true,
		hotOnly: true
	},
	
	plugins: [	
		new webpack.HotModuleReplacementPlugin()
	],
	optimization: {
		usedExports: true
	},	
}
//将开发配置和公共配置做结合
module.exports = merge(commenConfig, devConfig)

webpack.prod.js

const merge = require("webpack-merge")
const commenConfig = require("./webpack.commin.js")

const prodConfig = {
	mode: "production",
	devtool: "cheap-module-source-map",
}
//将线上配置和公共配置做结合
module.exports = merge(commenConfig, prodConfig)

最后在根目录下创建一个build文件夹,将 webpack.common.js , webpack.dev.js ,webpack.prod.js 放在build文件夹下,统一管理。

在 package.json 中:

{
  "scripts": {
    "dev": "webpack-dev-server --config ./build/webpack.dev.js",
    "build": "webpack --config ./build/webpack.prod.js"
  },
}

详细请看官网文档:guides/production


Webpack和Code Splitting

安装: npm i lodash --save npm i babel-plugin-dynamic-import-webpack -D

代码分割,和webpack无关,为了提升性能 webpack中实现代码分割,两种方式:

第一种方法:同步代码: 只需要在webpack.common.js中做optimization的配置即可

第二种方法:异步代码(import): 异步代码,无需做任何配置,会自动进行代码分割,放置到新的文件中

第一种方法:在 webpack.common.js 中

module.exports = {
	entry: {
		main: "./src/index.js"
	},
	
	module: {
		rules: []
	},
	plugins: [],
+    optimization:{
+       splitChunks:{ //启动代码分割,有默认配置项
+            chunks:"all"
+        }  
+    },
	
	output: {}
}

第二种方法在 .babelrc 中:

{
	presets: [
		[
			"@babel/preset-env", {
				targets: {
					chrome: "67",
				},
				useBuiltIns: "usage"
			}
		],
		"@babel/preset-react"
	],
+	plugins: ["dynamic-import-webpack"]
}

详细内容请看官网:code-splitting


SplitChunksPlugin 配置参数详解

安装:npm install --save-dev @babeL/plugin-syntax-dynamic-import

在业务 index.js 中:

 function getComponent() {
 	return import(/* webpackChunkName:"lodash" */ "lodash").then(({ default: _ }) => {
 		var element = document.createElement("div");
		element.innerHTML = _.join(["1", "2"], "-");
 		return element;
	})
}

 getComponent().then(element => {
 	document.body.appendChild(element);
 });

.babelrc 中:

{
	presets: [
		[
			"@babel/preset-env", {
				targets: {
					chrome: "67",
				},
				useBuiltIns: "usage"
			}
		],
		"@babel/preset-react"
	],
+	plugins: ["@babeL/plugin-syntax-dynamic-import"]
}

在 webpack.common.js 中:

module.exports = {
	entry: {
		main: "./src/index.js"
	},
	
	module: {
		rules: []
	},
	plugins: [],
+    optimization:{
+       splitChunks:{ //启动代码分割,不写有默认配置项
+            chunks: "all",//参数all/initial/async,只对所有/同步/异步进行代码分割
              minSize: 30000, //大于30kb才会对代码分割
              maxSize: 0,
              minChunks: 1,//打包生成的文件,当一个模块至少用多少次时才会进行代码分割
              maxAsyncRequests: 5,//同时加载的模块数最多是5个
              maxInitialRequests: 3<           
               
                                           
                       
                 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/7340.html

相关文章

  • webpack 基础与项目优化实践总结

    摘要:前言本文基于,主要涉及基本概念基本配置和实际项目打包优化。关于概念方面参考官网,常用配置来自于网络资源,在文末有相关参考链接,实践部分基于自己的项目进行优化配置。同一文件中,修改某个影响其他。 前言:本文基于weboack4.x,主要涉及webpack4 基本概念、基本配置和实际项目打包优化。关于概念方面参考官网,常用配置来自于网络资源,在文末有相关参考链接,实践部分基于自己的项目进行...

    Scorpion 评论0 收藏0
  • 手摸带你实现 小游戏<别踩白块儿 -- 内有游戏链接>

    摘要:别踩白块儿使用白鹭引擎编写的游戏游戏地址准备工作了解白鹭引擎并安装编写工具安装游戏引擎安装创建项目创建项目可以选择不同版本的引擎,创建成功之后还可以查看,对发布进行设置。 别踩白块儿 使用(白鹭引擎)Egret编写的游戏 showImg(https://user-gold-cdn.xitu.io/2018/10/26/166af8033a59fdbf?w=500&h=840&f=gif...

    zhoutk 评论0 收藏0
  • 摸手带你用vue撸后台 系列一(基础篇)

    摘要:详细具体的使用可以见文章手摸手,带你优雅的使用。为了加速线上镜像构建的速度,我们利用源进行加速并且将一些常见的依赖打入了基础镜像,避免每次都需要重新下载。 完整项目地址:vue-element-admin系类文章二:手摸手,带你用vue撸后台 系列二(登录权限篇)系类文章三:手摸手,带你用vue撸后台 系列三(实战篇)系类文章四:手摸手,带你用vue撸后台 系列四(vueAdmin 一...

    xiaotianyi 评论0 收藏0
  • 摸手带你用vue撸后台 系列三(实战篇)

    摘要:社区的认可目前已经是相关最多的开源项目了,体现出了社区对其的认可。监听事件手动维护列表这样我们就简单的完成了拖拽排序。 完整项目地址:vue-element-admin 系类文章一:手摸手,带你用vue撸后台 系列一(基础篇)系类文章二:手摸手,带你用vue撸后台 系列二(登录权限篇)系类文章三:手摸手,带你用vue撸后台 系列三(实战篇)系类文章四:手摸手,带你用vue撸后台 系列...

    Channe 评论0 收藏0
  • 摸手带你用vue撸后台 系列三(实战篇)

    摘要:社区的认可目前已经是相关最多的开源项目了,体现出了社区对其的认可。监听事件手动维护列表这样我们就简单的完成了拖拽排序。 完整项目地址:vue-element-admin 系类文章一:手摸手,带你用vue撸后台 系列一(基础篇)系类文章二:手摸手,带你用vue撸后台 系列二(登录权限篇)系类文章三:手摸手,带你用vue撸后台 系列三(实战篇)系类文章四:手摸手,带你用vue撸后台 系列...

    zgbgx 评论0 收藏0

发表评论

0条评论

王军

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<