前言

webpack前端工程中扮演的角色越来越重要,它也是前端工程化很重要的一环。本文将和大家一起按照项目流程学习使用wbepack,妈妈再也不用担心我不会使用webpack,哪里不会看哪里。这是一个由浅入深的文章。

工程化

这里是一个项目工程化,规范化的设置,如果是初次使用webpack的同学还是最后在看这一块知识

现在vue、react等脚手架都会自动将开发环境使用的webpack的配置文件和生产环境的配置文件分开,将压缩代码,添加hash控制版本等操作放在项目上线时运行,这样避免了在开发阶段打包时间过长的问题。比如像这样,把两个环境的配置文件分开。


下面来看下两个配置文件的内容(我是用的typescript开发react,内容请忽略)
开发环境:

生产环境:


可以看到,开发环境增加了几个插件,这样做的好处就是更加工程化,规范化,降低开发环境的打包时间,代码维护性也更高。

分开写配置文件就要涉及到使用命令执行不同的配置文件,我们可以使用npm的脚本命令,我们可以在package.json中找到scripts,添加如下命令"build": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress"

给大家解释下这个命令的意思

  • NODE_ENV=production 就是将运行环境设置成生产环境
  • webpack --config 就是运行webpack的配置文件
  • ./webpack.production.config.js 是要运行的指定位置的文件,这个路径是相对根目录来说的
  • --progress 是编译过程显示进程百分比的

如果你不追求规范化和工程化,我们就写一个配置文件就好,这里没有硬性要求。下面我们来讲webpack的具体配置

开始

在我们对于webpack不是特别熟练的时候,我们可能不会写全配置文件,往往是用到什么再去添加,下面我们就按照这个步骤彻底学会使用webpack。

module.exports = {
entry: './src/index.js' // 这里是项目入口文件地址
ouput: {
path: __dirname + "/dist", // 这里是项目输出的路径,__dirname表示当前文件的位置
filename: "js/"+"[name].js" // 这里是生成文件的名称,可起你想要的名字
}
}

loader

这就是我们最初一个骨架,下面我们再添加一些配置,比如你使用的是react,那么你就需要添加react的相关loader,这里以typescript编写的react为例。

