# webpack-imooc-test **Repository Path**: hongjunyong/webpack-imooc-test ## Basic Information - **Project Name**: webpack-imooc-test - **Description**: 慕课-webpack入门介绍 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2018-03-14 - **Last Updated**: 2021-03-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # webpack入门介绍 ## 1、基本介绍 webpack是为什么? 为什么要使用webpack? 怎么配置webpack? ### 1.1、webpack官方文档 https://doc.webpack-china.org/ https://github.com/webpack/webpack ### 1.2、webpack概述 js(ES6、typescript)的打包器、代码按需加载、loader加载器 ![](./img/webpack-detail.png) 从图中我们可以看出,Webpack 可以将多种静态资源 js、css、less(不仅仅这些,还有像jade、less等等)转换成一个静态文件,减少了页面的请求。 ### 1.3、webpack版本变化 webpack v1.0.0 --- 2014.2.20 编译打包、模块热更新、代码分割、文件处理 webpack v2.2.0 --- 2017.1.18 打包文件体积更小、动态import、新的官方文档 webpack v3.0.0 --- 2017.6.19 作用域提升(打包后的代码性能)、配合动态import使用 webpack v4.0.0 --- 2018.2.27 打包的速度提升(构建时间降低了 60%-98%)、Mode 零配置以及默认值:development 或者是 production、entry默认:./src/index.js为入口文件,output默认:./dist/main.js ![](./img/time.png) ### 1.4、为什么webpack? 1、最热门的三大框架:vue、react、angular,他们命令行工具都使用webpack构建工具 Vue-cli Angular-cli React-starter 2、代码分割:Code-splitting 3、模块化(js模块化、css模块化【css设计模式,例如:SMACSS模式(减少代码量、简化代码维护)、oocss模式】) ### 1.5、hello webpack(案例:1-1-first) ![](./img/demo.png) ### 1.6、安装 npm install webpack@3.10.0 -g webpack4.0以上版本:npm install webpack-cli -g(交互式的初始化一个项目、迁移项目V1 -> V2[仅限配置文件]) ## 二、核心概念 ### 2.1、Entry : 功能:1、代码入口; 2、打包的入口; 3、单个(业务代码、框架代码分开)或多个(多页面程序) 示例: 写法一、 // 扩展性差 module.exports = { entry: 'index.js' } 写法二、 // 扩展性差(两个文件、两个路径) module.exports = { entry: ['index.js', 'vendor.js'] } 写法三(推荐)、 module.exports = { entry: { index: 'index.js', vendor: 'vendor.js' } }; ### 2.2、Output: 功能:1、打包成的文件(bundle); 2、一个或多个、自定义规则 示例: // 一个入口对应一个出口 module.exports = { entry: { index: 'index.js', }, output: { filename: 'index.min.js' } }; module.exports = { entry: { index: 'index.js', vendor: 'vendor.js' }, // 例如:entry=index ==> index.min.js // 例如:entry=vendor ==> vendor.min.js // MD5:版本号 output: { // 用于输出文件的文件名 MD5码(5代表有五位数) filename: '[name].min.[hash:5].js' // 目标输出目录 path 的绝对路径(此配置将一个单独的 bundle.js 文件输出到 /home/proj/public/assets 目录中) path: '/home/proj/public/assets' } }; ### 2.3、loader: 功能:1、处理文件; 2、转化为模块(例如loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript) 示例:(rules执行的顺序从下到上) module.exports = { module: [ rules: [ { // 易错:这里的正则不带引用 test: /\.css$/, use: 'css-loader', // 排除在规则之外的 exclude: '/node_modules' } ] ] } ### 2.3.1、常用的loader 编译相关: babel-loader、ts-loader 样式相关: css-loader、style-loader、less-loader、postcss-loader 文件相关: file-loader、url-loader ### 2.4、plugin: 功能:1、插件是 wepback 的支柱功能; 2、参与打包整个过程; 3、打包优化和压缩(打包公共代码,如果是多页面的程序,公用的代码会缓存到浏览器,减少对服务端的请求) 4、配置编译时的变量 示例: // 压缩代码 const webpack = require('webpack'); module.exports = { plugins: [ new webpack.optimize.UglifyJsPlugin() ] } #### 2.4.1、常用的plugins 优化相关: commonsChunkPlugin:提取不同chunk(提取公共代码,形成一个公共的代码块) uglifyjsWebpackPlugin:压缩代码 功能相关: extractTextWebpackPlugin:css提取出来作为一个单独的文件 htmlWebpackPlugin:生成html hotModuleReplacementPlugin:模块热更新 copyWebpackPlugin:拷贝文件(例如引用别人的插件,别人已经压缩打包好了) ### 2.5、 名词解释 Chunk:代码块(提取公共代码,形成一个公共的代码块) Bundle:一捆、一束:打包过的代码 Module:模块 ## 3、webpack基本命令 webpack -h 查看所有命令 webpack -v 查看版本 webpack entry output 或 webpack --config webpack.conf.js 打包js webpack-cli init webpack-addons-demo(webpack-addons前缀,demo项目名称): 交互式的初始化一个项目 ![image](./img/webpack-cli.png) ![image](./img/webpack-cli-pengwings.png) ## 4、 实战 ### 4.1、 打包js(案例:3-1-js 同 1-1-first) 打包:webpack app.js bundle.js(app.js代表入口文件;bundle.js代表打包后生成的文件) webpack --config webpack.conf.js(文件名不是webpack.config.js,如果是的话,直接执行webpack命令) ### 4.2、 编译ES6(案例:3-2-es6) 略 npm init 项目初始化,添加package.json npm install babel-loader@8.0.0-beta.0 @babel/core 静态文件托管 npm install @babel/preset-env --save-dev ### 4.3、 编译typescript(案例:3-3-typescript) 略 npm install webpack typescript ts-loader awesome-typescript-loader --save-dev npm install typescipt ts-loader --save-dev npm install typescipt awesome-typescript-loader --save-dev 如果项目中有用到lodash npm install lodash --save ### 4.4、 打包公共代码(案例:3-4-public) #### 4.4.1、 作用 减少代码冗余 提高加载速度 案例: ![](./img/public.png) 把C提取出来:如果用户访问了A并且加载了C,再当用户浏览了B,C就不用再去加载 #### 4.4.2、 应用场景: 单页面就不需要再去加载 多页面利用浏览器缓存 ### 4.4.3、 使用的插件 commonsChunkPlugin 配置 ![](./img/public2.png) ### 4.4.4、 使用步骤 初始化:npm init 安装本地依赖:npm install webpack --save-dev 针对多个entry,如果只有一个entry是没有作用的(单页面更多的是用懒加载,懒加载有其他的打包方式) // 打包公共代码(第三方依赖 与 业务代码 混在一起) new webpack.optimize.CommonsChunkPlugin({ name: 'common', // 代码出现2次就进行打包 minChunks: 2 }) // 分离第三方依赖 与 分离业务代码 new webpack.optimize.CommonsChunkPlugin({ name: 'common', // 代码出现2次就进行打包 minChunks: 2, // 需要指定要打包的公共代码 chunks: ['pageA','pageB'] }), new webpack.optimize.CommonsChunkPlugin({ // vendor是第三方插件打包后的代码,manifest是自己封装的公共代码进行打包 names: ['vendor','manifest'], // 把webpack的代码页打包进来,不需要在任何地方重复了 minChunks: Infinity }) ## 4.5、 代码分割 和 懒加载(案例:3-5-splice) 让用户浏览的时候加载更少的代码,用更短的时间看到页面 AMD:依赖前置,提前执行 CMD:尽可能懒执行 ### 4.5.1、 使用场景 分离业务代码 和 第三方依赖 分离业务代码 和 业务公共代码 和 第三方依赖 分离首次加载 和 访问后加载的代码 ### 4.5.2、 pageA.js案例 // 只有打包出一个pageA.bundle.js文件(混在一起) import * as _ from 'lodash' // ensure只是把lodash加载进来,并没有执行到lodash代码(lodash提取到vendor里) require.ensure(['lodash'], function () { // 这里才有执行到lodash代码 var _ = require('lodash'); _.join(['1', '2'], '3') },'vendor'); // 提前include,这样moduleA就被提取到pageA.bundle.js里 require.include('./moduleA'); // 会生成subPageA.chunk.js、subPageB.chunk.js文件(但是moduleA没有被分离出来) var page = 'subPageA'; if (page === 'subPageA'){ require.ensure(['./subPageA'], function () { var subPageA = require('./subPageA') },'subPageA'); } else if (page === 'subPageB') { require.ensure(['./subPageB'], function () { var subPageB = require('./subPageB') },'subPageB'); } ## 4.6、 css style-loader(案例:3-6-style-loader) 帮助需要载入的页面创建style标签(也就是:使用标签 ### 4.6.1 安装 npm install style-loader --save-dev npm install css-loader --save-dev ### 4.6.2 配置 module: { rules: [ { test: /\.css$/, use: [ { // 放到HTML页面上 // useable可以动态让css插入或不插入页面中 loader: 'style-loader/useable', options: { // 让css代码插入到指定的DOM节点上(图1) insertInto: '#app', // 让样式结合到一个style标签上(图2) singleton: true, // css函数(图3、4、5) transform: './css.transform.js' } }, { // 把css交给css-loader,让他处理完js可以import css这块内容,再交给style-loader loader: 'css-loader' } ] } ] } import base from './css/base.css' // 使用base样式 base.use() // 不使用base样式 base.unuse() (图1) ![](./img/style.png) (图2) ![](./img/style2.png) (图3) ![](./img/pc.png) (图4) ![](./img/iphone.png) (图5) ![](./img/transform.png) ## 4.7 css css-loader 加载.css文件 ### 4.7.1 安装 npm install css-loader --save-dev ### 4.7.1 配置 module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { // 把css交给css-loader,让他处理完js可以import css代码,再交给style-loader(相当于引用css文件) loader: 'css-loader', options: { // css被压缩(图1) minimize: true, // js代码中使用css样式(图2) modules: true, // 给class命名:路径 文件名 class名称 五位的编码(图3) localIdentName: '[path][name]_[local]_[hash:base64:5]' } } ] } ] } // css-loader要结合app.js: var app = document.getElementById('app'); app.innerHTML = '
' (图1) ![](./img/cssmin.png) (图2) ![](./img/css-loader.png) (图3) ![](./img/name.png) ## 4.7 配置less/sass(案例:3-7-less-sass) ### 4.7.1 安装 npm install less-loader less --save-dev //因为sass-loader依赖于node-sass,所以还要安装node-sass npm install sass-loader node-sass --save-dev ### 4.7.2 配置 module: { rules: [ { test: /\.less$/, use: [ { // 放到HTML页面上 loader: 'style-loader', }, { // 把css交给css-loader,让他处理完js可以import css代码,再交给style-loader(相当于引用css文件) loader: 'css-loader' }, { loader: 'less-loader' } ] } ] } ## 4.8 提取css文件(案例:3-8-extract) style-loader、css-loader、less、sass都是把样式打包到js文件里,并不是生成独立的css文件, 利用提取css文件,会在dist目录下生成app.min.css文件 ### 4.8.1 安装 npm install extract-text-webpack-plugin webpack --save-dev 加载:var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin') plugins: [ // 对(提取css文件)插件的调用 new ExtractTextWebpackPlugin({ // 打包后的名字 filename: '[name].min.css', // 指定提取范围(如果是true是就把所有有引入的css文件都打包;如果是false,只会提取初始化的文件) allChunks: false }) ] use: ExtractTextWebpackPlugin.extract({ // 当不提取用什么方式加载到页面上(直接把样式插入到HTML页面上) fallback: { // 放到HTML页面上 loader: 'style-loader' }, // 继续处理的loader use: [ { // 把css交给css-loader,让他处理完js可以import css代码,再交给style-loader(相当于引用css文件) loader: 'css-loader' }, { loader: 'less-loader' } ] }) 提取出来的代码不会在页面上引用,需要手动引入 ## 4.9 PostCSS(案例:3-8-postcss) Autoprefixer:自动添加css前缀 css-nano:优化、压缩css css-next:使用未来的css语法(例如calc) npm install postcss postcss-loader autoprefixer cssnano postcss-cssnext --save-dev 核心配置: { // 放在less或sass预处理语言之前 loader: 'postcss-loader', options: { // 表明接下来插件是给postcss用的 ident: 'postcss', plugins: [ // require('autoprefixer')(), // postcss-cssnext已经包含了autoprefixer require('postcss-cssnext')() ] } } 未来的css语法: :root { --mainColor: red; } a { color: var(--mainColor); } ![](./img/postcss.png) ## 4.10 Tree Shaking(案例:3-8-tree-shaking) 摇树木(摇完叶子会掉下来):写项目的时候有的代码没有用到,项目上线的时候代码还存在,会存在资源浪费、等待时间加长 ### 4.10.1 使用场景: 常规优化 引入第三方库的某一个功能 ### 4.10.2 js Tree Shaking // 对没有用到的js代码进行过滤 new webpack.optimize.UglifyJsPlugin() // 未使用前 ![](./img/js-tree-shaking.png) // 使用后(代码被压缩,且只能找到‘this is a’) ![](./img/js-tree-shaking-result.png) ### 4.10.3 css Tree Shaking npm install purifycss-webpack glob-all --save-dev // 要写在ExtractTextWebpackPlugin的后面 new PurifyCSS({ paths: glob.sync([ path.join(__dirname, './*.html'), path.join(__dirname, './src/*.js') ]) }), ## 5.1 图片处理(案例:4-1-img) ### 5.1.1 css中引入的图片(npm isntall file-loader) 作用:如果没有引入,图片资源会找不到;同时图片资源没有被打包 { test:/\.(png|jpg|jped|gif)$/, use: [ { // 引入的图片 loader: 'file-loader', options: { // 设置绝对路径(指定路径,例如图片路径为:aa/1.jpg) // publicPath: 'aa/', // 输出的路径放到dist目录下(暂时没用,因为默认放在dist目录下) // outputPath: 'dist/', // 图片会放在dist/assets/imgs里,如果没有设置true,会裸露在外面 useRelativePath: true } } ] } ![](./img/file-loader.png) ### 5.1.2 base64编码(npm isntall url-loader) { test:/\.(png|jpg|jped|gif)$/, use: [ { // base64图片 loader: 'url-loader', options: { name: '[name]-min[hash:5].[ext]', // 当图片大于多少K的时候,转换成base64 100000 10K limit: 100000, // 图片会放在dist/assets/imgs里,如果没有设置true,会裸露在外面 useRelativePath: true } } ] } ### 5.1.3 压缩图片(npm isntall img-loader) { loader: 'img-loader', options: { pngquant: { // 压缩图片比例 quality: 80 } } } // 压缩前(图片文件比较大) ![](./img/img-loader2.png) // 压缩后(图片文件比较小) ![](./img/img-loader.png) ### 5.1.4 自动合成雪碧图(npm isntall postcss-sprites) 多张图片合成一张,压缩的时候会根据图片的位置进行定位 ![](./img/sprite.png) { loader: 'postcss-loader', options: { ident: 'postcss', plugins: [ // 自动合成雪碧图 require('postcss-sprites')({ // 指定输出的路径 spritePath: 'dist/assets/imgs/sprites' }), require('postcss-cssnext')(), ] } }, ### 5.1.5 字体文件 test: /\.(eot|woff|woff2|ttf|svg)$/, use: [ { loader: 'url-loader', options: { name: '[name]-[hash:5].[ext]', limit: 5000, publicPath: '', useRelativePath: true } } ] } ### 5.1.6 处理第三方 JS 库 三种引入方式:外网引入、npm安装、文件引入 #### 第一种:外网引入(直接写在页面上就可以使用) #### 第二种:npm安装:npm install jquery --save // 在每一个模块注入$这个变量 new webpack.ProvidePlugin({ $: 'jquery' }), #### 第三种:文件引入 两处的jquery要对应 // 在每一个模块注入$这个变量 new webpack.ProvidePlugin({ $: 'jquery' }), 配合 // 解析路径 resolve: { alias: { // jquery$:把jquery解析到某个路径下 jquery$: path.resolve(__dirname, 'src/libs/jquery-2.1.1.js') } }, // app.js $('div').addClass('new'); ![](./img/jquery.png) ## 5.2 生成HTML npm install html-webpack-plugin --save-dev var HtmlWebpackPlugin = require('html-webpack-plugin') plugins: [ // 生成html new HtmlWebpackPlugin({ // 生成后的文件名 filename: 'index.html', // 指定页面进行生成 template: './index.html', // 打包后的引用路径不会重复 inject: false }) ] 引入图片 npm install html-loader --save-dev ## THE END ### 本次分享的不足、亟待: 1、需要优化配置 2、最好有两份配置文件,例如生产环境和开发环境区分开 3、模块热更新(无需刷新页面,便能替换、增加、删除必要的模块) 4、优化打包速度 5、最好有 webpack + vue 的技术分享