webpack4 【开发】【生产】【优化】相关配置

自动化构建

(一)npm scripts

npm允许在package.json文件里面,使用scripts字段定义脚本命令

{
  // ...
  "scripts": {
    "build": "node build.js"
  }
}

命令行下使用npm run命令,就可以执行这段脚本。

$ npm run build
# 等同于执行
$ node build.js
$ npm run	//查看所有脚本命令

之前项目弊端

  1. 网页加载速度慢,因为会发起很多的二次请求(html中引入css、js、image等)。

    解决方案:合并文件、压缩、精灵图、将图片转成base64编码直接放入。

  2. 不能直接使用less、scss、ts等文件。

    解决方案:先转成浏览器能够识别的文件css、js再引入。

  3. 要处理引入之间错综复杂的依赖关系。(比如:bootstrap前要引入jquery)。

    解决方案:使用requireJS、webpack

  4. es6及以上,旧版本浏览器不能很好支持。

    解决方案:使用babel进行低版本浏览器兼容处理。

模块化打包

(一)webpack4

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler),依赖于node环境。

​ 当 webpack 处理应用程序时,它会递归地构建一个依赖chunk关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle

npm init	//初始化包描述文件,输入包名称,以及其他信息,最终会生成package.json文件

npm i webpack webpack-cli -g	//全局安装,以便于使用webpack命令

npm i webpack webpack-cli -dev	//本地安装开发依赖

//运行打包项目指令
webpack	//将打包结果输出
npx webpack-dev-server	//在内存中编译打包,没有输出文件

1. 五个概念

  • 入口(entry):告知webpack从哪个文件开始打包。
  • 输出(output):最终打包文件dundle存放位置。
  • loader:让 webpack 能够去处理那些非 JavaScript/json 文件(webpack 自身只理解 JavaScript和json,不能处理css、img等。)。
  • 插件(plugins):打包优化和压缩。
  • 模式(model):development:能够让代码在本地调试运行。 production:代码优化后上线运行。

小技巧:node在当前目录中没有找打依赖包会到上级去找,所以可以把npm init 在多个目录最外层去install包,多个项目共用一份依赖包。

2. 配置

​ 2.1 development开发环境配置:

/**
 * webpack.config.js webpack的配置文件
 *  作用:指示webpack干什么(当运行webpack指令时,会加载里面的配置)
 * 
 * 所有构建工具都是基于nodejs平台运行的,模块化默认采用commonjs格式。
 */

