webpack4搭建项目环境

webpack是实现工程化,模块化,自动化的一个静态编译工具。当前项目开发过程当中脚手架也是非常方便,比如vue的脚手架,react的脚手架。只要命令行自动帮我们搭建项目环境。实则这些脚手架的基础就是webpack,所以了解和学会运用webpack搭建项目环境是前端开发工程师非常必要的一环。
运用webpack4搭建项目环境,我搭建过2次。这两次不同的地方在于,项目的目录结构是不一样的,那么配置过程中路径写法也是不一样的。实际在我搭建的过程中,遇到的坑是真的多,不过坑踩多了,路就更顺咯。
先来了解一下什么是魔术变量—__dirname。这个概念非常重要,因为在配置过程中路径会让你搞得特别晕,我所理解的是指当前文件所在位置。即用于指向当前执行脚本所在的目录路径。
直接附上代码和目录结构吧~~
1、目录结构一
在这里插入图片描述
config文件夹是存放webpack配置的目录,public是静态html,static是一些静态的东西会原封不动的打包到dist目录。

package.json的代码
{
  "name": "web",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "cross-env NODE_ENV=production webpack --config config/webpack.pro.js",
    "dev": "webpack-dev-server --config config/webpack.dev.js "
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "babel-core": "^6.26.3",
    "cross-env": "^6.0.3",
    "file-loader": "^4.2.0",
    "html-webpack-plugin": "^3.2.0",
    "path": "^0.12.7",
    "resolve-url-loader": "^3.1.0",
    "vue": "^2.6.10",
    "vue-loader": "^15.7.1",
    "vue-template-compiler": "^2.6.10",
    "webpack-cli": "^3.3.9"
  },
  "devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/preset-env": "^7.6.3",
    "babel-loader": "^8.0.4",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^5.0.4",
    "css-loader": "^3.2.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "less-loader": "^5.0.0",
    "sass-loader": "^8.0.0",
    "style-loader": "^1.0.0",
    "url-loader": "^2.2.0",
    "webpack": "^4.41.2",
    "webpack-dev-server": "^3.8.2",
    "webpack-merge": "^4.2.2"
  }
}

基本配置

const path=require('path');
const pathRoot=path.resolve('./');      //根目录
var ExtractTextPlugin = require("extract-text-webpack-plugin");     //抽离公共的css代码
var HtmlWebpackPlugin=require('html-webpack-plugin');       
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const webpack = require('webpack');
const env = process.env.NODE_ENV
module.exports={
    entry:{
        // index:path.resolve(pathRoot,'src/main.js'),
        index:path.resolve(__dirname,'../src/main.js'),
        venders:['vue']
    },
    output:{
        filename:'js/[name]-[hash].js',     //配置出口文件在哪里放置和文件命名
        path:path.resolve(pathRoot,'dist'), //出口目录
    },
    module:{
        rules:[
            {
                test:/\.less$/,
                use:[
                    {   //对象写法
                        loader:'style-loader',
                    },
                    {
                        loader:'css-loader'
                    },
                    {
                        loader:'less-loader'
                    }
                ]
            },
            {
                test:/\.scss$/,
                use:['style-loader','css-loader','resolve-url-loader','sass-loader']        //数组写法
            },
            {
                test:/\.css$/,
                use: ExtractTextPlugin.extract({
                    // fallback:'style-loader',        //额外的css要链接到html中
                    use:[ 'css-loader' ]
                })
            },
            {
                
                test:/\.(png|jpg|gif)$/,
                // loader:'url-loader?limit=10&name=img/[hash:8].[name].[ext]'    
                use:[
                    {
                        loader:'url-loader',     //将图片转成base64
                        options:{
                            limit:10,
                            fallback:'file-loader',  //当文件或图片超过8192,用file-loader进行压缩
                            name:"imgs/[name].[ext]",     //超过10字节将在dist目录生成img图片被file-loader压缩
                                // name: '[name].[hash:8].[ext]',
                                // publicPath: path.resolve(pathRoot,'assets/img'),
                                // outputPath:path.resolve(__dirname,'../imgs'),
                        }
                    }
                ]
                
            },
            {
                test:/\.vue$/,
                use:{
                    loader:'vue-loader'
                }
            },
            {
                test:/\.js/,
                use:[{
                    loader:'babel-loader',
                    options:{
                        "presets": [
                            [
                              "@babel/preset-env",
                            ]
                          ]
                    }
                }],
                exclude: /(node_modules)/
            }
        ]
    },
    resolve:{       //配置模块如何解析
        extensions:['.vue','.js','.json','.css','.less','.scss'],       //可省略扩展名
        alias:{     //src下的文件夹可用@省略符号
            '@':path.resolve(pathRoot,'src'),
        }
    },
    // resolveLoader: {     //解析webpack的loader包
    //     moduleExtensions: ["-loader"]
    //   },
    plugins: [
        new ExtractTextPlugin({
            filename:'style/[name].css' //css抽离出来的文件名
        }),
        new HtmlWebpackPlugin({
            template:path.resolve(__dirname,'../public/page.html'),    //要打包的html模板
            filename:'index.html',         //打包之后生成的目录和文件名称
            inject: true,   //是否引用打包好的js
            minify:{            //
                crashWhitespace :true,//去除所有的空格
                removeComments:true,//去除所有的注释
                removeRedundantAttributes:false, //去除多余的属性
                removeScriptTypeAttributes:false,    //去除js标签
                // removeStyleLinkTypeAttributes:true, //去除样式标签
                // useShortDoctype: true   //使用简短的文档
            }
        }),
        new VueLoaderPlugin(),
        // 按需加载,webpack4被弃用代码分离主要目的是防止代码重复,减少代码体积,达到加载速度快减少 服务器 压力和带宽等目的。
        // new webpack.optimize.CommonsChunkPlugin({
        //     name: "venders",
        //     minChunks: function(module) {
        //       if (module.resource && (/^.*\.(css|scss)$/).test(module.resource)) {
        //         return false;
        //       }
        //       return module.context && module.context.includes("node_modules");
        //     }
        //   }),
        //    new webpack.optimize.CommonsChunkPlugin({
        //     name: "manifest" //But since there are no more common modules between them we end up with just the runtime code included in the manifest file
        //   }),
    ],
    // watch:true       //监听模式,当为true,打包成功还是还会更新文件
}