module.exports = {
entry: './src/index.js' // 这里是项目入口文件地址
ouput: {
path: __dirname + "/dist", // 这里是项目输出的路径,__dirname表示当前文件的位置
filename: "js/"+"[name].js" // 这里是生成文件的名称,可起你想要的名字
},
module: {
rules: [
{ test: /\.tsx?$/, loader: "awesome-typescript-loader" },
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
}

css/css预处理语言(less、sass、stylus)

webpack是将一个个文件分拆成一个个模块(module)来进行编译打包的,我们所有的处理文件内容的东西都要放在module里,rules即规则。
rules里面的两个loader都是编译.tsx文件及处理错误信息的。

在你写好了组件之后,你需要开始编写样式,但无论是css还是使用less、sass等预处理语言,webpack都是无法直接处理的,我们安装并使用相应的loader。下面以less和css为例。

 {test: /\.(less|css)?$/, loader: ["style-loader", "css-loader", "less-loader"]}

webpack会按照从右到左的顺序执行loader,我们新解析less,之后进行css的打包编译。如果你不适用less等预处理语言,安装css-loader和style-loader即可。

  • style-loader 将css插入到页面的style标签
  • css-loader 是处理css文件中的url()等
  • less-loader 是将less文件编译成css

postcss解决css兼容问题

写到这里我们会突然想到一个点,就是css样式的兼容性问题,靠人工去写的话,你心里可能会有一句mmp不值当讲不当讲,哈哈,我们必须使用postcss来解决这个问题。

postcss是目前css兼容性的解决方案,会自动帮我们加入前缀,以使css样式在不同的浏览器能兼容,这里安装使用postcss-loader

{ test: /\.(less|css)?$/, loader: ["style-loader", "css-loader", "less-loader", "postcss-loader"]}

postcss-loader要写在最后(其实只要放在css-loader之后就可以),写到这你以为就可以了吗?只能说 too young,postcss解决兼容性问题主要靠的其实是它的插件autoprefixer,我们还需要在根目录写一个postcss.config.js的配置文件,如下

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

写到这,我们就不用再担心css兼容性问题了,就想使用babel文件一样,这个文件会自动解析,我们不需要管它。

svg图片的使用

我们在开发时,往往会遇到一些图标图片在不同情况下会失真,以及资源过多,我们需要减小图标类图片的大小,这时我们就需要引入svg,国内可能都会去使用阿里的iconfont库,从而引入svg图标,解决上面的问题

我们打开下载的素材文件夹,发现里面有一些.woff、.svg、.eot的文件,我们要想使用svg的图标还必须依赖这些文件,这时webpack不支持这些文件,我们需要引入新的loader

{ test: /\.(woff|svg|eot|ttf)?$/, loader: "url-loader" }

下面我们就能愉快的使用svg图标了,不存在失真的情况,同时会很小

webpack-dev-server

写到这,我们可能不断的打包webpack了,太麻烦了,于是乎webpack-dev-server应运而生。它是webpack提供的服务器,我们使用npm i webpack-dev-server --save-dev来安装。
我们其实在命令行中敲击webpack-dev-server --open就可以开启,默认是localhost:8080开启,现在我们不需要在重复使用webpack命令打包,安装。

值得注意的是,webpack-dev-server打包的文件会存在内存中,所以在index.html中引入文件的时候就要如下,这里是默认输出文件是bundle.js

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

今天我们不重点讲webpack-dev-server,以后我会再写文章,深入的讲解其使用。

可能我们在开发阶段只用到了这几个功能,下面我们来讲一下项目上线的准备。

生产环境

优化

压缩js代码

我们打包完成的项目往往比较大,包含很多空格,占用了很大空间,这时我们要通过压缩js来减小文件体积。webpack自带了UglifyJsPlugin插件来压缩js代码,使用如下

plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]

我们的插件统一放在export.modules = {}的plugins里面,它是一个数组,使用插件时new 一个实例即可。这里我们使用到webpack实例,所以要在配置文件头部引入webpack,即var webpack = require('webpack');

拆分文件

我们在使用的js库如vue或者react等的时候,webpack会将它们一起打包,react和react-dom文件就好几百k,全部打包成一个文件,可想而知,这个文件会很大,用户在首次打开时就往往会出现白屏等待时间过长的问题,这时,我们就需要将这类文件抽离出来。

externals: {
"react": "React",
"react-dom": "ReactDOM"
},

这里我们会用到externals,它和plugins是平级。左侧key表示依赖,右侧value表示文件中使用的对象。比如在react开发中,我们常常会这样在文件头部写import React from 'react',这里大家可以和上面对号入座下。

这里我们就需要对这个文件进行单独的引入使用了,在index.html中添加如下代码

<script src="./node_modules/react/umd/react.xxx.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.xxx.js"></script>

写到这,我们就已经将文件拆分了。
不过,我们在项目上线的时候不可能会带有node_modules,所以我们就需要使用一个copy插件将react和react-dom文件复制出来

 new CopyWebpackPlugin([ // from是要copy的文件,to是生成出来的文件
{ from: "node_modules/react/umd/react.xxx.js", to: "js/react.min.js" },
{ from: "node_modules/react-dom/umd/react-dom.xxx.js", to: "js/react-dom.min.js" }
{ from: "public/favicon.ico", to: "favicon.ico" }
])

这样我们的index.html文件中就要写成下面这种形式

拆分css

我们也可以将css文件单独拆分出来,这样的好处就是打包的css文件我们可以放到cdn上,然后缓存到浏览器客户端中。这样就尽可能的减小文件的体积,以及不必要的资源重新加载,浪费带宽。

我们要先安装插件

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

配置文件添加对应配置

var ExtractTextPlugin = require("extract-text-webpack-plugin");

plugins里面添加插件

new ExtractTextPlugin("styles.css")
下面是具体的使用

module.exports = {
// entry和output自动省略
module: {
loaders: [{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader',
'css-loader!postcss-loader') // 这里我目前使用less还没有成功
}]
},
postcss: function() {
return [autoprefixer, cssnext, precss, cssnano]
},
plugins: [
new ExtractTextPlugin('./css/[name].min.css') // 生成到css文件夹下
]
}

