webpack基础配置(多页面应用)

webpack基础配置

第一次自己写webpack的配置,记录下使用过的配置的作用和遇到的问题。因为是按照自己多页面应用的配置来说的,所以和vue、react的配置有些不同,如果有错误,欢迎大家指出。也是第一次写博客,写的不好见笑,233
源码在这里~

entry

webpack打包的入口,webpack执行构建的第一步是从入口开始,查找并递归解析出所有入口依赖的模块(js/hmtl/css等文件)

  1. 这里配置是必须的,没有填写会报错;
  2. 可以配置单文件入口,也可以配置多文件入口;
  3. entry类型
//string
module.exports = {
 entry: './app/main.js'
}
//array
module.exports = {
 entry:['./app/entry1.js','./app/entry2.js']
}
//object
module.exports = {
 entry:{
  index:'./app/js/index.js',
  index2:'./app/js/index2.js'
 }
}

感觉string类型表示本项目既单文件入口(vue、react项目),object类型是多文件入口项目(即使普通的html、css项目,不使用vue、react等框架也可以用webpack来打包)哈哈哈

output

output配置如何输出最终想要的代码,既打包输出之后的文件是怎么样的,包括目录结构、文件名称

  1. filename 配置输出的文件的名称,string类型
//如果只有一个输出文件,就可以写成一个固定的名字
module.exports = {
 output:{
  filename:'bundle.js'
 }
}
//但是在有多个chunk(模块)输出的时候,就不能写成固定的名称,需要借助模板和变量
//webpack会为每个chunk取一个名称,所以可以使用变量让webpack根据每个chunk原来的名称来给输出的文件命名
module.exports = {
 output:{
  filename:'[name].js'
 }
}
//还可以调整输出结果的目录结构
module.exports = {
 output:{
  filename:'js/[name].js'
 }
}
//加hash值
module.exports = {
 output:{
  filename:'js/[name].[chunkhash].js'
 }
}
//设置chunhash与hash值得长度,默认20位,以下设置成8位
module.exports = {
 output:{
  filename:'js/[name].[chunkhash:8].js'
 }
}

除了name变量还有其他变量

