2023年6月21日发(作者:)

vue-vue-cli2脚⼿架搭建build⽂件夹详解构建环境下的配置:  loading动画  删除创建⽬标⽂件夹  webpack编译;输出信息//这是vue-cli脚⼿架⼯具的⽣产环境配置⼊⼝ 中的"build": "node build/"的直接指向。// js的严格模式'use strict'

//检查node+npm的版本,引⽤./⽂件require('./check-versions')()//设置环境变量为⽣产环境_ENV = 'production'//导⼊ora模块 实现loading效果,实际是⼀个命令⾏转圈圈动画插件,好看⽤的const ora = require('ora')//导⼊rimraf模块 以包的形式包装rm -rf命令,⽤来删除⽂件和⽂件夹的,不管⽂件是否为空//rimraf插件是⽤来执⾏UNIX命令rm和-rf的⽤来删除⽂件夹和⽂件,清空旧的⽂件const rm = require('rimraf')//导⼊node的path模块,路径模块 连接路径,例⼦:('/foo', 'bar', 'baz/asdf', 'quux', '..');const path = require('path')//导⼊chalk模块 ⽤来改变⽂字颜⾊const chalk = require('chalk')//导⼊webpack模块使⽤内置插件和webpack⽅法const webpack = require('webpack')//导⼊config/,commonJs风格,引⼊⽂件模块,引⼊模块分为内置模块与⽂件模块两种const config = require('../config')//导⼊nst webpackConfig = require('./')//实现loading的模块const spinner = ora('building ')//开始动画()/* rm⽅法删除dist/static⽂件夹 是将路径⽚段以''连接成新的路径,任何⼀个路径⽚段有错误就会报错 调⽤rm⽅法,第⼀个参数的结果就是 绝对/⼯程名/dist/static,表⽰删除这个路径下⾯的所有⽂件 若删除中有错误则抛出异常并终⽌程序 若没有错误则继续执⾏,构建webpack 结束动画 若有异常则抛出 标准输出流,类似于*/rm((Root, SubDirectory), err => { //如果删除的过程中出现错误,就抛出这个错误,同时程序终⽌ if (err) throw err //没有错误,就执⾏webpack编译 构建webpack webpack(webpackConfig, (err, stats) => { //停⽌动画 () if (err) throw err //如果有错误就抛出错误 //是标准输出,相当于 (ng({ //stats对象中保存着编译过程中的各种消息 colors: true, // 增加控制台颜⾊开关 colors: true, // 增加控制台颜⾊开关 modules: false, // 是否增加内置模块信息 children: false, // 不增加⼦级信息 chunks: false, // 允许较少的输出 chunkModules: false // 不将内置模块信息加到包信息 }) + 'nn') // 编译过程持续打印 // 编译出错的信息 if (ors()) { ((' Build failed with errors.n')) //执⾏失败 (1) } //以上就是在编译过程中,持续打印消息 // 编译成功的信息,并退出 ((' Build complete.n')) (( ' Tip: built files are meant to be served over an HTTP server.n' + ' Opening over file:// won't work.n' )) })})和npm的版本检查// js的严格模式'use strict'// 导⼊chalk模块 ⽤来改变⽂字颜⾊const chalk = require('chalk')// 控制版本const semver = require('semver')// 获取版本,commonJs风格,引⼊⽂件模块,引⼊模块分为内置模块与⽂件模块两种const packageConfig = require('../')// 插件,执⾏unix系统命令const shell = require('shelljs')function exec (cmd) { // 脚本可以通过child_process模块新建⼦进程,从⽽执⾏Unix系统命令 // 将cmd参数传递的值转换成前后没有空格的字符串,也就是版本号 // require('child_process')调⽤nodejs⼦进程, // execSync同步的exec⽅法执⾏command return require('child_process').execSync(cmd).toString().trim()}//声明常量数组,数组内容为有关node相关信息的对象const versionRequirements = [ { //对象名称为node name: 'node', //使⽤semver插件,把版本信息转换成规定格式 currentVersion: (n), //规定中engines选项的node版本信息 versionRequirement: }]//which为linux指令,在$path规定的路径下查找符合条件的⽂件//('npm')就是寻找npm命令if (('npm')) { //将npm添加到versionRequirements