webpack会将所有引用到的css文件打包,最终生成./css/[name].min.css文件。

图片处理

这里对图片进行base64进行转码同样是减小资源的体积

安装 url-loader

npm install url-loader --save-dev

在modules的rules里面添加

{
test: /\.(png|jpg)$/,
loader: 'url?limit=8192&name=images/[hash:8].[name].[ext]'
}

limit 设置一个阈值,小于这个值得图片就会自动启用 base64 编码的图片,大于这个值的图片会打包到name 这参数对应的路径,图片名称就会包括8位md5编码 name 对应文件本来名称,ext 对应扩展名

浏览器缓存资源

我们的后台会给资源设置Cache-Control: max-age=秒替代,来对资源进行缓存时间的设置,这使得我们在刷新页面之后会去缓存中加载资源,但是存在一个问题,就是,一旦我们更新版本之后,客户没有去清除缓存,同时缓存还没有过期的情况下,就无法加载到最新的资源。这时我们就需要hash值来进行版本控制

我们通常这样做

output: {
path: __dirname + "/dist",
filename: "[name][hash].js"
}

给输出文件加上[hash]来添加hash值,这样就可以做到用户加载html里会去加载对应hash值得打包文件,比如下面这样

<script type="text/javascript" src="main3d1cb903f77dad5737e9.js"></script>

打包出来的js文件是这样


这样就能解决这个问题了。

还有最后一项

我们不可能每次都去手动复制一个index.html到打包好的dist文件中,我们会使用一款插件html-webpack-plugin
它可以自动添加html文件到dist文件中,同时它会自动添加js文件并带有hash值

引入插件

var HtmlWebpackPlugin = require('html-webpack-plugin');

使用插件

new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.tmpl.html'),
filename: 'index.html'
})

这里给大家解释下,template是模板,我们在很多情况下,生产环境和开发环境不同,导致index.html引入的资源路径不同,这是为了改来改去,我们可以创建一个模板,它指定编译时我们copy的index.html文件。filename是最终生成的文件名。

模板文件如下

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<title>Projection-Web</title>
</head>
<body>
<div id="root"></div>
<script src="js/react.min.js"></script>
<script src="js/react-dom.min.js"></script>
</body>
</html>

生成的index.html文件如下

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<title>Projection-Web</title>
</head>
<body>
<div id="root"></div>
<script src="js/react.min.js"></script>
<script src="js/react-dom.min.js"></script>
<script type="text/javascript" src="js/main3d1cb903f77dad5737e9.js"></script></body>
</html>

下面是我打包编译的dist文件夹内容


下面是生产环境的配置文件(部分)

var CopyWebpackPlugin = require("copy-webpack-plugin");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require("webpack");
var path = require('path');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: "./src/index.tsx",
output: {
path: __dirname + "/dist",
filename: "js/"+"[name][hash].js"
},
devtool: "source-map", resolve: {
extensions: [".ts", ".tsx", ".js", ".json"]
},
module: {
rules: [
{ test: /\.tsx?$/, loader: "awesome-typescript-loader" },
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
{ test: /\.(less|css)?$/, loader: ["style-loader", "css-loader", "less-loader", "postcss-loader"] },
{ test: /\.(woff|svg|eot|ttf)?$/, loader: "url-loader" }
]
},
externals: {
"react": "React",
"react-dom": "ReactDOM"
},
plugins: [
new CopyWebpackPlugin([
{ from: "node_modules/react/dist/react.js", to: "js/react.min.js" },
{ from: "node_modules/react-dom/dist/react-dom.js", to: "js/react-dom.min.js" },
{ from: "index.html", to: "index.html" },
{ from: "public/favicon.ico", to: "favicon.ico" }
]),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.tmpl.html'),
filename: 'index.html'
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
};

学好webpack,是一名现代前端开发工程师的基本素养。后续还会深入webpack,谢谢大家