项目Value
idchunk的唯一标识,从0开始
hashchunk的唯一标识的hash值
chunkhashchunk内容的hash值
  1. chunkFilename 配置无入口的chunk在输出时的名称
    chunkFilename只用于指定在运行过程中生产的chunk在输出时的文件名称
    常见的场景:使用CommonChunkPlugin、使用import(‘path/to/module’)动态加载等
    chunkFilename的内置变量和filename一样
  2. path 配置输出文件存放在本地的目录,必须是string类型的绝对路径(非绝对路径webpack会报错),通常使用node.js提供的path模块获取绝对路径(path.join 和 path.resolve 的区别
const path = require('path')
module.exports = {
 output:{
  path:path.join(__dirname,'dist')
 }
}
//__dirname表示当前js文件所在的绝对路径

module

配置处理各种模块的规则

  1. rules 配置模块的读取规则和解析规则,通常用来配置loader。其类型是一个数组,数组的每项是一个对象
  • 条件匹配:同过test、include(只包含)、exclude(排除)三个配置来选中loader要应用规则的文件
  • 应用规则:对选中的文件通过use配置来应用loader,可以只用一个loader,或者按照从后往前的顺序应用一组loader,同时可以分别向loader传入参数
  • 重置顺序:laoder的顺序默认从右往左(从后往前),可以通过enforce来改变顺序,其值有pre、post(这个功能通常用不到)
 	//以下是自己用的多页面应用(既传统的html、css、js项目)loader规则,和vue、react项目的规则有些不同
module.exports = {
 module: {
  rules: [
   {
     test: /\.js$/,
     loader: 'babel-loader',
     //include表示直接去哪些文件夹下面找,可以加快速度
     include: [path.join(__dirname, '../src/js',)]
   },
   {
     test: /\.css$/,
     loader: 'style-loader!css-loader' 
   },
   {
     test: /\.html$/,
     loader: 'html-loader'
   },
  {
    test: /\.(png|jpg)$/,
    loader: 'url-loader?limit=4000&name=images/[name]-[hash:5].[ext]'
    /*limit:
    表示的是一个阀值,如果当前我们资源中的图片大于4kb就从.js中剥离出来,如果小于4kb打包进.js中
    name:打包出来的图片,放在那个文件夹下,用什么文件名称命名
    [name]代表你原始的文件名称
    [hash:5] 让浏览器支持图片的缓存
    [ext] 图片本身的拓展名
    */
   }
  ]   			
 }
}

resolve

webpack启动后会从入口模块出发找出所有依赖的模块,resolve配置webpack如何寻找模块对应的文件,webpack会采用模块化标准里约定的规则去寻找,但是我们可以通过resolve来配置自己的规则

  1. alias 配置通过别名来将原导入路径映射成一个新的路径(就是给原来可能较长的导入路径取一个简短的新路径名称)
//以下路径和文件名 都是传统的html、css、js项目使用的
//配置了alias之后,以后所有js文件需要导入rem.js时只需 import 'rem'
//而不是import '../src/common/js/rem.js'这一大段路径名(这是我项目的相对路径名)果然程序员都是懒人
module.exports = {
 resolve: {
  extensions: ['.js', '.json'],
  alias: {
   rem: path.join(__dirname, '../src/common/js/rem.js'),
   "reset.css": path.join(__dirname, '../src/common/css/reset.css'),
  }
 }
}
  1. extensions 当导入语句没有带文件后缀时,webpack会自动带上extensions里面的后缀去尝试访问文件是否存在,是一个数组。例如上面的配置,在使用import 'rem’导入语句时,webpack会先去找rem.js文件如果找不到就会去找rem.json文件。由于我同时配置了alias和extensions,在以后的导入语句是会简短很多。
    简单来说extensions可以让你的导入语句少些一个文件后缀,alias可以让你的导入语句不需要写一大段路径名

devServer

开发时配置项,里面的配置用来提高开发效率

  1. hot 热模块替换功能,值为boolean类型,当为true时会开启功能,页面在不需要手动刷新的情况下通过用新模块替换老模块来做到实时预览。ps:我使用的webpack是3.6.0版本,webpack-dev-serve是2.9.1版本,仅仅设置hot:true是不成功的会报错,需要同时在plugins配置项里配置热模块替换插件,这样的话就是说版本的差别会导致配置的不同
const webpack = require('webpack')
module.exports = {
 devServer: {
  hot:true,
  inline: true
 },
 plugins:[
  new webpack.HotModuleReplacementPlugin()
 ]
}
  1. inline devServer实时预览功能依赖一个注入页面里的代理客户端,去接收来自devServer的命令并负责刷新网页的工作。这个配置项就是用来配置是否将这个代理客户端自动注入将运行在页面的chunk里,既配合hot用来打热更新功能的,值为boolean类型。
  2. host 配置devServer服务监听的地址,通常设置为’loaclhost’,如果想让局域网中的其他设备也访问自己的本地服务,可以设置成’0.0.0.0’,也可以设置成本机域名,其他设备可以通过本机域名来访问,这个配置项当用来测试移动端时就很有用了,移动端网页也可以一起热更新、测试。
module.exports = {
 devServer: {
  //host:'locakhost' //通常
  host:'获取的本机ip地址' // 可以让同一域名下的其他设备访问
 }
}
  1. port 配置devServer服务监听的端口,通常使用8080端口,当然可以随便使用其他端口(需要注意使用的端口没有被占用),可以使用portfinder插件来让webpack自动检测设置的端口有无被占用,如果被占用portfinder插件会自动更换端口。portfinder用法地址
const portfinder = require('portfinder')//通过npm安装
const devWebpackConfig = {
 //...其他配置
 devServer: {
  port: 8080
 }
}
module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = 8080 //设置默认端口
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      devWebpackConfig.devServer.port = port
      resolve(devWebpackConfig)
    }
  })
})
  1. open 配置当devServer启动第一次构建完成时,是否自动使用当前系统默认浏览器打开要开发的网页。
  2. contentBase 配置http服务的根目录,默认情况下是当前执行目录,通常是项目根目录,一般情况不需要设置