({ name: 'npm', 调⽤npm --version命令,并且把参数返回给exec函数获取纯净版本 调⽤npm --version命令,并且把参数返回给exec函数获取纯净版本 //exec()⽅法就是执⾏⼀个命令(在这⾥是执⾏npm --version),返回版本信息的函数。 currentVersion: exec('npm --version'), //规定中engines选项的npm版本信息 versionRequirement: })}s = function () { const warnings = [] for (let i = 0; i < ; i++) { const mod = versionRequirements[i] // 如果版本号不符合⽂件中指定的版本号,就执⾏... // 当前版本号⽤红⾊标识,要求版本号⽤绿⾊标识,当前版本不符合要求版本那么就将提⽰信息添加到wranings if (!ies(tVersion, nRequirement)) { ( + ': ' + (tVersion) + ' should be ' + (nRequirement) // ⼤致意思就是 把当前版本号⽤红⾊字体 符合要求的版本号⽤绿⾊字体 给⽤户提⽰具体合适的版本 ) } } //如果为真,则打印提⽰⽤户升级新版本 if () { ('') (('To use this template, you must update following to modules:')) () for (let i = 0; i < ; i++) { const warning = warnings[i] (' ' + warning) } //执⾏失败 (1) }}配置静态资源路径;⽣成cssLoaders⽤于加载.vue⽂件中的样式;⽣成styleLoaders⽤于加载不在.vue⽂件中的单独存在的样式⽂件'use strict'// 引⼊nodejs路径模块const path = require('path')// 引⼊config下的⽂件const config = require('../config')// ⼀个插件,抽离css样式,防⽌将样式打包在js中引起样式加载错乱// 引⼊extract-text-webpack-plugin插件,⽤来将css提取到单独的css⽂件中// 详情请看(1)const ExtractTextPlugin = require('extract-text-webpack-plugin')

const packageConfig = require('../')// exports其实就是⼀个对象,⽤来导出⽅法的,最终还是使⽤s,此处导出Path = function (_path) { // 如果是⽣产环境assetsSubDirectory就是'static',否则还是'static' const assetsSubDirectory = _ENV === 'production' SubDirectory : SubDirectory // 返回绝对路径(在电脑上的实际位置);返回相对路径 return (assetsSubDirectory, _path)

// 此⽅法返回⼀个⼲净的相对根路径

}// 下⾯是导出cssLoaders的相关配置ders = function (options) { options = options || {}

// cssLoader的基本配置 const cssLoader = { loader: 'css-loader', // options是⽤来传递参数给loader的 options: { // minimize表⽰压缩,如果是⽣产环境就压缩css代码,这⾥全部压缩 // minimize: _ENV === 'production', // 是否开启cssmap,默认是false sourceMap: Map } }

// 为css⾃动⽣成兼容性前缀 const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: Map } }

// 适配移动端屏幕⾃适应像素兼容性75px==1rem,这⾥没有⽤到 // const px2remLoader = { // loader: 'px2rem-loader', // options: { // remUnit: 75 // } // } // generate loader string to be used with extract text plugin function generateLoaders (loader, loaderOptions) { // 将上⾯的基础cssLoader配置、兼容性前缀配置、⾃适应配置放在⼀个数组⾥⾯ // const loaders = tCSS ? [cssLoader, postcssLoader, px2remLoader] : [cssLoader, px2remLoader] const loaders = tCSS ? [cssLoader, postcssLoader] : [cssLoader] // 如果该函数传递了单独的loader就加到这个loaders数组⾥⾯,这个loader可能是less,sass之类的 if (loader) { ({ // 加载对应的loader loader: loader + '-loader', // 是es6的⽅法,主要⽤来合并对象的,浅拷贝 options: ({}, loaderOptions, { sourceMap: Map }) }) } // Extract CSS when that option is specified // (which is the case during production build) // 注意这个extract是⾃定义的属性,可以定义在options⾥⾯,主要作⽤就是当配置为true就把⽂件单独提取, // false表⽰不单独提取,这个可以在使⽤的时候单独配置 if (t) { return t({ use: loaders, fallback: 'vue-style-loader' }) } else { return ['vue-style-loader'].concat(loaders) } // 上⾯这段代码就是⽤来返回最终读取和导⼊loader,来处理对应类型的⽂件 } // options如果不为null或者undefined,0,""等等就原样,否则就是{}。在js⾥⾯,||运算符,A||B,A如果为真,直接返回A。如果为假,直接返回B(不会判断B是什么 } // /en/configurations/ return { // css对应 vue-style-loader 和 css-loader css: generateLoaders(), // postcss对应 vue-style-loader 和 css-loader postcss: generateLoaders(), // less对应 vue-style-loader 和 less-loader less: generateLoaders('less'), // sass对应 vue-style-loader 和 sass-loader sass: generateLoaders('sass', { indentedSyntax: true }), // scss对应 vue-style-loader 和 sass-loader scss: generateLoaders('sass'), // stylus对应 vue-style-loader 和 stylus-loader stylus: generateLoaders('stylus'), // styl对应 vue-style-loader 和 styl-loader styl: generateLoaders('stylus') }}// Generate loaders for standalone style files (outside of .vue)// 下⾯这个主要处理import这种⽅式导⼊的⽂件类型的打包,上⾯的ders是为这⼀步服务的oaders = function (options) { const output = [] // 下⾯就是⽣成的各种css⽂件的loader对象 const loaders = ders(options) for (const extension in loaders) { // 把每⼀种⽂件的laoder都提取出来 const loader = loaders[extension] ({ // 把最终的结果都push到output数组中,⼤事搞定 test: new RegExp('.' + extension + '$'), use: loader }) } return output}NotifierCallback = () => { // 发送桌⾯消息 const notifier = require('node-notifier') return (severity, errors) => { if (severity !== 'error') return const error = errors[0] const filename = && ('!').pop() ({ title: , message: severity + ': ' + , subtitle: filename || '', icon: (__dirname, '') }) }}注释1// extract-text-webpack-plugin插件是⽤来将⽂本从bundle中提取到⼀个单独的⽂件中// 基本使⽤⽅法如下const ExtractTextPlugin = require("extract-text-webpack-plugin");s = { module: { rules: [ { test: /.css$/, //主要⽤来处理css⽂件 use: t({ fallback: "style-loader", // fallback表⽰如果css⽂件没有成功导⼊就使⽤style-loader导⼊ use: "css-loader" // 表⽰使⽤css-loader从js读取css⽂件 }) } ], plugins: [ new ExtractTextPlugin("") //表⽰⽣成⽂件 ] }}处理.vue⽂件的配置⽂件'use strict'const utils = require('./utils')const config = require('../config')// 是否为⽣产环境const isProduction = _ENV === 'production'// 根据环境来获取相应的productionSourceMap或者cssSourceMapconst sourceMapEnabled = isProduction tionSourceMap : rceMap// 导出s = { // 载⼊utils中的cssloaders返回配置好的css-loader和vue-style=loader loaders: ders({ // 是否开始sourceMap ⽤来调试 sourceMap: sourceMapEnabled, // 是否将单独的css⽂件(⼀般为引⼊的外部⽂件)进⾏提取单独打包 extract: isProduction }), // 记录压缩的代码,⽤来找到源码位置 cssSourceMap: sourceMapEnabled, // 是否缓存破坏 cacheBusting: usting, // transformToRequire的作⽤是在模块编译的过程中,编译器可以将某些属性,⽐如src转换为require调⽤ transformToRequire: { video: ['src', 'poster'], source: 'src', img: 'src', image: 'xlink:href' }}基本的webpack配置  配置webpack编译⼊⼝  配置webpack输出路径和命名规则  配置模块resolve规则  配置不同类型模块的处理规则'use strict'// 引⼊node path 中间件 可以获取到 path 路径的⼀些信息const path = require('path')// 引⼊utils⼯具模块 utils主要⽤来处理css-loader和vue-style-loader的const utils = require('./utils')// 引⼊config下⾯的index⽂件 主要是配置⼀些开发环境和⽣产环境的配置const config = require('../config')// ⽤来解决各种css ⽂件 sass less stulys 等const vueLoaderConfig = require('./')// 定义了⼀个路径函数 返回当前的⽬录的平⾏⽬录下的dir 因为有'..'也就是获取绝对路径,⽅便对import时引⼊地址的⽅便填写function resolve(dir) { return (__dirname, '..', dir)}// eslint 的检测规则const createLintingRule = () => ({ // 对js和vue ⽂件进⾏eslint 检查 test: /.(js|vue)$/, // 使⽤eslint-loader loader: 'eslint-loader', // enforce执⾏的意思 有两个值 pre post // pre是在其他规则执⾏之前执⾏ post是在其他规则执⾏之后执⾏ enforce: 'pre', // 进⾏检测的⽂件⽬录包括哪些 调⽤了路径函数 include: [resolve('src'), resolve('test')], options: { // 使⽤第三⽅的插件进⾏eslint 检测 formatter: require('eslint-friendly-formatter'), // 是否输出eslint报错信息 emitWarning: !lintErrorsInOverlay }})// webpack的配置,可以理解成是开发环境和正式环境的⼀些公共配置s = { // webpack 解析时根⽬录地址如果此⽂件在跟⽬录这句话就不⽤写 context: e(__dirname, '../'), // 项⽬的⼊⼝⽂件 entry: { app: './src/' }, // 项⽬出⼝⽂件配置 output: { // 项⽬buid的出⼝⽂件的⽬录地址,这⾥指的是(../dist⽂件⽬录) 引⼊的是 下⾯的配置 path: Root, // ⽂件的名字 filename: '[name].js', // 输出解析⽂件的⽬录,url 相对于 HTML 页⾯(⽣成的html⽂件中,css和js等静态⽂件的url前缀) publicPath: _ENV === 'production' PublicPath : PublicPath }, resolve: { // 指定哪些⽂件在引⽤时可以省略后缀名 extensions: ['.js', '.vue', '.json'], // 别名,在引⽤⽂件时 使⽤别名代理真实⽬录 后⾯再在⽬录时以别名代替 alias: { alias: { 'vue$': 'vue/dist/', '@': resolve('src'), } }, module: { // 转换解析规则 // 是⽤来解析所有此后缀名的⽂件, // 我们⽤什么npm什么形式的loader去解析 // e是代表我们解析的⽂件只包含那些东西 // s解析⽂件参数设置 具体看下⾯的解释 rules: [ ...(int ? [createLintingRule()] : []), { test: /.vue$/, loader: 'vue-loader', // 对vue的css进⾏解析 options: vueLoaderConfig }, { // 对js⽂件使⽤babel-loader进⾏解析 主要是解析es6 test: /.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] }, { // 对图⽚使⽤url-loader解析 这个插件的作⽤是将⼀个⾜够⼩的⽂件⽣成⼀个64位的DataURL // 当limit⼩于10000进⾏将图⽚⽣成base64 // name 指的是引⼊的utils⾥⾯的⼀个⽅法 将name ,7位哈希 .ext 代表后缀名 // 传⼊⽅法 返回结果是 /static/img/[name].[hash:7].[ext] test: /.(png|jpe?g|gif|svg)(?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: Path('img/[name].[hash:7].[ext]') } }, { // 对⼀些⾳频⽂件进⾏解析 test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: Path('media/[name].[hash:7].[ext]') } }, { // 对字体⽂件进⾏解析 test: /.(woff2?|eot|ttf|otf)(?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: Path('fonts/[name].[hash:7].[ext]') } } ] }, node: { // prevent webpack from injecting useless setImmediate polyfill because Vue // source contains it (although only uses it if it's native). setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client // 是否 polyfill 或 mock // 源包含它(虽然仅在本地使⽤) // 预防webpack从注⼊模拟节点到node原⽣模块 // 预防webpack从注⼊模拟节点到node原⽣模块 dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' }, // webpack不处理下⾯的库,压缩包的⼤⼩,但是依然可以引⽤ externals: { 'AMap': 'AMap', }}'use strict'// 引⼊当前⽬录下的⽂件模块const utils = require('./utils')const webpack = require('webpack')const config = require('../config')// 进⾏合并对象,相同项⽬会进⾏覆盖const merge = require('webpack-merge')const path = require('path')const baseWebpackConfig = require('./')/ ⼀个拷贝资源的插件const CopyWebpackPlugin = require('copy-webpack-plugin')// ⽣成html⽂件const HtmlWebpackPlugin = require('html-webpack-plugin')// 下⾯这个插件是⽤来把webpack的错误和⽇志收集起来,漂亮的展⽰给⽤户const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')// ⼀个⾃动打开可⽤端⼝的包const portfinder = require('portfinder')// 当前环境的hostconst HOST = // //当前环境的portconst PORT = && Number()// 开发环境的配置const devWebpackConfig = merge(baseWebpackConfig, { module: { // loader的配置,创建模块时匹配请求的规则数组,这⾥调⽤了utils中的配置模板styleLoaders rules: oaders({ sourceMap: rceMap, usePostCSS: true }) }, // cheap-module-eval-source-map is faster for development // //debtool是开发⼯具选项,⽤来指定如何⽣成sourcemap⽂件,cheap-module-eval-source-map此款soucemap⽂件性价⽐最⾼ devtool: l, // these devServer options should be customized in /config/ // webpack服务器配置 devServer: { // 重新加载server时,控制台对⼀些错误以warning的⽅式提⽰ clientLogLevel: 'warning', // 当使⽤ HTML5 History API 时,任意的 404 响应都可能需要被替代为 historyApiFallback: { rewrites: [ { from: /.*/, to: (PublicPath, '') }, ], }, // 是否启⽤webpack的模块热替换特性。这个功能主要是⽤于开发过程中,对⽣产环境⽆帮助。效果上就是界⾯⽆刷新更新。 hot: true, // 告诉服务器从哪⾥提供内容。只有在你想要提供静态⽂件时才需要,这⾥我们禁⽤ contentBase: false, // since we use CopyWebpackPlugin. // ⼀切服务都启⽤gzip压缩 compress: true, // 指定⼀个host,默认是localhost。如果有全局host就⽤全局,否则就⽤中的设置。 host: HOST || , // 指定端⼝ port: PORT || , // 是否在浏览器开启本dev server,是否⾃动打开浏览器 open: enBrowser, // 当有编译器错误时,是否在浏览器中显⽰全屏覆盖。 overlay: verlay { warnings: false, errors: true } : false, // 静态内容的路径,此路径下的打包⽂件可在浏览器中访问 publicPath: PublicPath, // 如果你有单独的后端开发服务器api,并且希望在同域名下发送api请求,那么代理某些URL会很有⽤。 // 接⼝代理 proxy: able, // 启⽤ quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来⾃ webpack 的错误或警告在控制台不可见 quiet: true, // necessary for FriendlyErrorsPlugin // 监视⽂件的选项 watchOptions: { poll: , //是否使⽤轮询 } }, plugins: [ // DefinePlugin 允许创建⼀个在编译时可以配置的全局常量。这⾥⽣成了⼀个当前环境的常量 new Plugin({ '': require('../config/') }), // 模块热替换插件,修改模块时不需要刷新页⾯ new uleReplacementPlugin(), // 当开启 HMR 的时候使⽤该插件会显⽰模块的相对路径 new odulesPlugin(), // HMR shows correct file names in console on update. // 在编译出现错误时,使⽤ NoEmitOnErrorsPlugin 来跳过输出阶段。这样可以确保输出资源不会包含错误。 new OnErrorsPlugin(), // /ampedandwired/html-webpack-plugin // 模块HtmlWebpackPlugin new HtmlWebpackPlugin({ filename: '', //⽣成的⽂件的名称 template: '', //可以指定模块html⽂件 inject: true //打包后js⽂件放在body的最后 }), // copy custom static assets // 将static的内容拷贝到开发路径,忽略这个⽂件夹下“.XX”的⽂件 // 模块CopyWebpackPlugin 将单个⽂件或整个⽂件复制到构建⽬录 new CopyWebpackPlugin([ { from: e(__dirname, '../static'), to: SubDirectory, ignore: ['.*'] } ]) ]})// webpack将运⾏由配置⽂件导出的函数,并且等待promise返回,便于需要异步地加载所需的配置变量。s = new Promise((resolve, reject) => { rt = || t((err, port) => { if (err) { reject(err) } else { // publish the new Port, necessary for e2e tests = port // add port to devServer config // webpack 使⽤⽂件系统(file system)获取⽂件改动的通知。在某些情况下,不会正常⼯作。例如,当使⽤ Network File System (NFS) 时。Vagrant 也有很多问题。 = port // Add FriendlyErrorsPlugin (new FriendlyErrorsPlugin({ // 出错友好处理插件 compilationSuccessInfo: { // build成功的话会执⾏者块 messages: [`Your application is running here: ${}:${port}`], }, onErrors: OnErrors // 如果出错就执⾏这块,其实是utils⾥⾯配置好的提⽰信息 NotifierCallback() : undefined })) resolve(devWebpackConfig) } })})'use strict'const path = require('path')// utils⼯具配置⽂件,主要⽤来处理css类⽂件的loaderconst utils = require('./utils')const webpack = require('webpack')// config⽬录下的配置⽂件,主要⽤来定义了⽣产和开发环境的相关基础配置const config = require('../config')// 下⾯是webpack的merger插件,主要⽤来处理配置对象合并的,可以将⼀个⼤的配置对象拆分成⼏个⼩的,合并,相同的项将覆盖const merge = require('webpack-merge')const baseWebpackConfig = require('./')// copy-webpack-plugin使⽤来复制⽂件或者⽂件夹到指定的⽬录的const CopyWebpackPlugin = require('copy-webpack-plugin')// html-webpack-plugin是⽣成html⽂件,可以设置模板const HtmlWebpackPlugin = require('html-webpack-plugin')// extract-text-webpack-plugin这个插件是⽤来将bundle中的css等⽂件产出单独的bundle⽂件的const ExtractTextPlugin = require('extract-text-webpack-plugin')// 详情见(1)const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')// 压缩js 的插件const UglifyJsPlugin = require('uglifyjs-webpack-plugin')const env = require('../config/')// 把当前的配置对象和基础的配置对象合并const webpackConfig = merge(baseWebpackConfig, { module: { // 下⾯就是把utils配置好的处理各种css类型的配置拿过来,和dev设置⼀样,就是这⾥多了个extract: true,此项是⾃定义项,设置为true表⽰,⽣成独⽴的⽂件 rules: oaders({ sourceMap: tionSourceMap, extract: true, usePostCSS: true }) }, // devtool开发⼯具,⽤来⽣成个sourcemap⽅便调试 // 按理说这⾥不⽤⽣成sourcemap多次⼀举,这⾥⽣成了source-map类型的map⽂件,只⽤于⽣产环境 devtool: tionSourceMap ? l : false, output: { // 打包后的⽂件放在dist⽬录⾥⾯ path: Root, // ⽂件名称使⽤ static/js/[name].[chunkhash].js, 其中name就是main,chunkhash就是模块的hash值,⽤于浏览器缓存的 filename: Path('js/[name].[chunkhash].js'), // chunkFilename是⾮⼊⼝模块⽂件,也就是说filename⽂件中引⽤了chunckFilename chunkFilename: Path('js/[id].[chunkhash].js') },// optimize-css-assets-webpack-plugin插件的作⽤是压缩css代码的,还能去掉extract-text-webpack-plugin插件抽离⽂件产⽣的重复代码,因为同⼀个css可能在多个 }, plugins: [ // /vue-loader/en/workflow/ // 下⾯是利⽤DefinePlugin插件,定义环境变量为env new Plugin({ '': env }), // UglifyJsPlugin插件是专门⽤来压缩js⽂件的 new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false // 禁⽌压缩时候的警告信息,给⽤户⼀种vue⾼⼤上没有错误的感觉 } }, // 压缩后⽣成map⽂件 sourceMap: tionSourceMap, parallel: true }), // extract css into its own file new ExtractTextPlugin({ // ⽣成独⽴的css⽂件,下⾯是⽣成独⽴css⽂件的名称 filename: Path('css/[name].[contenthash].css'), // Setting the following option to `false` will not extract CSS from codesplit chunks. // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,

// increasing file size: /vuejs-templates/webpack/issues/1110 allChunks: true, }), // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different components can be deduped. // 压缩css new OptimizeCSSPlugin({ cssProcessorOptions: tionSourceMap { safe: true, map: { inline: false } } : { safe: true } }), // generate dist with correct asset hash for caching. // you can customize output by editing / // see /ampedandwired/html-webpack-plugin // 在dist⽬录⽣成html⽂件 new HtmlWebpackPlugin({ filename: , template: '', // 将js⽂件放到body标签的结尾 inject: true, minify: { // 压缩产出后的html页⾯ removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true // more options: // /kangax/html-minifier#options-quick-reference }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin // 分类要插到html页⾯的模块 chunksSortMode: 'dependency' }), // keep stable when vendor modules does not change // 该插件会根据模块的相对路径⽣成⼀个四位数的hash作为模块id, 建议⽤于⽣产环境 new ModuleIdsPlugin(), // enable scope hoisting new ConcatenationPlugin(), // split vendor js into its own file // 将第三⽅的包分离出来 new sChunkPlugin({ // 去 webpack 打包时的⼀个取舍是将 bundle 中各个模块单独打包成闭包。这些打包函数使你的 JavaScript 在浏览器中处理的更慢。相⽐之下,⼀些⼯具像 Closur new sChunkPlugin({ // common 模块的名称 name: 'vendor', minChunks (module) { // any required modules inside node_modules are extracted to vendor // 将所有依赖于node_modules下⾯⽂件打包到vendor中 return ( ce && /.js$/.test(ce) && f( (__dirname, '../node_modules') ) === 0 ) } }), // extract webpack runtime and module manifest to its own file in order to // prevent vendor hash from being updated whenever app bundle is updated // 为了避免每次更改项⽬代码时导致venderchunk的chunkHash改变,我们还会单独⽣成⼀个manifestchunk new sChunkPlugin({ name: 'manifest', minChunks: Infinity }), // This instance extracts shared chunks from code splitted chunks and bundles them // in a separate chunk, similar to the vendor chunk // see: /plugins/commons-chunk-plugin/#extra-async-commons-chunk // 主要逻辑的js⽂件 new sChunkPlugin({ name: 'app', async: 'vendor-async', children: true, minChunks: 3 }), // copy custom static assets // 拷贝资源 new CopyWebpackPlugin([ { from: e(__dirname, '../static'), to: SubDirectory, ignore: ['.*'] } ]) ]})// 开启Gzi压缩打包后的⽂件if (tionGzip) { const CompressionWebpackPlugin = require('compression-webpack-plugin') ( new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp( // 这⾥是把js和css⽂件压缩 '.(' + ('|') + ')$' ), threshold: 10240, minRatio: 0.8 }) )}if (AnalyzerReport) { // 打包编译后的⽂件打印出详细的⽂件信息,vue-cli默认把这个禁⽤了,个⼈觉得还是有点⽤的,可以⾃⾏配置 // 打包编译后的⽂件打印出详细的⽂件信息,vue-cli默认把这个禁⽤了,个⼈觉得还是有点⽤的,可以⾃⾏配置 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin (new BundleAnalyzerPlugin())}s = webpackConfig注释1// optimize-css-assets-webpack-plugin插件// 在⽣产环境中使⽤extract-text-webpack-plugin,最好也使⽤这个插件// 使⽤⽅法如下// 安装 npm install --save-dev optimize-css-assets-webpack-plugin// 还要安装 cssnano 这是⼀个css编译器 npm install --save-dev cssnano 这个vue-cli脚⼿架并没有使⽤cssnanonew OptimizeCssAssetsPlugin({ assetNameRegExp: /.$/g, // 不写默认是/.css$/g cssProcessor: require('cssnano'), // 编译器选项,不写默认是cssnano,所以使⽤这个插件不管怎样都要cssnano cssProcessorOptions: { discardComments: {removeAll: true } }, // 传递给编译器的参数 canPrint: true // 是否能够输出信息})

2023年6月21日发(作者:)

vue-vue-cli2脚⼿架搭建build⽂件夹详解构建环境下的配置:  loading动画  删除创建⽬标⽂件夹  webpack编译;输出信息//这是vue-cli脚⼿架⼯具的⽣产环境配置⼊⼝ 中的"build": "node build/"的直接指向。// js的严格模式'use strict'

//检查node+npm的版本,引⽤./⽂件require('./check-versions')()//设置环境变量为⽣产环境_ENV = 'production'//导⼊ora模块 实现loading效果,实际是⼀个命令⾏转圈圈动画插件,好看⽤的const ora = require('ora')//导⼊rimraf模块 以包的形式包装rm -rf命令,⽤来删除⽂件和⽂件夹的,不管⽂件是否为空//rimraf插件是⽤来执⾏UNIX命令rm和-rf的⽤来删除⽂件夹和⽂件,清空旧的⽂件const rm = require('rimraf')//导⼊node的path模块,路径模块 连接路径,例⼦:('/foo', 'bar', 'baz/asdf', 'quux', '..');const path = require('path')//导⼊chalk模块 ⽤来改变⽂字颜⾊const chalk = require('chalk')//导⼊webpack模块使⽤内置插件和webpack⽅法const webpack = require('webpack')//导⼊config/,commonJs风格,引⼊⽂件模块,引⼊模块分为内置模块与⽂件模块两种const config = require('../config')//导⼊nst webpackConfig = require('./')//实现loading的模块const spinner = ora('building ')//开始动画()/* rm⽅法删除dist/static⽂件夹 是将路径⽚段以''连接成新的路径,任何⼀个路径⽚段有错误就会报错 调⽤rm⽅法,第⼀个参数的结果就是 绝对/⼯程名/dist/static,表⽰删除这个路径下⾯的所有⽂件 若删除中有错误则抛出异常并终⽌程序 若没有错误则继续执⾏,构建webpack 结束动画 若有异常则抛出 标准输出流,类似于*/rm((Root, SubDirectory), err => { //如果删除的过程中出现错误,就抛出这个错误,同时程序终⽌ if (err) throw err //没有错误,就执⾏webpack编译 构建webpack webpack(webpackConfig, (err, stats) => { //停⽌动画 () if (err) throw err //如果有错误就抛出错误 //是标准输出,相当于 (ng({ //stats对象中保存着编译过程中的各种消息 colors: true, // 增加控制台颜⾊开关 colors: true, // 增加控制台颜⾊开关 modules: false, // 是否增加内置模块信息 children: false, // 不增加⼦级信息 chunks: false, // 允许较少的输出 chunkModules: false // 不将内置模块信息加到包信息 }) + 'nn') // 编译过程持续打印 // 编译出错的信息 if (ors()) { ((' Build failed with errors.n')) //执⾏失败 (1) } //以上就是在编译过程中,持续打印消息 // 编译成功的信息,并退出 ((' Build complete.n')) (( ' Tip: built files are meant to be served over an HTTP server.n' + ' Opening over file:// won't work.n' )) })})和npm的版本检查// js的严格模式'use strict'// 导⼊chalk模块 ⽤来改变⽂字颜⾊const chalk = require('chalk')// 控制版本const semver = require('semver')// 获取版本,commonJs风格,引⼊⽂件模块,引⼊模块分为内置模块与⽂件模块两种const packageConfig = require('../')// 插件,执⾏unix系统命令const shell = require('shelljs')function exec (cmd) { // 脚本可以通过child_process模块新建⼦进程,从⽽执⾏Unix系统命令 // 将cmd参数传递的值转换成前后没有空格的字符串,也就是版本号 // require('child_process')调⽤nodejs⼦进程, // execSync同步的exec⽅法执⾏command return require('child_process').execSync(cmd).toString().trim()}//声明常量数组,数组内容为有关node相关信息的对象const versionRequirements = [ { //对象名称为node name: 'node', //使⽤semver插件,把版本信息转换成规定格式 currentVersion: (n), //规定中engines选项的node版本信息 versionRequirement: }]//which为linux指令,在$path规定的路径下查找符合条件的⽂件//('npm')就是寻找npm命令if (('npm')) { //将npm添加到versionRequirements

({ name: 'npm', 调⽤npm --version命令,并且把参数返回给exec函数获取纯净版本 调⽤npm --version命令,并且把参数返回给exec函数获取纯净版本 //exec()⽅法就是执⾏⼀个命令(在这⾥是执⾏npm --version),返回版本信息的函数。 currentVersion: exec('npm --version'), //规定中engines选项的npm版本信息 versionRequirement: })}s = function () { const warnings = [] for (let i = 0; i < ; i++) { const mod = versionRequirements[i] // 如果版本号不符合⽂件中指定的版本号,就执⾏... // 当前版本号⽤红⾊标识,要求版本号⽤绿⾊标识,当前版本不符合要求版本那么就将提⽰信息添加到wranings if (!ies(tVersion, nRequirement)) { ( + ': ' + (tVersion) + ' should be ' + (nRequirement) // ⼤致意思就是 把当前版本号⽤红⾊字体 符合要求的版本号⽤绿⾊字体 给⽤户提⽰具体合适的版本 ) } } //如果为真,则打印提⽰⽤户升级新版本 if () { ('') (('To use this template, you must update following to modules:')) () for (let i = 0; i < ; i++) { const warning = warnings[i] (' ' + warning) } //执⾏失败 (1) }}配置静态资源路径;⽣成cssLoaders⽤于加载.vue⽂件中的样式;⽣成styleLoaders⽤于加载不在.vue⽂件中的单独存在的样式⽂件'use strict'// 引⼊nodejs路径模块const path = require('path')// 引⼊config下的⽂件const config = require('../config')// ⼀个插件,抽离css样式,防⽌将样式打包在js中引起样式加载错乱// 引⼊extract-text-webpack-plugin插件,⽤来将css提取到单独的css⽂件中// 详情请看(1)const ExtractTextPlugin = require('extract-text-webpack-plugin')

const packageConfig = require('../')// exports其实就是⼀个对象,⽤来导出⽅法的,最终还是使⽤s,此处导出Path = function (_path) { // 如果是⽣产环境assetsSubDirectory就是'static',否则还是'static' const assetsSubDirectory = _ENV === 'production' SubDirectory : SubDirectory // 返回绝对路径(在电脑上的实际位置);返回相对路径 return (assetsSubDirectory, _path)

// 此⽅法返回⼀个⼲净的相对根路径

}// 下⾯是导出cssLoaders的相关配置ders = function (options) { options = options || {}

// cssLoader的基本配置 const cssLoader = { loader: 'css-loader', // options是⽤来传递参数给loader的 options: { // minimize表⽰压缩,如果是⽣产环境就压缩css代码,这⾥全部压缩 // minimize: _ENV === 'production', // 是否开启cssmap,默认是false sourceMap: Map } }

// 为css⾃动⽣成兼容性前缀 const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: Map } }

// 适配移动端屏幕⾃适应像素兼容性75px==1rem,这⾥没有⽤到 // const px2remLoader = { // loader: 'px2rem-loader', // options: { // remUnit: 75 // } // } // generate loader string to be used with extract text plugin function generateLoaders (loader, loaderOptions) { // 将上⾯的基础cssLoader配置、兼容性前缀配置、⾃适应配置放在⼀个数组⾥⾯ // const loaders = tCSS ? [cssLoader, postcssLoader, px2remLoader] : [cssLoader, px2remLoader] const loaders = tCSS ? [cssLoader, postcssLoader] : [cssLoader] // 如果该函数传递了单独的loader就加到这个loaders数组⾥⾯,这个loader可能是less,sass之类的 if (loader) { ({ // 加载对应的loader loader: loader + '-loader', // 是es6的⽅法,主要⽤来合并对象的,浅拷贝 options: ({}, loaderOptions, { sourceMap: Map }) }) } // Extract CSS when that option is specified // (which is the case during production build) // 注意这个extract是⾃定义的属性,可以定义在options⾥⾯,主要作⽤就是当配置为true就把⽂件单独提取, // false表⽰不单独提取,这个可以在使⽤的时候单独配置 if (t) { return t({ use: loaders, fallback: 'vue-style-loader' }) } else { return ['vue-style-loader'].concat(loaders) } // 上⾯这段代码就是⽤来返回最终读取和导⼊loader,来处理对应类型的⽂件 } // options如果不为null或者undefined,0,""等等就原样,否则就是{}。在js⾥⾯,||运算符,A||B,A如果为真,直接返回A。如果为假,直接返回B(不会判断B是什么 } // /en/configurations/ return { // css对应 vue-style-loader 和 css-loader css: generateLoaders(), // postcss对应 vue-style-loader 和 css-loader postcss: generateLoaders(), // less对应 vue-style-loader 和 less-loader less: generateLoaders('less'), // sass对应 vue-style-loader 和 sass-loader sass: generateLoaders('sass', { indentedSyntax: true }), // scss对应 vue-style-loader 和 sass-loader scss: generateLoaders('sass'), // stylus对应 vue-style-loader 和 stylus-loader stylus: generateLoaders('stylus'), // styl对应 vue-style-loader 和 styl-loader styl: generateLoaders('stylus') }}// Generate loaders for standalone style files (outside of .vue)// 下⾯这个主要处理import这种⽅式导⼊的⽂件类型的打包,上⾯的ders是为这⼀步服务的oaders = function (options) { const output = [] // 下⾯就是⽣成的各种css⽂件的loader对象 const loaders = ders(options) for (const extension in loaders) { // 把每⼀种⽂件的laoder都提取出来 const loader = loaders[extension] ({ // 把最终的结果都push到output数组中,⼤事搞定 test: new RegExp('.' + extension + '$'), use: loader }) } return output}NotifierCallback = () => { // 发送桌⾯消息 const notifier = require('node-notifier') return (severity, errors) => { if (severity !== 'error') return const error = errors[0] const filename = && ('!').pop() ({ title: , message: severity + ': ' + , subtitle: filename || '', icon: (__dirname, '') }) }}注释1// extract-text-webpack-plugin插件是⽤来将⽂本从bundle中提取到⼀个单独的⽂件中// 基本使⽤⽅法如下const ExtractTextPlugin = require("extract-text-webpack-plugin");s = { module: { rules: [ { test: /.css$/, //主要⽤来处理css⽂件 use: t({ fallback: "style-loader", // fallback表⽰如果css⽂件没有成功导⼊就使⽤style-loader导⼊ use: "css-loader" // 表⽰使⽤css-loader从js读取css⽂件 }) } ], plugins: [ new ExtractTextPlugin("") //表⽰⽣成⽂件 ] }}处理.vue⽂件的配置⽂件'use strict'const utils = require('./utils')const config = require('../config')// 是否为⽣产环境const isProduction = _ENV === 'production'// 根据环境来获取相应的productionSourceMap或者cssSourceMapconst sourceMapEnabled = isProduction tionSourceMap : rceMap// 导出s = { // 载⼊utils中的cssloaders返回配置好的css-loader和vue-style=loader loaders: ders({ // 是否开始sourceMap ⽤来调试 sourceMap: sourceMapEnabled, // 是否将单独的css⽂件(⼀般为引⼊的外部⽂件)进⾏提取单独打包 extract: isProduction }), // 记录压缩的代码,⽤来找到源码位置 cssSourceMap: sourceMapEnabled, // 是否缓存破坏 cacheBusting: usting, // transformToRequire的作⽤是在模块编译的过程中,编译器可以将某些属性,⽐如src转换为require调⽤ transformToRequire: { video: ['src', 'poster'], source: 'src', img: 'src', image: 'xlink:href' }}基本的webpack配置  配置webpack编译⼊⼝  配置webpack输出路径和命名规则  配置模块resolve规则  配置不同类型模块的处理规则'use strict'// 引⼊node path 中间件 可以获取到 path 路径的⼀些信息const path = require('path')// 引⼊utils⼯具模块 utils主要⽤来处理css-loader和vue-style-loader的const utils = require('./utils')// 引⼊config下⾯的index⽂件 主要是配置⼀些开发环境和⽣产环境的配置const config = require('../config')// ⽤来解决各种css ⽂件 sass less stulys 等const vueLoaderConfig = require('./')// 定义了⼀个路径函数 返回当前的⽬录的平⾏⽬录下的dir 因为有'..'也就是获取绝对路径,⽅便对import时引⼊地址的⽅便填写function resolve(dir) { return (__dirname, '..', dir)}// eslint 的检测规则const createLintingRule = () => ({ // 对js和vue ⽂件进⾏eslint 检查 test: /.(js|vue)$/, // 使⽤eslint-loader loader: 'eslint-loader', // enforce执⾏的意思 有两个值 pre post // pre是在其他规则执⾏之前执⾏ post是在其他规则执⾏之后执⾏ enforce: 'pre', // 进⾏检测的⽂件⽬录包括哪些 调⽤了路径函数 include: [resolve('src'), resolve('test')], options: { // 使⽤第三⽅的插件进⾏eslint 检测 formatter: require('eslint-friendly-formatter'), // 是否输出eslint报错信息 emitWarning: !lintErrorsInOverlay }})// webpack的配置,可以理解成是开发环境和正式环境的⼀些公共配置s = { // webpack 解析时根⽬录地址如果此⽂件在跟⽬录这句话就不⽤写 context: e(__dirname, '../'), // 项⽬的⼊⼝⽂件 entry: { app: './src/' }, // 项⽬出⼝⽂件配置 output: { // 项⽬buid的出⼝⽂件的⽬录地址,这⾥指的是(../dist⽂件⽬录) 引⼊的是 下⾯的配置 path: Root, // ⽂件的名字 filename: '[name].js', // 输出解析⽂件的⽬录,url 相对于 HTML 页⾯(⽣成的html⽂件中,css和js等静态⽂件的url前缀) publicPath: _ENV === 'production' PublicPath : PublicPath }, resolve: { // 指定哪些⽂件在引⽤时可以省略后缀名 extensions: ['.js', '.vue', '.json'], // 别名,在引⽤⽂件时 使⽤别名代理真实⽬录 后⾯再在⽬录时以别名代替 alias: { alias: { 'vue$': 'vue/dist/', '@': resolve('src'), } }, module: { // 转换解析规则 // 是⽤来解析所有此后缀名的⽂件, // 我们⽤什么npm什么形式的loader去解析 // e是代表我们解析的⽂件只包含那些东西 // s解析⽂件参数设置 具体看下⾯的解释 rules: [ ...(int ? [createLintingRule()] : []), { test: /.vue$/, loader: 'vue-loader', // 对vue的css进⾏解析 options: vueLoaderConfig }, { // 对js⽂件使⽤babel-loader进⾏解析 主要是解析es6 test: /.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] }, { // 对图⽚使⽤url-loader解析 这个插件的作⽤是将⼀个⾜够⼩的⽂件⽣成⼀个64位的DataURL // 当limit⼩于10000进⾏将图⽚⽣成base64 // name 指的是引⼊的utils⾥⾯的⼀个⽅法 将name ,7位哈希 .ext 代表后缀名 // 传⼊⽅法 返回结果是 /static/img/[name].[hash:7].[ext] test: /.(png|jpe?g|gif|svg)(?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: Path('img/[name].[hash:7].[ext]') } }, { // 对⼀些⾳频⽂件进⾏解析 test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: Path('media/[name].[hash:7].[ext]') } }, { // 对字体⽂件进⾏解析 test: /.(woff2?|eot|ttf|otf)(?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: Path('fonts/[name].[hash:7].[ext]') } } ] }, node: { // prevent webpack from injecting useless setImmediate polyfill because Vue // source contains it (although only uses it if it's native). setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client // 是否 polyfill 或 mock // 源包含它(虽然仅在本地使⽤) // 预防webpack从注⼊模拟节点到node原⽣模块 // 预防webpack从注⼊模拟节点到node原⽣模块 dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' }, // webpack不处理下⾯的库,压缩包的⼤⼩,但是依然可以引⽤ externals: { 'AMap': 'AMap', }}'use strict'// 引⼊当前⽬录下的⽂件模块const utils = require('./utils')const webpack = require('webpack')const config = require('../config')// 进⾏合并对象,相同项⽬会进⾏覆盖const merge = require('webpack-merge')const path = require('path')const baseWebpackConfig = require('./')/ ⼀个拷贝资源的插件const CopyWebpackPlugin = require('copy-webpack-plugin')// ⽣成html⽂件const HtmlWebpackPlugin = require('html-webpack-plugin')// 下⾯这个插件是⽤来把webpack的错误和⽇志收集起来,漂亮的展⽰给⽤户const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')// ⼀个⾃动打开可⽤端⼝的包const portfinder = require('portfinder')// 当前环境的hostconst HOST = // //当前环境的portconst PORT = && Number()// 开发环境的配置const devWebpackConfig = merge(baseWebpackConfig, { module: { // loader的配置,创建模块时匹配请求的规则数组,这⾥调⽤了utils中的配置模板styleLoaders rules: oaders({ sourceMap: rceMap, usePostCSS: true }) }, // cheap-module-eval-source-map is faster for development // //debtool是开发⼯具选项,⽤来指定如何⽣成sourcemap⽂件,cheap-module-eval-source-map此款soucemap⽂件性价⽐最⾼ devtool: l, // these devServer options should be customized in /config/ // webpack服务器配置 devServer: { // 重新加载server时,控制台对⼀些错误以warning的⽅式提⽰ clientLogLevel: 'warning', // 当使⽤ HTML5 History API 时,任意的 404 响应都可能需要被替代为 historyApiFallback: { rewrites: [ { from: /.*/, to: (PublicPath, '') }, ], }, // 是否启⽤webpack的模块热替换特性。这个功能主要是⽤于开发过程中,对⽣产环境⽆帮助。效果上就是界⾯⽆刷新更新。 hot: true, // 告诉服务器从哪⾥提供内容。只有在你想要提供静态⽂件时才需要,这⾥我们禁⽤ contentBase: false, // since we use CopyWebpackPlugin. // ⼀切服务都启⽤gzip压缩 compress: true, // 指定⼀个host,默认是localhost。如果有全局host就⽤全局,否则就⽤中的设置。 host: HOST || , // 指定端⼝ port: PORT || , // 是否在浏览器开启本dev server,是否⾃动打开浏览器 open: enBrowser, // 当有编译器错误时,是否在浏览器中显⽰全屏覆盖。 overlay: verlay { warnings: false, errors: true } : false, // 静态内容的路径,此路径下的打包⽂件可在浏览器中访问 publicPath: PublicPath, // 如果你有单独的后端开发服务器api,并且希望在同域名下发送api请求,那么代理某些URL会很有⽤。 // 接⼝代理 proxy: able, // 启⽤ quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来⾃ webpack 的错误或警告在控制台不可见 quiet: true, // necessary for FriendlyErrorsPlugin // 监视⽂件的选项 watchOptions: { poll: , //是否使⽤轮询 } }, plugins: [ // DefinePlugin 允许创建⼀个在编译时可以配置的全局常量。这⾥⽣成了⼀个当前环境的常量 new Plugin({ '': require('../config/') }), // 模块热替换插件,修改模块时不需要刷新页⾯ new uleReplacementPlugin(), // 当开启 HMR 的时候使⽤该插件会显⽰模块的相对路径 new odulesPlugin(), // HMR shows correct file names in console on update. // 在编译出现错误时,使⽤ NoEmitOnErrorsPlugin 来跳过输出阶段。这样可以确保输出资源不会包含错误。 new OnErrorsPlugin(), // /ampedandwired/html-webpack-plugin // 模块HtmlWebpackPlugin new HtmlWebpackPlugin({ filename: '', //⽣成的⽂件的名称 template: '', //可以指定模块html⽂件 inject: true //打包后js⽂件放在body的最后 }), // copy custom static assets // 将static的内容拷贝到开发路径,忽略这个⽂件夹下“.XX”的⽂件 // 模块CopyWebpackPlugin 将单个⽂件或整个⽂件复制到构建⽬录 new CopyWebpackPlugin([ { from: e(__dirname, '../static'), to: SubDirectory, ignore: ['.*'] } ]) ]})// webpack将运⾏由配置⽂件导出的函数,并且等待promise返回,便于需要异步地加载所需的配置变量。s = new Promise((resolve, reject) => { rt = || t((err, port) => { if (err) { reject(err) } else { // publish the new Port, necessary for e2e tests = port // add port to devServer config // webpack 使⽤⽂件系统(file system)获取⽂件改动的通知。在某些情况下,不会正常⼯作。例如,当使⽤ Network File System (NFS) 时。Vagrant 也有很多问题。 = port // Add FriendlyErrorsPlugin (new FriendlyErrorsPlugin({ // 出错友好处理插件 compilationSuccessInfo: { // build成功的话会执⾏者块 messages: [`Your application is running here: ${}:${port}`], }, onErrors: OnErrors // 如果出错就执⾏这块,其实是utils⾥⾯配置好的提⽰信息 NotifierCallback() : undefined })) resolve(devWebpackConfig) } })})'use strict'const path = require('path')// utils⼯具配置⽂件,主要⽤来处理css类⽂件的loaderconst utils = require('./utils')const webpack = require('webpack')// config⽬录下的配置⽂件,主要⽤来定义了⽣产和开发环境的相关基础配置const config = require('../config')// 下⾯是webpack的merger插件,主要⽤来处理配置对象合并的,可以将⼀个⼤的配置对象拆分成⼏个⼩的,合并,相同的项将覆盖const merge = require('webpack-merge')const baseWebpackConfig = require('./')// copy-webpack-plugin使⽤来复制⽂件或者⽂件夹到指定的⽬录的const CopyWebpackPlugin = require('copy-webpack-plugin')// html-webpack-plugin是⽣成html⽂件,可以设置模板const HtmlWebpackPlugin = require('html-webpack-plugin')// extract-text-webpack-plugin这个插件是⽤来将bundle中的css等⽂件产出单独的bundle⽂件的const ExtractTextPlugin = require('extract-text-webpack-plugin')// 详情见(1)const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')// 压缩js 的插件const UglifyJsPlugin = require('uglifyjs-webpack-plugin')const env = require('../config/')// 把当前的配置对象和基础的配置对象合并const webpackConfig = merge(baseWebpackConfig, { module: { // 下⾯就是把utils配置好的处理各种css类型的配置拿过来,和dev设置⼀样,就是这⾥多了个extract: true,此项是⾃定义项,设置为true表⽰,⽣成独⽴的⽂件 rules: oaders({ sourceMap: tionSourceMap, extract: true, usePostCSS: true }) }, // devtool开发⼯具,⽤来⽣成个sourcemap⽅便调试 // 按理说这⾥不⽤⽣成sourcemap多次⼀举,这⾥⽣成了source-map类型的map⽂件,只⽤于⽣产环境 devtool: tionSourceMap ? l : false, output: { // 打包后的⽂件放在dist⽬录⾥⾯ path: Root, // ⽂件名称使⽤ static/js/[name].[chunkhash].js, 其中name就是main,chunkhash就是模块的hash值,⽤于浏览器缓存的 filename: Path('js/[name].[chunkhash].js'), // chunkFilename是⾮⼊⼝模块⽂件,也就是说filename⽂件中引⽤了chunckFilename chunkFilename: Path('js/[id].[chunkhash].js') },// optimize-css-assets-webpack-plugin插件的作⽤是压缩css代码的,还能去掉extract-text-webpack-plugin插件抽离⽂件产⽣的重复代码,因为同⼀个css可能在多个 }, plugins: [ // /vue-loader/en/workflow/ // 下⾯是利⽤DefinePlugin插件,定义环境变量为env new Plugin({ '': env }), // UglifyJsPlugin插件是专门⽤来压缩js⽂件的 new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false // 禁⽌压缩时候的警告信息,给⽤户⼀种vue⾼⼤上没有错误的感觉 } }, // 压缩后⽣成map⽂件 sourceMap: tionSourceMap, parallel: true }), // extract css into its own file new ExtractTextPlugin({ // ⽣成独⽴的css⽂件,下⾯是⽣成独⽴css⽂件的名称 filename: Path('css/[name].[contenthash].css'), // Setting the following option to `false` will not extract CSS from codesplit chunks. // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,

// increasing file size: /vuejs-templates/webpack/issues/1110 allChunks: true, }), // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different components can be deduped. // 压缩css new OptimizeCSSPlugin({ cssProcessorOptions: tionSourceMap { safe: true, map: { inline: false } } : { safe: true } }), // generate dist with correct asset hash for caching. // you can customize output by editing / // see /ampedandwired/html-webpack-plugin // 在dist⽬录⽣成html⽂件 new HtmlWebpackPlugin({ filename: , template: '', // 将js⽂件放到body标签的结尾 inject: true, minify: { // 压缩产出后的html页⾯ removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true // more options: // /kangax/html-minifier#options-quick-reference }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin // 分类要插到html页⾯的模块 chunksSortMode: 'dependency' }), // keep stable when vendor modules does not change // 该插件会根据模块的相对路径⽣成⼀个四位数的hash作为模块id, 建议⽤于⽣产环境 new ModuleIdsPlugin(), // enable scope hoisting new ConcatenationPlugin(), // split vendor js into its own file // 将第三⽅的包分离出来 new sChunkPlugin({ // 去 webpack 打包时的⼀个取舍是将 bundle 中各个模块单独打包成闭包。这些打包函数使你的 JavaScript 在浏览器中处理的更慢。相⽐之下,⼀些⼯具像 Closur new sChunkPlugin({ // common 模块的名称 name: 'vendor', minChunks (module) { // any required modules inside node_modules are extracted to vendor // 将所有依赖于node_modules下⾯⽂件打包到vendor中 return ( ce && /.js$/.test(ce) && f( (__dirname, '../node_modules') ) === 0 ) } }), // extract webpack runtime and module manifest to its own file in order to // prevent vendor hash from being updated whenever app bundle is updated // 为了避免每次更改项⽬代码时导致venderchunk的chunkHash改变,我们还会单独⽣成⼀个manifestchunk new sChunkPlugin({ name: 'manifest', minChunks: Infinity }), // This instance extracts shared chunks from code splitted chunks and bundles them // in a separate chunk, similar to the vendor chunk // see: /plugins/commons-chunk-plugin/#extra-async-commons-chunk // 主要逻辑的js⽂件 new sChunkPlugin({ name: 'app', async: 'vendor-async', children: true, minChunks: 3 }), // copy custom static assets // 拷贝资源 new CopyWebpackPlugin([ { from: e(__dirname, '../static'), to: SubDirectory, ignore: ['.*'] } ]) ]})// 开启Gzi压缩打包后的⽂件if (tionGzip) { const CompressionWebpackPlugin = require('compression-webpack-plugin') ( new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp( // 这⾥是把js和css⽂件压缩 '.(' + ('|') + ')$' ), threshold: 10240, minRatio: 0.8 }) )}if (AnalyzerReport) { // 打包编译后的⽂件打印出详细的⽂件信息,vue-cli默认把这个禁⽤了,个⼈觉得还是有点⽤的,可以⾃⾏配置 // 打包编译后的⽂件打印出详细的⽂件信息,vue-cli默认把这个禁⽤了,个⼈觉得还是有点⽤的,可以⾃⾏配置 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin (new BundleAnalyzerPlugin())}s = webpackConfig注释1// optimize-css-assets-webpack-plugin插件// 在⽣产环境中使⽤extract-text-webpack-plugin,最好也使⽤这个插件// 使⽤⽅法如下// 安装 npm install --save-dev optimize-css-assets-webpack-plugin// 还要安装 cssnano 这是⼀个css编译器 npm install --save-dev cssnano 这个vue-cli脚⼿架并没有使⽤cssnanonew OptimizeCssAssetsPlugin({ assetNameRegExp: /.$/g, // 不写默认是/.css$/g cssProcessor: require('cssnano'), // 编译器选项,不写默认是cssnano,所以使⽤这个插件不管怎样都要cssnano cssProcessorOptions: { discardComments: {removeAll: true } }, // 传递给编译器的参数 canPrint: true // 是否能够输出信息})