//resolve用来拼接绝对路径的方法(nodejs自带的path小工具)
const {resolve} = require('path');
//引入html插件
const  HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    //webpack配置
    //入口起点
    entry: './src/index.js',
    //输出
    output: {
        //输出文件名
        filename: 'js/built.js',
        //输出路径:_dirname node.js的变量,代表当前目录的根目录(npm_learn/build)
        path: resolve(__dirname, 'build')
    },
    //loader配置(打包样式资源css/less/img): 安装 使用
    module: {
        rules: [
            //1.匹配css文件, npm i css-loader style-loader -D
            {
                test: /\.css$/,
                //use数组中loader执行顺序:从右向左,从下向上 依次执行
                use: [
                    //创建style标签,将js中的样式资源插入,添加到head中生效
                    'style-loader',
                    //将css文件变成commonjs模块加载js中,里面内容是样式字符串
                    'css-loader'
                ]
                //不能使用outputPath: 'css'指定css输出目录,应为use规则:最终会将样式打包到js中 
            },
            //2.匹配less文件, npm i css-loader style-loader less less-loader -D
            {
                test: /\.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    //将less文件编译成css文件(下载less 和less-loader)
                    'less-loader'
                ]
                //不能使用outputPath: 'css'指定css输出目录,应为use规则:最终会将样式打包到js中 
            },
            //3.匹配图片资源, npm i url-loader file-loader -D
            {
                test: /\.(jpg|png|gif)$/,
                loader: 'url-loader',
                options: {
                    //图片小于8k ,就会被base64处理(服务器会一次性将图片资源转成base64数据一次性返回,减少请求压力,小体积图片可以使用)
                    limit: 8 * 1024,
                    //关闭url-loader的默认es6的模块解析(html-loader引入图片是commonjs会出现问题),使用commonjs解析
                    esModule: false
                },
                outputPath: 'imgs'
            },
            //4. 专门处理html文件中(包括模板html)的img图片(负责引入img,从而能被url-loader进行处理),npm i html-loader -D
            {
                test: /\.html$/,
                loader: 'html-loader'
            },
            //5. 其他资源(除了html/css/js资源以外的资源)字体,图标等,npm i file-loader -D
            {
                exclude: /\.(css|js|html|less|json)$/,
                loader: 'file-loader',
                options: {
                    name: '[hash: 10].[ext]'    //打包后的命名:hash值取10位,保留原先后缀名
                },
                outputPath: 'other'
            }
        ]
    },
    //plugins配置(打包html资源): 安装 引入 使用
    plugins: [
        //1. 打包html资源 npm i html-webpack-plugin -D
        new HtmlWebpackPlugin({
            //不写template默认会创建一个空html,自动引入打包输出的所有资源(JS/CSS)
            //复制 './src/index.html'文件,并自动引入打包输出的所有资源(JS/CSS)
            template: './src/index.html'
        }),
    ],
    //模式
    mode: 'development',    //production
}

devServer:自动化(自动全部编译,自动打开浏览器,自动刷新浏览器)运行npx webpack-dev-server而不是webpack,否则看不到自动编译效果

const {resolve} = require('path');

module.exports = {
   //devServer:开发服务器:用于自动化(自动编译,自动打开浏览器,自动刷新浏览器)
    //特点:只会在内存中编译打包,不会有任何编译输出文件
    //启动devServer指令为:npx webpack-dev-server(安装 npm i webpack-dev-server -D)
    devServer: {
        contentBase: resolve(__dirname, 'build'),
        //启动gzip压缩
        compress: true,
        //端口号
        port: 3000,
        //自动打开默认浏览器
        open: true
    }
}

开发环境缺点:

  1. css文件都统一打包到js中,会让js体积变大,加载js变慢会出现闪屏

  2. 代码未经过压缩

  3. 兼容性问题

2.2 production生产环境配置,会自动压缩js:

​ webpack.config.js配置

const {resolve} = require('path');
//将css从js中抽离出来
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//压缩css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
//html
const HtmlWebpackPlugin = require('html-webpack-plugin');

//定义nodejs环境变量,决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';

//复用loader
const conmmonCssLoader = [
    // 取代style-loader,作用:提取js中的css成单独文件
    MiniCssExtractPlugin.loader,
    'css-loader',
    //css做兼容性处理,需要在package.json中定义browserslist
    {
        loader: 'postcss-loader',
        options: {
            ident: 'postcss',
            plugins: () => [
                require('postcss-preset-env')()
            ]
        }
    }
];
module.exports = {
    entry: '.src/js/index.js',
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'built')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [...conmmonCssLoader]
            }, 
            {
                test: /\.less$/,
                use: [...conmmonCssLoader,'less-loader']
            },

            //js语法规范检查,需在package.json中增加eslintConfig --> airbnb规则
            {
                test: /\.js$/,
                exclude: /node_modules/,
                enforce: 'pre', //优先执行
                loader: 'eslint-loader',
                //自动修复错误
                options: {
                    fix: true
                }
            },
            //js兼容性处理:es6转成es5兼容性会更好
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        '@babel/preset-env',//基本js兼容性处理,只能转换基本语法,像Promise不能转换
                        {
                            //按需加载(@babel/policy会将所有兼容性全引进去)
                            useBuiltIns: 'usage',
                            //按需加载使用corejs
                            corejs: {version:3},
                            //兼容chrome版本60+
                            targets: {
                                chrome: '60',
                                firefox: '50'
                            }
                        }
                    ]
                }
            },
            {
                test: /\.(jpg|png|gif)$/,
                loader: 'url-loader',
                options: {
                    limit: 8 * 1024,
                    name: '[hash:10].[ext]',
                    outputPath: 'imgs',
                    esModule: false //关闭es6模块化,因为html-loader使用的commonjs模块化
                }
            },
            {
                test: /\.html$/,
                loader: 'html-loader'
            },
            {
                test: /\.(js|css|less|html|jpg|png|gif)$/,
                loader: 'file-loader',
                options: {
                    outputPath:'other'
                }
            }
            
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            //指定css输出文件
            filename: 'css/built.css'
        }),
        new OptimizeCssAssetsWebpackPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            //压缩html
            minify: {
                collapseWhitespace: true,   //去除空格
                removeComments: true    //去除注释
            }
        })
    ],
    mode: 'production'  //js自动压缩
}