const portfinder = require('portfinder')//通过npm安装
const devWebpackConfig = {
 //...其他配置
 devServer: {
  //以dist为开启服务时的根目录,既以otput配置的path文件为根目录
  contentBase:path.join(__dirname, '../dist')
 }
}
  1. proxy 配置网络请求的代理路径(proxy还有其他的配置,下面只是最简单的配置)
const devWebpackConfig = {
 //...其他配置
 devServer: {
  proxy: {
   '/': { // /表示所有请求都转发到设置的路径地址去
    target: 'https://xxx.xxx',
    changeOrigin: true,
   }
  }
 }
}

devtool

配置如何生成source map,默认值是false,想要构建的代码生成source map方便调试就需要设置cheap-module-eval-source-map,其实就是设置这个之后,能在浏览器的开发者工具栏的source选项里面看到源文件(js)

plugins

在webpack运行时需要用到的插件都写在这个数组里面,例如前面提到的热模块替换插件

const devWebpackConfig = {
 //...其他配置
 plugins:[
  new CleanWebpackPlugin(['dist'],{
   root: path.resolve(__dirname, '../'),
   //这是我的文件目录(dist文件在当前文件的上一级目录),可以根据自己目录设置
  }), // 生成环境用到的删除插件,用来每次打包时先删除原有的dist文件
  new webpack.HotModuleReplacementPlugin(),//热模块更新插件
  new UglifyJsPlugin({
   uglifyOptions: {
     compress: {
      warnings: false,
      drop_console: true // 去除console.log日志
     }
   },
   sourceMap: true,
   parallel: true
  }), // 生成环境用到的美化js文件的插件
  new webpack.optimize.CommonsChunkPlugin({
   name: 'vendor',
   minChunks(module) {
    return (
     module.resource &&
     /\.js$/.test(module.resource) &&
     module.resource.indexOf(
     path.join(__dirname, '../node_modules')
     ) === 0
    )
   }
  }),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest',
   minChunks: Infinity, 
   // 可以填数字, 最小值为2,模块被多少个chunk公共引用才被抽取出来成为commons chunk
   //  Infinity:只有当入口文件(entry chunks) >= 3 才生效,用来在第三方库中分离自定义的公共模块
  }),
  // CommonsChunkPlugin是提取公共模块的插件
  // vendor的配置可以提取node_modules里面的公共模块放在生成的vendor.js文件里面
  // manifest的配置会提取自定义公共模块放在生成的manifest.js文件里面
  // 注意 :这两个名字需要配合HtmlWebpackPlugin插件选项chunks一起使用,
  // 只有这样HtmlWebpackPlugin插件才会把生成的vendor.js和manifest.js引入到html文件里
  new HtmlWebpackPlugin({
   // 打包之后生成出来的html文件名
   filename: 'xxx.html',
   // 每个html的模版
   template: 'xxx.html',
   // 自动将引用插入body
   inject: true,
   //chunks: ['manifest', 'vendor', entryFileName],多页面使用
   chunksSortMode: 'dependency',//如果是单页面应用使用这个
   minify: {
    removeComments: true,//去除注释
    collapseWhitespace: true,//去除空格
    removeAttributeQuotes: true //移除属性的引号}
   }
  }),
  new webpack.ProvidePlugin({
   $: "jquery",
   jQuery: "jquery",
   moment: "moment"
  })//可以将全局使用的一些插件写在这里,那么在项目中使用的时候就不需要使用 import来导入了,
  // 例如上面的配置,可以在项目所有文件里直接使用$、moment函数
 ]
}

