webpack.config.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const HtmlWebpackPlugin = require('html-webpack-plugin'); // 自动生成index.html
  4. const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 文本分离插件,分离js和css
  5. const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 清理垃圾文件
  6. const CopyWebpackPlugin = require('copy-webpack-plugin');
  7. const WebpackBar = require('webpackbar');
  8. const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue加载器
  9. const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); // 为模块提供中间缓存,缓存默认的存放路径是: node_modules/.cache/hard-source
  10. /**
  11. * 判断是生产环境还是开发环境
  12. * @type {boolean}
  13. * isProd为true表示生产
  14. */
  15. const isProd = process.env.NODE_ENV === 'production';
  16. // 获取本机ip
  17. const getIp = require('./get_ip')();
  18. // 获取时间
  19. const TimeFn = require('./get_time');
  20. console.log(
  21. `
  22. _ooOoo_
  23. o8888888o
  24. 88" . "88
  25. (| -_- |)
  26. O\\ = /O
  27. ____/\`---'\\____
  28. .' \\\\| |// \`.
  29. / \\\\||| : |||// \\
  30. / _||||| -:- |||||- \\
  31. | | \\\\\\ - /// | |
  32. | \\_| ''\\---/'' | |
  33. \\ .-\\__ \`-\` ___/-. /
  34. ___\`. .' /--.--\\ \`. . __
  35. ."" '< \`.___\\_<|>_/___.' >'"".
  36. | | : \`- \\\`.;\`\\ _ /\`;.\`/ - \` : | |
  37. \\ \\ \`-. \\_ __\\ /__ _/ .-\` / /
  38. ======\`-.____\`-.___\\_____/___.-\`____.-'======
  39. \`=---='
  40. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  41. 佛祖保佑 永无BUG
  42. ${TimeFn()}
  43. `
  44. );
  45. /**
  46. * css和stylus开发、生产依赖
  47. * 生产分离css
  48. */
  49. const cssConfig = [
  50. isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
  51. 'thread-loader',
  52. {
  53. loader: 'css-loader',
  54. options: {
  55. sourceMap: !isProd
  56. }
  57. },
  58. 'postcss-loader'
  59. ];
  60. const stylusConfig = [
  61. isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
  62. 'thread-loader',
  63. {
  64. loader: 'css-loader',
  65. options: {
  66. sourceMap: !isProd
  67. }
  68. },
  69. {
  70. loader: 'stylus-loader',
  71. options: {
  72. sourceMap: !isProd
  73. }
  74. }, {
  75. loader: 'style-resources-loader',
  76. options: {
  77. injector: 'prepend',
  78. patterns: path.resolve(__dirname, 'src/assets/stylus/variables.styl')
  79. }
  80. }
  81. ];
  82. const config = {
  83. entry: {
  84. index: isProd ? ['core-js/stable', 'regenerator-runtime/runtime', './src/main.js'] : './src/main.js' // 入口文件
  85. // index: ['core-js/stable', 'regenerator-runtime/runtime', './src/main.js'], // 入口文件
  86. },
  87. output: {
  88. path: path.resolve(__dirname, 'production'),
  89. filename: isProd ? 'javascript/[name].[hash:8].js' : '[name].js', // [name] 是entry的key
  90. publicPath: isProd ? './' : '/'
  91. // publicPath: './',
  92. },
  93. module: {
  94. rules: [
  95. {
  96. test: /\.css$/,
  97. use: cssConfig
  98. },
  99. {
  100. test: /\.styl(us)?$/,
  101. use: stylusConfig,
  102. include: [path.resolve(__dirname, 'src')]
  103. },
  104. {
  105. test: /\.vue$/,
  106. use: [
  107. 'thread-loader', 'cache-loader',
  108. {
  109. loader: 'vue-loader',
  110. options: {
  111. loaders: {
  112. css: cssConfig,
  113. stylus: stylusConfig
  114. },
  115. preserveWhitespace: false // 不要留空白
  116. }
  117. }],
  118. include: [path.resolve(__dirname, 'src')]
  119. },
  120. {
  121. test: /\.js$/,
  122. use: [
  123. 'thread-loader', 'cache-loader',
  124. {
  125. loader: 'babel-loader',
  126. options: {
  127. cacheDirectory: !isProd
  128. }
  129. }
  130. ],
  131. exclude: (file) => (
  132. /node_modules/.test(file) && !/\.vue\.js/.test(file)
  133. )
  134. },
  135. {
  136. test: /\.svg$/,
  137. use: ['thread-loader', 'babel-loader', 'vue-svg-loader'],
  138. include: [path.resolve(__dirname, 'src')]
  139. },
  140. {
  141. test: /\.(png|jpe?g|gif|bmp)$/,
  142. use: [
  143. {
  144. loader: 'url-loader',
  145. options: { // 配置图片编译路径
  146. limit: 8192, // 小于8k将图片转换成base64
  147. name: '[name].[ext]?[hash:8]',
  148. outputPath: 'images/'
  149. }
  150. }],
  151. include: [path.resolve(__dirname, 'src')]
  152. },
  153. {
  154. test: /\.html$/,
  155. use: [{
  156. loader: 'html-loader',
  157. options: { // 配置html中图片编译
  158. minimize: true,
  159. attributes: false
  160. }
  161. }]
  162. }
  163. ]
  164. },
  165. resolve: { // 配置路径别名
  166. extensions: ['.js', '.vue', '.styl'], // import引入文件的时候不用加后缀
  167. modules: [
  168. 'node_modules',
  169. path.resolve(__dirname, 'src/assets'),
  170. path.resolve(__dirname, 'src/docs'),
  171. path.resolve(__dirname, 'src/utils')
  172. ]
  173. },
  174. plugins: [
  175. new webpack.BannerPlugin(`@meri-design ${TimeFn()}`),
  176. new HardSourceWebpackPlugin(),
  177. new VueLoaderPlugin(), // vue加载器
  178. new CopyWebpackPlugin([{
  179. from: path.resolve(__dirname, 'node_modules/vue/dist/vue.min.js'),
  180. to: 'modules'
  181. }, {
  182. from: path.resolve(__dirname, 'node_modules/vuex/dist/vuex.min.js'),
  183. to: 'modules'
  184. }, {
  185. from: path.resolve(__dirname, 'node_modules/vue-router/dist/vue-router.min.js'),
  186. to: 'modules'
  187. }]),
  188. new HtmlWebpackPlugin({
  189. template: path.join(__dirname, 'src/index.html'), // 引入模版
  190. favicon: path.join(__dirname, 'src/assets/favicon.ico'),
  191. filename: 'index.html',
  192. minify: { // 对index.html压缩
  193. collapseWhitespace: isProd, // 去掉index.html的空格
  194. removeAttributeQuotes: isProd // 去掉引号
  195. },
  196. hash: true, // 去掉上次浏览器的缓存(使浏览器每次获取到的是最新的html)
  197. // ,chunks:['vendor','main'] // 在产出的html文件里面引入哪些代码块,里面的名字要跟entry里面key对应(一般用于多文件入口)
  198. inlineSource: '.(js|css)'
  199. }),
  200. new WebpackBar({
  201. color: '#0091ff'
  202. })
  203. ],
  204. externals: {
  205. vue: 'Vue',
  206. vuex: 'Vuex',
  207. 'vue-router': 'VueRouter'
  208. }
  209. };
  210. if (isProd) {
  211. config.plugins.push(
  212. new CleanWebpackPlugin({
  213. verbose: true, // 打印被删除的文件
  214. protectWebpackAssets: false, // 允许删除cleanOnceBeforeBuildPatterns中的文件
  215. cleanOnceBeforeBuildPatterns: ['**/*', path.resolve(__dirname, 'production')]
  216. }),
  217. new MiniCssExtractPlugin({ // 分离css
  218. filename: 'stylesheets/[name].[contenthash:8].css'
  219. // chunkFilename: isProd?'stylesheets/[name].[contenthash:8].css':'[name].css'
  220. })
  221. );
  222. config.optimization = { // 抽离第三方插件
  223. splitChunks: {
  224. chunks: 'all', // 必须三选一: "initial" | "all" | "async"(默认就是异步)
  225. minSize: 10000, // 提高缓存利用率,这需要在http2/spdy
  226. maxSize: 0, // 没有限制
  227. minChunks: 3, // 共享最少的chunk数,使用次数超过这个值才会被提取
  228. maxAsyncRequests: 5, // 最多的异步chunk数
  229. maxInitialRequests: 5, // 最多的同步chunks数
  230. name: true,
  231. cacheGroups: { // 这里开始设置缓存的 chunks
  232. vendor: { // key 为entry中定义的 入口名称,new webpack.ProvidePlugin中的库
  233. test: /node_modules/, // 正则规则验证,如果符合就提取 chunk (指定是node_modules下的第三方包)
  234. name: 'vendor', // 要缓存的 分隔出来的 chunk 名称
  235. enforce: true
  236. },
  237. styles: {
  238. test: /src\.(css|styl)$/,
  239. name: 'main',
  240. enforce: true
  241. }
  242. }
  243. },
  244. runtimeChunk: { name: 'manifest' } // 为每个入口提取出webpack runtime模块
  245. };
  246. } else {
  247. config.devtool = 'source-map'; // 如果只用source-map开发环境出现错误定位源文件,生产环境会生成map文件
  248. config.devServer = {
  249. contentBase: path.join(__dirname, 'production'), // 将 dist 目录下的文件,作为可访问文件。
  250. compress: true, // 开启Gzip压缩
  251. // , host: 'localhost' // 设置服务器的ip地址,默认localhost
  252. host: getIp, // 设置服务器的ip地址,默认localhost
  253. port: 3002, // 端口号
  254. open: true, // 自动打开浏览器
  255. hot: true,
  256. overlay: { // 当出现编译器错误或警告时,就在网页上显示一层黑色的背景层和错误信息
  257. errors: true
  258. },
  259. disableHostCheck: true // 不检查主机
  260. // historyApiFallback: { // 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 /
  261. // rewrites: [{ from: /./, to: '/' }]
  262. // }
  263. };
  264. }
  265. module.exports = config;