​ package.json配置

 "browserslist": {
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ]
  },
  "eslientConfig": {
    "extends": "airbnb-base",
    // eslient不识别window、navigator等浏览器属性
    "env": {
        "browser": true
    }
  }

3. 优化(没有写笔记)

3.1 开发环境性能优化

  • 优化打包构建速度(默认修改一个文件全部文件都会重新打包):基于devServe的HMR (Hot Module Replacement,一个模块发生变化,只会重新打包这一个模块)

    /*
    	样式文件:可以使用HMR,style-loader默认内部会检测是否开启HMR
    	js文件:默认不能使用HMR,会全部进行打包。需要在js文件添加指定代码
    	html文件:默认不能使用HMR,同时会导致不能热更新了。需要在入口文件加入html就行(一般入口文件不需变化,不用做HMR功能)
    */
    const {resolve} = require('path');
    
    module.exports = {
        entry: ['./src/js/index.js', './src/index.html']
        devServer: {
            contentBase: resolve(__dirname, 'build'),
            compress: true,
            port: 3000,
            open: true,
            // 开启HMR功能
            hot: true
        }
    }
    
    // index.js
    import print from 'print';
    // 开启HMR
    if (module.hot) {
        // 监听print.js文件的变化,以但变化,其他模块不会重新打包构建,会执行后面的回调
        module.hot.accept('print.js', function() {
          print();  
        })
    }
    
    // print.js
    function print() {
        console.log("js的HMR生效~~");
    }
    export default pring;
    
  • 优化代码调试 source-map(提供构建后代码报错,通过改该映射可以追踪源代码错误行数等信息)

    const {resolve} = require('path');
    
    module.exports = {
        entry: ['./src/js/index.js', './src/index.html']
        devServer: {
            contentBase: resolve(__dirname, 'build'),
            compress: true,
            port: 3000,
            open: true,
            hot: true
        },
        // 开启source-map
        devtool: 'source-map'
    }
    