多页面应用的HtmlWebpackPlugin插件配置

写一个utils.js用来放公共的方法,下面返回的entry对象用来配置前面提到的 entry,就不需要自己手动写一大堆入口文件了(下面这个方法是从别人那里看来的,先谢谢大佬了。原网

const path = require('path')
const glob = require("glob");
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const srcDir = path.join(__dirname, '../src');
let plugins = [];
const getEntry = (env) => {
  env = env || 'dev'
  let files = glob.sync(srcDir + '/js/**/*.js'),
      entry = {},
      entryFileName,
      outputHtmlName,
      minifyParms;
  if (env == 'prod') {
    minifyParms = {
      removeComments: true,//去除注释
      collapseWhitespace: true,//去除空格
      removeAttributeQuotes: true //移除属性的引号
    }
  } else {
    minifyParms = false;
  }
  for (let i = 0; i < files.length; i++) {
    let matchs = /js\/(\S*).js/.exec(files[i]);
    entryFileName = outputHtmlName = matchs[1]; //得到apps/question/index这样的文件名
    if (/^_\w*/.test(entryFileName) || /\/_\w*/.test(entryFileName)) {
      continue;
    }
    entry[entryFileName] = files[i]
    //生成html配置
    plugins.push(new HtmlWebpackPlugin({
      // 打包之后生成出来的html文件名
      filename: outputHtmlName + '.html',
      // 每个html的模版
      template: './src/html/' + outputHtmlName + '.html',
      // 自动将引用插入body
      inject: true,
      title: outputHtmlName,
      // 每个html引用的js模块,也可以在这里加上vendor等公用模块
      chunks: ['manifest', 'vendor', entryFileName],
      // chunksSortMode: 'dependency',//如果是单页面应用使用这个就行,上面chunks不需要设置
      minify: minifyParms
    }));
  }
  return entry;
}
const utils = {
  getEntry,
  plugins
}
module.exports = utils
// 导出给webpack.dev.config.js和webpack.prod.config.js使用

webpack.dev.config.js文件

// 开发环境使用的热更新插件联合utils.js返回的插件数组
const utils = require('./utils')
const plugins = [
  new webpack.HotModuleReplacementPlugin()
];
module.exports = {
	entry: utils.getEntry(),
	//... 其他配置
	plugins:plugins.concat(utils.plugins),
}

webpack.prod.config.js文件

// 生产环境使用的插件联合utils.js返回的插件数组
const utils = require('./utils')
const env = 'prod';
const plugins = [
  new CleanWebpackPlugin(['dist'], {
    root: path.resolve(__dirname, '../'),   //根目录
    verbose: true,                  //开启在控制台输出信息
  }),
  new webpack.DefinePlugin({
    'process.env': '"production"'
  }),
  new UglifyJsPlugin({
    uglifyOptions: {
      compress: {
        warnings: false,
        drop_console: true // 去除console.log日志
      }
    },
    sourceMap: true,
    parallel: true
  }),
  new ExtractTextPlugin({
    filename: 'css/[name].[contenthash:8].css',
    allChunks: true,
  }),
  new webpack.HashedModuleIdsPlugin(),
  new webpack.optimize.ModuleConcatenationPlugin(),
  //从node_modules提取第三方库
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks(module) {
      return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
              path.join(__dirname, '../node_modules')
          ) === 0
      )
    }
  }),
  //从入口文件里提取自定义公共js
  new webpack.optimize.CommonsChunkPlugin({
    name: 'manifest',
    minChunks: Infinity, // 可以填数字, 最小值为2,模块被多少个chunk公共引用才被抽取出来成为commons chunk
    //  Infinity:只有当入口文件(entry chunks) >= 3 才生效,用来在第三方库中分离自定义的公共模块
  })
];
module.exports = {
	entry: utils.getEntry(env),
	//... 其他配置
	plugins:plugins.concat(utils.plugins),
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值