前言:文件依赖关系错综复杂,静态资源请求效率低,模块化支持不友好,浏览器对高级JS兼容程度低?那就是时候了解webpack了javascript
webpack 是一个JavaScript 应用程序的静态模块打包构建器。在处理应用程序时, webpack 会递归地构建一个依赖关系图,其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle。webpack提供了友好的模块化支持,以及代码压缩混淆、高级js兼容、性能优化。css
入口起点(entry point)指示 webpack 使用哪一个模块,做为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。html
webpack.config.js:vue
module.exports = { entry: { main: './src' //打包入口,来指定一个入口起点(或多个入口起点,默认值为 ./src) }, entry: './src', //这个是上面的简写方式,是等价的 entry: { home: "./home.js", about: "./about.js", contact: "./contact.js" },//对象法指定多个入口,若是你想要多个依赖一块儿注入到一个模块,向 entry 属性传入「文件路径(file path)数组」。 entry: () => new Promise((resolve) => resolve(['./demo', './demo2'])),//动态入口,当结合 output.library 选项时:若是传入数组,则只导出最后一项 };
output 属性告诉 webpack 在哪里输出它所建立的 bundles,以及如何命名这些文件。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。java
webpack.config.js:node
const path = require('path'); module.exports = { output: { path: path.resolve(__dirname, 'dist'),//打包文件夹名,默认值为 ./dist filename: '[name].js'//入口文件名 } };
loader 用于转换某些类型的模块,webpack 自身只理解 JavaScript,loader 能够将全部类型的文件转换为 webpack 可以处理的有效模块。loader 可以 import
导入任何类型的模块(如 .css
),是 webpack 特有的功能,其余打包工具备可能不支持。webpack
webpack.config.js:ios
const path = require('path'); const config = { module: { rules: [//在 webpack 配置中定义 loader 时,要定义在 module.rules 中,里面包含两个"必须属性":test 和 use { test: /\.txt$/, //test 定义须要使用相应 loader 进行转换的某类文件 use: 'raw-loader' //use 定义使用哪一个 loader 进行转换 } ] } }; module.exports = config;
插件接口功能极其强大,能够用来处理各类各样的任务。经过require()
使用插件,而后把它添加到 plugins
数组中。多数插件能够经过选项(option)自定义。es6
webpack.config.js:web
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 经过 npm 安装 const webpack = require('webpack'); // 用于访问内置插件 const config = { plugins: [ //在一个配置文件中由于不一样目的而屡次使用同一个插件,须要经过使用 new 操做符来建立它的一个实例 new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
module.exports = { mode: 'production'//经过选择 development(开发) 或 production(生产),启用相应模式下的 webpack 内置的优化 };
webpack 须要传入一个配置对象, 根据对象定义的属性进行解析,所以不多有 webpack 配置看起来很彻底相同。 webpack 的配置文件,是导出一个对象的 JavaScript 文件。能够经过两种方式(终端、Node.js)使用 webpack。
webpack 配置是标准的 Node.js CommonJS 模块,你能够:
require(...)
导入其余文件require(...)
使用 npm 的工具函数?:
操做符应避免如下作法:
--env
)时,访问命令行接口(CLI)参数webpack 配置是标准的 Node.js CommonJS 模块,在安装webpack以前,请确保安装了 Node.js 的最新版本,使用旧版本可能遇到各类问题(可能缺乏 webpack 功能或者缺乏相关 package 包)。
对于大多数项目,建议本地安装。这能够在引入破坏式变动(breaking change)的依赖时,更容易分别升级项目。不推荐全局安装 webpack。这会将你项目中的 webpack 锁定到指定版本,而且在使用不一样的 webpack 版本的项目中,可能会致使构建失败。
①本地安装 npm install --save-dev webpack //安装最新版本 npm install --save-dev webpack@<version> //安装特定版本 ②全局安装 npm install --global webpack
若是你使用 webpack 4+ 版本,你还须要安装 CLI,此工具用于在命令行中运行 webpack。
npm install --save-dev webpack-cli //webpack-cli用于在命令行中运行 webpack
在已有的项目中:
npm init -y //初始化webpack 这里会自动生成一个package.json npm i -D webpack webpack-cli //安装webpack及其脚手架
一个项目包两个项目demo1和demo2(适用于两个项目功能需求很相似有公用的地方有不一样的地方):
{ "name": "webpackstudy", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "demo1-start": "webpack-dev-server --progress --color", "demo2-start": "webpack-dev-server --progress --color", "demo1-mock": "webpack-dev-server --progress --color", "demo2-mock": "webpack-dev-server --progress --color", "demo1-te": "webpack --progress --color", "demo2-te": "webpack --progress --color" }, "author": "", "license": "ISC", "dependencies": { "axios": "^0.19.0", "vue": "^2.6.10", "vue-pull-to": "^0.1.8", "vue-router": "^3.1.2", "vuex": "^3.1.1" }, "devDependencies": { "@babel/core": "^7.5.5", "@babel/preset-env": "^7.5.5", "autoprefixer": "^9.6.1", "babel-loader": "^8.0.6", "clean-webpack-plugin": "^3.0.0", "css-loader": "^3.2.0", "file-loader": "^4.2.0", "html-webpack-plugin": "^3.2.0", "html-withimg-loader": "^0.1.16", "jsonc": "^2.0.0", "less": "^3.10.2", "less-loader": "^5.0.0", "mini-css-extract-plugin": "^0.8.0", "mocker-api": "^1.8.1", "optimize-css-assets-webpack-plugin": "^5.0.3", "postcss-loader": "^3.0.0", "style-loader": "^1.0.0", "terser-webpack-plugin": "^1.4.1", "uglifyjs-webpack-plugin": "^2.2.0", "url-loader": "^2.1.0", "vue-loader": "^15.7.1", "vue-style-loader": "^4.1.2", "vue-template-compiler": "^2.6.10", "webpack": "^4.39.2", "webpack-cli": "^3.3.7", "webpack-dev-server": "^3.8.0" } }
const path = require('path'); const webpack = require('webpack'); // script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题; 自动建立html入口文件 const HtmlWebpackPlugin = require('html-webpack-plugin'); // 用terser-webpack-plugin替换掉uglifyjs-webpack-plugin解决uglifyjs不支持es6语法问题 const TerserJSPlugin = require('terser-webpack-plugin'); // 此模块至少须要Node v6.9.0和webpack v4.0.0 混淆代码 const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); // 这个插件将CSS提取到单独的文件中 支持按需加载CSS和SourceMaps 创建在webpack v4上 const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 用于优化、压缩CSS资源 const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 打包时将以前打包的目录里的文件先清除干净,再生成新的 const {CleanWebpackPlugin} = require('clean-webpack-plugin'); //mock数据 const apiMocker = require('mocker-api'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); //获取 npm run 后面的命令 const lifecycle = process.env.npm_lifecycle_event; //npm run 的文件名 const project = lifecycle.split('-')[0]; //npm run 的环境名 const proMode = lifecycle.split('-')[1] === 'te'; const envMode = lifecycle.split('-')[1]; const webpackConfig = { mode: proMode ? 'production' : 'development', //打包入口为每一个项目的main.js entry: path.resolve(__dirname, `${project}/main.js`), output: { //打包后的文件目录为各自项目名+Dist path: path.resolve(__dirname, `${project}Dist`), //打包后源代码映射 // devtool: proMode ?'cheap-module-eval-source-map':'hidden-source-map', // devtool: "inline-source-map", //打包后的出口js目录 filename: 'js/[name].[hash].js', //分块打包的js目录 chunkFilename: proMode ? 'js/[name].[contenthash].bundle.js' : 'js/[name].bundle.js', }, module: { rules: [ { test: /\.vue$/, exclude: /node_modules/, use: { loader: 'vue-loader' } }, { test: /\.(le|c)ss$/i, use: [ proMode ? MiniCssExtractPlugin.loader : 'vue-style-loader', 'css-loader', 'postcss-loader', 'less-loader', ], }, { test: /\.html$/i, use: [ 'html-withimg-loader' ] }, { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 4096, name: 'img/[name].[contenthash].[ext]' }, }, ], }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] }, //webpack-dev-server 配置npm run 时启动本地服务 devServer: { contentBase: `./${project}Dist`, inline: true //实时刷新 }, //优化 optimization: { // 分块 splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all' }, } } }, plugins: [ new CleanWebpackPlugin(), //定义插件—— 在项目中能够读取到 new webpack.DefinePlugin({ 'baseUrl':proMode ? 'https:www.baidu.com':JSON.stringify('localhost') }), new HtmlWebpackPlugin({ title:'webpack练习', filename: 'index.html', template: `${project}/index.html`, // 对 html 文件进行压缩 minify: { //是否对大小写敏感,默认false caseSensitive: false, //是否简写boolean格式的属性如:disabled="disabled" 简写为disabled 默认false collapseBooleanAttributes: true, //是否去除空格,默认false collapseWhitespace: true, //是否压缩html里的css(使用clean-css进行的压缩) 默认值false; minifyCSS: true, //是否压缩html里的js(使用uglify-js进行的压缩) minifyJS: true, //是否移除注释 默认false removeComments: true, //Prevents the escaping of the values of attributes preventAttributesEscaping: true, //是否移除属性的引号 默认false removeAttributeQuotes: true, //从脚本和样式删除的注释 默认false removeCommentsFromCDATA: true, //是否删除空属性,默认false removeEmptyAttributes: false, // 若开启此项,生成的html中没有 body 和 head,html也未闭合 removeOptionalTags: false, //删除多余的属性 removeRedundantAttributes: true, //删除script的类型属性,在h5下面script的type默认值:text/javascript 默认值false removeScriptTypeAttributes: true, //删除style的类型属性, type="text/css" 同上 removeStyleLinkTypeAttributes: true, //使用短的文档类型,默认false useShortDoctype: false, } }), new VueLoaderPlugin() ], //目录映射 resolve: { alias: { '@assets': path.resolve(__dirname, `${project}/assets`), '@mixins': path.resolve(__dirname, `${project}/mixins`), '@tools': path.resolve(__dirname, `${project}/tools`), '@components': path.resolve(__dirname, `${project}/components`), } } }; if (proMode) { webpackConfig.optimization.minimizer = [ //混淆语法 new UglifyJsPlugin({ chunkFilter: (chunk) => { if (chunk.name === 'vendor') { return false; } return true; }, //去掉控制台日志 uglifyOptions: { compress: { drop_console: true } } }), new OptimizeCssAssetsPlugin({}) ]; // webpackConfig.optimization.minimizer = [new TerserJSPlugin({}), // new OptimizeCssAssetsPlugin({}),]; webpackConfig.plugins.push( new MiniCssExtractPlugin({ filename: proMode ? '[name].css' : '[name].[hash].css', chunkFilename: proMode ? '[id].css' : '[id].[hash].css', }) ) } else { // 热更新模块 webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); webpackConfig.devtool = 'inline-source-map'; if (envMode == 'mock') { //mock环境,启用mock代理服务 webpackConfig.devServer.before = (app) => { apiMocker(app, path.resolve(`${project}/mock/api.js`)); }; //非mock匹配项走测试环境 webpackConfig.devServer.proxy = process.baseUrl; } } module.exports = webpackConfig;