3.2 生产环境性能优化

  • 优化打包构建速度

    • oneOf
    /*
    	oneOf的使用:
    */
    const {resolve} = require('path');
    
    module.exports = {
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    enforce: 'pre',
                    loader: 'eslint-loader',
                },
                // 以下loader当匹配一个后续就不再进行匹配,注意相同类型文件要将多余放到外部
                oneOf: [
                	{
                        test: /\.css$/,
                        use: [...conmmonCssLoader]
                    }, 
                    {
                        test: /\.js$/,
                        exclude: /node_modules/,
                        loader: 'babel-loader',
                    }
            	]   
            ]
        }
    }
    
    • babel缓存(js文件进行babel-loader处理,比方说100个文件,只修改1个js,其他打包好的js是不会在重新打包)
    /*
    	babel缓存的使用:cacheDirectory: true,让第二次打包构建速度更快。
    */
    const {resolve} = require('path');
    
    module.exports = {
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    enforce: 'pre',
                    loader: 'eslint-loader',
                },
                oneOf: [
                    {
                        test: /\.js$/,
                        exclude: /node_modules/,
                        loader: 'babel-loader',
        				options: {
                            presets: [
                                '@babel/preset-env',
                                {
                                    useBuiltIns: 'usage',
                                    corejs: {version:3},
                                    targets: {
                                        chrome: '60',
                                        firefox: '50'
                                    }
                                }
                            ]
                        },
                        // 开启babel缓存,第二次构建时,会读取之前的缓存
                        cacheDirectory: true
                    }
            	]   
            ]
        }
    }
    
    • 多进程打包

      /*
      	thread-loader放在某个loader的后面,会对后面lodaer使用多进程处理
      */
      module.exports = {
            module: {
                rules: [
                    {
                        test: /\.js$/,
                        exclude: /node_modules/,
                        use: [
                            // 开启多线程,进程开启大概为600ms,进程通信也有开销。耗时较长时再考虑使用。
                            {
                                loader: 'thread-loader',
                                options: {
                                    workers: 2	//	一般是最大核心数-1
                                }
                            },
                            {
                                loader: 'babel-loader',
                                options: {
                                    presets: [
                                        '@babel/preset-env',
                                        {
                                            useBuiltIns: 'usage',
                                            corejs: {version:3},
                                            targets: {
                                                chrome: '60',
                                                firefox: '50'
                                            }
                                        }
                                    ]
                                },
                                cacheDirectory: true
                            }
                        ]
                    }
                ]   
            }
        }
      
    • externals:拒绝npm某个包被打包进去,需要再模板html中通过cdn引入。

      /*
      	index.html中手动引入:<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
      */
      
      module.exports = {
          module: {},
          externals: {
          	// 忽略被打包的库名 --npm 包名
          	jquery: 'jQuery'
          }
      }
      
  • 优化代码运行性能

    • 文件资源缓存:contenthash根据文件内容生成hash值,打包命名使用到该hash值,修改内容文件名称会变化,客户端检测到文件名称变化就会请求服务器资源,而不是使用本地缓存。
    /*
        文件资源缓存,让上线运行更好使用浏览器缓存:
    		hash:每次webpack构建都会生成一个唯一的hash值。修改一个文件全部文件名称都会改变。
    		chunkhash:根据chunk生成的hash值。比如:入口文件引入多个css、js文件(入口文件和内部引用文件同属一个chunk),js和css的hash值一样。
    		contenthash:根据文件的内容生成hash值,不同文件hash值一定不同。
    */
    const {resolve} = require('path');
    
    module.exports = {
        entry: '.src/js/index.js',
        output: {
            filename: 'js/built.[contenthash:10].js',
            path: resolve(__dirname, 'built')
        },
        module: {}
    }
    
    • tree shaking:生产环境会自动开启(去除无用代码,较少代码体积,比如:只引入文件中一个方法,其他方法不会打包进去)
    /*
    	前提:1.使用es模块化引入文件。2.webpack.config.js开启mode: production
    */
    const {resolve} = require('path');
    
    module.exports = {
        entry: '.src/js/index.js',
        output: {
            filename: 'js/built.[contenthash:10].js',
            path: resolve(__dirname, 'built')
        },
        module: {}
    }
    
    // package.json设置哪些文件不进行tree shaking(“sideEffects”: false代表所有代码没有副作用,都可以进行tree shaking。问题:打包后生成的css文件去除)
    “sideEffects”: ["*.css"]
    
    • code split:代码分割
    /*
    	optimization:
    		单入口:将第三方依赖包单独打包到一个js中
    		多入口:自动分析多入口chunk中,将第三方依赖单独打包一个chunk,相当于抽取成公共部分。
    */
    const {resolve} = require('path');
    
    module.exports = {
        optimization: {
            splitChunks: {
                chunks: 'all'
            }
        }// 解决:a 通过懒加载引入 b;当b内容改变时打包后的文件名会变,a中引入的b所以a内容也变了a也会重新打包。
        // 生成runtime-[name].js管理打包后文件的名称,这样当a内容改变只会重新生成a和runtime-[name].js文件
      runtimeChunk: {
        	name: entrypoint => `runtime-${entrypoine.name}`
    }
    }
    
    • 懒加载/预加载
    // 通过js代码import动态导入语法,让某一个文件被单独打包成一个chunk
    // 通过/* webpackChunkName: 'test' */对打包文件命名
    document.getElementById('btn').onclick = function() {
        // 懒加载:代码中真正使用到才会去 请求加载并执行;
        import(/* webpackChunkName: 'test' */'test').then().catch();
        
      // 预加载prefetch: 等其他资源加载完毕,浏览器空闲了,会去预先请求加载,等到真正使用时立即执行,就无需等待网络的消耗;
        // (preload和prefetch的兼容性不太好)
      import(/* webpackChunkName: 'test', webpackPrefetch: true */'test').then().catch()
    }
    
  • PWA:借助ServiceWorker使其离线可访问,sw代码必须运行再服务器上

    借助服务器 npm i service -g

    serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去

    /*
    	optimization:
    		单入口:将第三方依赖包单独打包到一个js中
    		多入口:自动分析多入口chunk中,将第三方依赖单独打包一个chunk,相当于抽取成公共部分。
    */
    const {resolve} = require('path');
    const WorkboxWebpackPlugin = require('work-webpack-plugin');
    
    module.exports = {
        plugins: [
        	new WorkboxWebpackPlugin.GenerateSW({
        		// 1. 帮助servieWorker快速启动。2. 删除旧的serviceWorker
        		clientsClain: true,
      		skipWating: true
        	})
        ]
    }
    
    // 入口文件index.js注册serivceWorker
    
    // 判断浏览器兼容serviceWOrker,等到浏览器加载完全部资源再注册
    if ('serviceWorker' in navigator) {
        window.addEventListener('load', () => {
            navigator.serviceWorker.register('/service.worker.js')
          	.then(() => {console.log('sw注册成功');})
            	.catch(() => {console.log('sw注册失败');})
        })
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Webpack是一个用于打包前端应用程序的工具,可以将多个模块打包成一个或多个文件,同时还支持代码分离、模块化、压缩等功能。下面是Webpack的基本配置优化代码的说明: 1. 基本配置 (1)entry:入口文件,Webpack会从该文件开始递归解析依赖,生成打包后的文件。 (2)output:输出文件配置,指定打包后生成的文件路径和名称。 (3)module:模块加载器配置,用于加载各种类型的文件,如js、css、图片等。 (4)plugins:插件配置,用于扩展Webpack功能,如压缩代码、提取公共模块、生成HTML模板等。 (5)devServer:开发服务器配置,可以自动编译代码并提供热更新等功能。 (6)resolve:模块解析配置,用于配置模块的搜索路径、别名等。 2. 优化代码 (1)使用Tree Shaking:Tree Shaking是Webpack 2引入的功能,用于去除无用的代码。只有被使用的代码才会被打包进最终的文件。 (2)使用Code Splitting:将代码拆分成多个块,按需加载,可以提高页面加载速度。 (3)使用动态导入:使用import()函数动态加载代码,可以根据需要加载不同的模块,提高性能。 (4)使用缓存:使用缓存可以避免重复打包已经打包过的代码,提高打包速度。 (5)使用异步加载:异步加载可以提高页面加载速度,特别是在处理大型应用程序时更为重要。 (6)使用压缩插件:压缩代码可以减小文件大小,提高加载速度。 (7)使用静态资源CDN:使用CDN可以将静态资源分布到多个服务器上,提高访问速度,减少服务器负载。 总之,通过合理的配置优化,可以大大提高Webpack的性能和效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值