dev配置

const merge = require('webpack-merge');
const common=require('./webpack.config');
const path=require('path');
const pathRoot=path.resolve('./');
const webpack = require('webpack');
module.exports=merge(common,{
    mode:'development',
    plugins:[
        new webpack.HotModuleReplacementPlugin(),       //热模块更新
    ],
    devServer:{
        open:true,
        port:3080,
        hot:true,
        inline:true,
        // contentBase:path.join(__dirname, "../dist/"),
        publicPath:'/'
    },
    devtool: 'inline-source-map',
})

pro配置

const merge = require('webpack-merge');
const common=require('./webpack.config');
const path=require('path');
const pathRoot=path.resolve('./');
const CopyPlugin = require('copy-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports=merge(common,{
    mode:'production',
    devtool: 'source-map',
    plugins:[
        new CopyPlugin([
            { from:path.resolve(pathRoot,'static'), to: path.resolve(pathRoot,'dist/static') },
        ]),
        new CleanWebpackPlugin({
            verbose:true,                         //是否启用控制台输出信息
         dry: false,                           //设置为false,启用删除文件
        }),        //清除dist,默认删除dist
    ],
     // 推荐此方式抽离,实现按需加载
    optimization: {
        splitChunks: {
        automaticNameDelimiter: '-',
            cacheGroups: {
            commons: {
                name: "commons",
                chunks: "initial",
                minChunks: 2
            },
            venders:{
                name:'venders',
                test:/vue/,
                chunks:'all'
            }
            }
        },
        minimize:false,     //压缩代码,webpack自动压缩代码
    },  
})

2、目录结构二
在这里插入图片描述
package.json的代码

{
  "name": "npmcs_web",
  "version": "1.0.0",
  "description": "项目管理数据分析平台",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --port 8888 --open --config webpack_dev",
    "build": "webpack --config webpack_pro.js"
  },
  "author": "hhl",
  "license": "ISC",
  "dependencies": {
    "@babel/polyfill": "^7.7.0",
    "clean-webpack-plugin": "^3.0.0",
    "html-webpack-plugin": "^3.2.0",
    "path": "^0.12.7"
  },
  "devDependencies": {
    "@babel/core": "^7.7.7",
    "@babel/preset-env": "^7.7.7",
    "babel-loader": "^8.0.4",
    "copy-webpack-plugin": "^5.1.1",
    "css-loader": "^3.4.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^5.0.2",
    "less": "^3.10.3",
    "less-loader": "^5.0.0",
    "style-loader": "^1.0.2",
    "transfer-webpack-plugin": "^0.1.4",
    "url-loader": "^3.0.0",
    "vue": "^2.6.11",
    "vue-loader": "^15.8.3",
    "vue-template-compiler": "^2.6.11",
    "webpack": "^4.41.4",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.1",
    "webpack-merge": "^4.2.2"
  }
}