(转)webpack用法的更多相关文章

  1. 通过核心概念了解webpack工作机制

    webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency gr ...

  2. Vue(四)之webpack和vue-cli

    01-webpack介绍 官方文档:https://www.webpackjs.com/concepts/ 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(modu ...

  3. 使用webpack从零开始搭建react项目

    webpack中文文档 webpack的安装 yarn add webpack@3.10.1 --dev 需要处理的文件类型 webpack常用模块 webpack-dev-server yarn a ...

  4. Webpack 打包太慢? 试试 Dllplugin

    webpack在build包的时候,有时候会遇到打包时间很长的问题,这里提供了一个解决方案,让打包如丝般顺滑~ 1. 介绍 在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 rea ...

  5. webpack原理

    webpack早就已经在前端领域大放异彩,会使用和优化webpack也已经是中.高级工程师必备技能,在此基础之上再对webpack的原理进行理解和掌握,必定会在未来的开发中事半功倍.若是对于webpa ...

  6. webpack 4.x 初级学习记录

    首先声明下,本人不擅长文字表达,文采不行,所以文章中文字较少,请看代码,初级学习,不足之处请多多指教 GitHub链接 看云kancloud [TOC] webpack 4.x 安装 首先需要在全局中 ...

  7. webpack学习之—— Plugins

    Plugins are the backbone of webpack! webpack 自身也是构建于你在 webpack 配置中用到的相同的插件系统之上! 插件目的在于解决 loader 无法实现 ...

  8. Webpack的基本配置和打包与介绍(二)

    1. 前言 在上一章中我们学习到了webpack的基本安装配置和打包,我们这一章来学学如何使用loader和plugins 如果没看第一章的这里有传送门 2. Loader 2.1 什么是loader ...

  9. Web前端性能优化——如何有效提升静态文件的加载速度

    WeTest 导读 此文总结了笔者在Web静态资源方面的一些优化经验. 一.如何优化 用户在访问网页时, 最直观的感受就是页面内容出来的速度,我们要做的优化工作, 也主要是为了这个目标.那么为了提高页 ...

随机推荐

  1. node jsonwebtoken

     jsonwebtoken是node版本的JWT(JSON Web Tokens)的实现.1.什么是JWT?Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于J ...

  2. MySQL在Linux下的表名如何不区分大小写

    MySQL在Linux下的表名如何不区分大小写   今天测试的时候,遇到一些问题,明明看到数据,就是查不出来;后来发现,在linux下, mysql的表名区分大小写,而在windows下是不区分,从w ...

  3. JDBC对MySQL数据库存储过程的调用

    一.MySQL数据库存储过程: 1.什么是存储过程 存储过程(英文:Stored Procedure)是在大型数据库系统中,为了完成特定功能而编写的一组的SQL语句集.存储过程经编译存储在数据库中,用 ...

  4. 用那啥 那啥来着Django来发送Email,结合腾讯云,批量发短信给用户!

    你们好,我是来ZB的! 这篇博客是用来发送邮件的,用的是Django框架,很好用.遗憾的是我当时用的阿里云,把腾讯QQ的端口给……给屏蔽了,啊啊啊啊,多么痛的领悟呀.后来用的163网易的邮箱.可以了! ...

  5. H5-video1 iOS苹果和微信中音频和视频实现自动播放的方法

    <audio preload="preload" controls id="car_audio" src="http://media.xitao ...

  6. react 父组件 向 子组件 传值

    父组件 import React, { Component } from 'react'; import Test from './component/test'; //声明welcome组件 cla ...

  7. Spring Cloud-Eureka实现服务的注册与发现(二)

    在Spring Cloud中是使用Eureka来实现服务的注册与发现的 请勿使用eureka2.x  用于生产 2.x已经停止开发了  使用1.x  最新版是1.9  我这里demo是使用1.9  详 ...

  8. sqlserver日志文件太大解决方法

    SQL Server 的事务日志意外增大或充满的处理方法 事务日志文件Transaction Log File是用来记录数据库更新情况的文件,扩展名为ldf. 在 SQL Server 7.0 和 S ...

  9. 心急的C小加 贪心算法

    心急的C小加 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 C小加有一些木棒,它们的长度和质量都已经知道,需要一个机器处理这些木棒,机器开启的时候需要耗费一个单位的 ...

  10. asp.net--ado.net5大对象代码示例

    连接数据库 string conn_string ="Data Source=localhost;Initial Catalog=SQLtest;Integrated Security=Tr ...