基本配置

const path = require('path');
const pathBase = path.resolve('./'); //当前根目录
const VueLoaderPlugin=require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
		entry:['@babel/polyfill',path.resolve(__dirname, './src/main.js')], //@babel/polyfill实现预编译
		// entry:path.join(pathBase,'index.html'),		//程序主入口,单页面字符串。多页面,可对象{key:value}
		output: { //浏览器出口,单文件可字符命名或占位符,多文件可使用占位符。
			filename: 'js/[name].[hash].bundle.js',
			path: path.resolve(__dirname, './dist')
		},
		module: {
			rules: [
				//{
					//test: /\.less$/,
					//use: [
					//	{
							//loader: "style-loader"	//将生成的<style>嵌入到html中
					//	},
					//	{
						//	loader: "css-loader"	//把css变成可识别的模块
						//},
						//{
						//	loader: "less-loader" //把less编译成css
						//}
					//]
				//},
				{
					test: /\.less$/,
					use: ExtractTextPlugin.extract({
					  fallback: 'style-loader',
					  use: ['css-loader', 'less-loader']
					})
				},
				{
					test: /\.(png|jpg|svg|gif)$/,
					use:[
						{
							loader:'url-loader',		//图片转成base64
							options:{
								limit:8119,	//表示超过8119才会被压缩生成到dist目录下的image下
								fallback:'file-loader',
								esModule: false, // 这里设置为false,打包之后才不会发现在html里面,img的src为[object Module]。因为版本的原因。
								name:'image/[name]-[hash:7].[ext]'
							}
						}
					]
				},
				{
					test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
					use: ['url-loader?limit=1024&name=fonts/[name]-[hash:7].[ext]']
				},
				**//js优雅降级的过程当中,低版本和高版本要对应要不然会踩坑**
 				{
 					test: /\.js$/,
 					exclude: /(node_modules)/,
 					use: [
 							{
 								loader:'babel-loader',
 								options:{
 									"presets":['@babel/preset-env']
 								}
 							},
 					]
 				},
				{
					
					test: /\.vue$/,
					loader:['vue-loader']
				}
			]
		},
		// 模块如何解析
		resolve:{
			alias: {		//创建模块的别名
				'@':path.resolve(__dirname,'./src/'),
				'$':'jquery',
			},
			extensions: [".js", ".json",".vue",".png",".jpg"],		//省略扩展符
		},
		plugins: [
        	new VueLoaderPlugin(),
			new HtmlWebpackPlugin({
				title: '项目管理数据分析平台',
				minify: { // 压缩HTML文件
					removeComments: true, // 移除HTML中的注释
					collapseWhitespace: true, // 删除空白符与换行符
					minifyCSS: true,// 压缩内联css
					minifyJS: true,	//是否压缩js
				},
				filename: path.resolve(__dirname,'./dist/index.html'),		//输出的文件名称
				template: path.resolve(__dirname,'./index.html'),					//模板
				favicon:path.resolve(__dirname,'./public/favicon.ico'),
				hash: true,
				}),
			new ExtractTextPlugin({			//将css抽离
				filename:'css/[name]-[hash:7].css'
	  	 	}),
    ],
}

dev配置

const merge=require('webpack-merge');
const path=require('path');
const config=require('./webpack.config');
module.exports=merge(config,{
	mode:'development',
	devServer: {
		// contentBase: path.join(__dirname, './public'), 
		inline:true,		//浏览器热刷新
		port: 8888,     //端口设置
		open:true,			//自动开启浏览器
		publicPath:'/',
	},
	devtool:'inline-source-map' 	//报错指向源代码
})

pro配置

const merge=require('webpack-merge');
const path=require('path');
const config=require('./webpack.config');
// const TransferWebpackPlugin = require('transfer-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports=merge(config,{
	mode:'production',
	devtool:'source-map' 	,//报错指向源代码
	plugins:[
		new CleanWebpackPlugin({
			verbose:true,    //是否启用控制台输出信息
   		dry: false,			//设置为false,启用删除文件
		}),
		new CopyWebpackPlugin([{
				from: path.resolve(__dirname,'./public/static'),  // 一次性把static 里面的所有文件全部拷贝过来
				to: path.resolve(__dirname,'./dist/static')
		}])
	]
})

package.json的包的版本号也是很重要的,因为版本不一样带来的问题也是不一样的。我就踩过因为版本带来的问题的坑~~

猜你喜欢

转载自blog.csdn.net/Miss_hhl/article/details/103643224