Webpack4.X构建html项目

本文章主要教大家从零到搭建、开发、打包html+css(less、sass)+js(es6、es7)+ 图片加载、优化项目

一、搭建项目

1. 我们先新建一个项目 并用 npm 命令初始化项目(一路回车)

npm init

执行完成后项目中就会生成一个package.json文件
在这里插入图片描述
这里主要说说几个参数
srcipts 是把需要执行的命令语句简化的存放地方
devDependenciesdependencies都是存放插件的地方
devDependencies里面的插件只用于开发环境,不用于生产环境,而 dependencies依赖的包不仅开发环境能使用,生产环境也能使用。

2. 安装 webpack 与 webpack-cli ( 4 版本需要cli才能执行命令)

npm install --save-dev webpack webpack-cli

**

3. 新建 src 文件夹,存放开发代码,默认输入文件是 index.js,所以我们先在 src 下新建一个index.js文件

**

document.write("测试打包")

4. 执行命令,便能实现最简单的 “ 项目打包 ”

webpack

5. 输入命令打包完成后会生成一个 dist 文件夹,里面就存放着我们需要打包的文件,这样一个最简单的 webpack 打包流程到此完工。

二、命令部分

1. webpack 默认打包命令

第一部分我们使用过 webpack 命令进行打包,其实这个命令是不完整的,细心的小伙伴会发现执行时控制台会有提示该命令有 production(生产) 与 development (开发)模式,完整命令如下:

// 两个命令有和不同就请大家自己手动试一下,这里就不赘述了
webpack --mode production
webpack --mode development

2. webpack 根据配置文件打包命令

实际中我们打包项目根据需要会有各种配置,因此常用的是根据配置文件来进行打包,所以我们在项目根目录下新建一个 webpack.config.js 文件来保存配置信息,考虑到开发跟生产环境的配置会有所不同可以新建两个文件对应执行打包跟开发,这里我命名是webpack.dev.config.js和webpack.prod.config.js。这里主要以webpack.config.js 文件来进行。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
  }
}

稍后会对这个文件进行详细讲解,这里先执行命令看是否能成功进行按需打包

// webpack.config.js 可根据自己需要命名 打包方法是 --config 配置文件路径
webpack --mode production --config ./webpack.config.js

打包成功会发现在 dist 下现在生成的文件名已经由默认变成了我们指定的 bundle.js

3. 改写 npm 命令

由于 webpack 指令比较长,输入时很不方便,我们有个小技巧可以简化这一步骤,就是对项目的 package.json 文件中的 script 部分进行修改

"scripts": {
    "dev": "webpack --mode development --config ./webpack.config.js",
    "build": "webpack --mode production --config ./webpack.config.js"
  },

执行以下命令就相当于执行了我们所设置对应的完整 webpack 命令

npm run dev
npm run build

三、配置部分

1. 关于文件路径

配置文件会有许多关于文件路径的设置,这方面一不小心就会出现问题,这里推荐采以下方法对相对路径进行处理

const path = require('path')
// 此方法会根据传入的相对路径自动转化为绝对路径,确保路径的正确
path.resolve(__dirname, '文件的相对路径')

2. 配置文件结构总览

主要包含以下 4 个部分
entry:配置文件入口
output:配置输出文件名与路径
plugins:配置引入的插件
module: 配置文件转换的规则

const path = require('path')

module.exports = {
  // 输入路径配置
  entry: path.resolve(__dirname, './src/index.js'),
  // 输出文件名和路径配置
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, './dist')
  },
  // 引入插件配置
  plugins: [],
  // 文件类型转换配置
  module: {}
}

3. 完善 js 文件输出路径

通常项目我们有一个专门的 js 文件夹进行存放 js 文件,并且为了区分版本,我们有时会使用 hash 进行区分( hash 值仅当源码文件被修改时才会更新)

const path = require('path')

module.exports = {
  // 输入路径配置
  entry: path.resolve(__dirname, './src/index.js'),
  // 输出文件名和路径配置
  output: {
    // [name] 可自行配置,参考文档
    // [hash:4] 使用 hash 取前 4 位
    filename: 'js/[name]-[hash:4].js',
    path: path.resolve(__dirname, './dist')
  },
  // 引入插件配置
  plugins: [],
  // 文件类型转换配置
  module: {}
}

4.引入 html 模板

目前为止,我们打包的都只有 js 文件,作为前端项目,怎么可以没有 html 文件呢,为了实现打包自动生成 html 文件,我们开始引入我们的第一个插件

  • 安装插件 html-webpack-plugin
npm install --save-dev html-webpack-plugin
  • 在项目根目录下新建 index.html 文件作为模板,供配置文件引入
  • webpack.config.js 配置例子
const path = require('path')
const htmlWebpackPlugins = require('html-webpack-plugin')

module.exports = {
  // 输入路径配置
  entry: //path.resolve(__dirname, './src/index.js'),
  {//若有多个js可以以对象形式写.
        'js/index': './src/index.js',  //移动端入口文件
        'pc/js/index': './src/pc/index.js',  //pc端入口文件
    },
  // 输出文件名和路径配置
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, './dist')
  },
  // 引入插件配置
  plugins: [
  	//若项目为多页面入口,只需new多几个htmlWebpackPlugins即可,
    new htmlWebpackPlugins({
      // 输出文件名
      filename: 'index.html',
      // 所引用模板文件位置
      template: 'index.html',
      // js 文件插入的位置
      inject: 'body',
      chunks:['pc/js/index'],//加载指定模块中的js文件,否则页面会加载所有js文件
      hash: false,    //为静态资源生成hash值
      minify: {    //压缩HTML文件
         removeComments: false,    //移除HTML中的注释
         collapseWhitespace: false    //删除空白符与换行符
      }
    }),
  ],
  // 文件类型转换配置
  module: {}
}

5. 完善项目目录

在 src 目录下新建 components 文件夹,分别新建 html, js, css 文件 ,下面以 scroll 组件为例
scroll.html

<div class="scroll">
  <p>scroll</p>
</div>

scroll.js

// import tpl from './scroll.html'
// import './scroll.css'

function scroll () {
  return {
    name: 'scroll',
    // tpl: tpl
  }
}

export default scroll

scroll.css

.scroll {
  height: 500px;
  width: 500px;
  background: red;
}

.scroll p {
  display: flex;
}

文件新建完还需在我们的入口文件 index.js 中引入

import Scroll from './components/scroll'

const App = function () {
  var dom = document.getElementById('app')
  var scroll = new Scroll()
  dom.innerHTML = scroll.tpl
  document.write(scroll.name)
}

new App()

最后修改下我们的 index.html 模板,新增 app 模块

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

这时尝试打包,便可把我们新增的 scroll.js 引入进来了,但是这时我们 tpl 也就是 scroll.html 还处于注释状态,想要正确引入,还需添加其他插件

6. 配对 .html 类型文件

  • 安装插件 html-loader
npm install --save-dev html-loader
  • 修改我们的 webpack.config.js ,在 module 中完善我们的文件转换配置
const path = require('path')
const htmlWebpackPlugins = require('html-webpack-plugin')

module.exports = {
  entry: path.resolve(__dirname, './src/index.js'),
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, './dist')
  },
  plugins: [
    new htmlWebpackPlugins({
      filename: 'index.html',
      template: 'index.html',
      inject: 'body'
    }),
  ],
  // 文件类型转换配置
  module: {
    rules: [
      {
        // 正则匹配 html 文件
        test: /\.html$/,
        use: [
          {
            // 引入 html 文件加载插件
            loader: 'html-loader'
          }
        ]
      }
    ]
  }
}
  • 修改下我们的 scroll.js 文件,将之前的注释取消
import tpl from './scroll.html'
// import './scroll.css'

function scroll () {
  return {
    name: 'scroll',
    tpl: tpl
  }
}

export default scroll

7.引入 加载图片模板

webpack加载css背景图片、img元素指向的网络图片、使用es6的import引入的图片时,需要使用url-loader或者file-loader。
否则会报错。
url-loader和file-loader可以加载任何文件,区别:

url-loader可以将图片转为base64字符串,能更快的加载图片,一旦图片过大,
就需要使用file-loader的加载本地图片,故url-loader可以设置图片超过多少字节时,使用file-loader加载图片。

安装url-loader和file-loader

npm install url-loader  file-loader --save-dev

webpack.config.js 配置

//文件类型转换配置
module: {
     rules: [
		{
		   //处理图片
		    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
		    use: [
		        {
		            loader: 'url-loader',
		            options: {
		                limit: 10000,//图片大小小于这个值则以base64字符串显示
		                name: 'images/[name].[ext]'
		            }
		        }
	    	]
		}
	]
}

打包后可以看出img元素的src可以看到具体src值为base64或地址引用。
若图片想使用懒加载,如jq的lazy-load等,打包时会直接跳过该图片的,这时候我们需要安装transfer-webpack-plugin插件,这个插件主要是用来把需要直接搬移的文件搬移到打包后的目录上。
webpack.config.js 配置

//插件
plugins: [
// 把app/src/images目录下的文件copy到dist/images目录下
 	new TransferWebpackPlugin([{
        from: 'images',
        to: 'images'
    },
    {
        from: 'pc/images',
        to: 'pc/images'
    }
    ], path.resolve(__dirname, 'src'))
]

这样懒加载的图片也会一并打包到dist目录里面了。

8. 配对 .css 类型文件

  • 安装插件 css-loader 与 style-loader
npm install --save-dev css-loader style-loader
  • 修改我们的 webpack.config.js, 添加匹配规则
 // 文件类型转换配置
  module: {
    rules: [
      {
        // 正则匹配 html 文件
        test: /\.html$/,
        use: [
          {
            // 引入 html 文件加载插件
            loader: 'html-loader'
          }
        ]
      },
      {
        // 正则匹配 css 文件
        test: /\.css$/,
        use: [
          {
            // 引入 style 文件加载插件
            loader: 'style-loader'
          },
          {
            // 引入 css 文件加载插件
            loader: 'css-loader'
          }
        ]
      },
    ]
  }
  • 修改下我们的 scroll.js 文件,将之前 css 的注释也取消
import tpl from './scroll.html'
import './scroll.css'

function scroll () {
  return {
    name: 'scroll',
    tpl: tpl
  }
}

export default scroll

如果想直接引入css可以在scr层级的index引入,js插件引入也是如此

index.js

require('./css/index.css');
require('./js/jquery.lazyload.min.js');

抽离css样式
一般加入了上面两个loader后css的样式会插入在html里面,如果想分离出来则需要使用extract-text-webpack-plugin

  • 安装extract-text-webpack-plugin插件
npm i extract-text-webpack-plugin@next -D 

注意这个@next紧在webpack4.x以上可用,版本低于4.x的请另行百度对应安装指令。

  • webpack.config.js配置
var ExtractTextPlugin = require("extract-text-webpack-plugin");
 rules: [
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        { 
                            loader: 'css-loader', 
                            options: { importLoaders: 1 } 
                        }
                    ]
                }),
            }
        ],
plugins:[
 		new ExtractTextPlugin({
            filename: (getPath) => {
                return getPath('[name].css').replace("js", "css")
            }
        }),
        
]

压缩CSS

  • 安装optimize-css-assets-webpack-plugin 插件
npm install optimize-css-assets-webpack-plugin --save-dev
  • webpack.config.js配置

var ExtractTextPlugin = require("extract-text-webpack-plugin");
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); //压缩css先引入
 rules: [
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        { 
                            loader: 'css-loader', 
                            options: { importLoaders: 1 } 
                        }
                    ]
                }),
            }
        ],
plugins:[
 		new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css$/g,       //一个正则表达式,指示应优化/最小化的资产的名称。提供的正则表达式针对配置中ExtractTextPlugin实例导出的文件的文件名运行,而不是源CSS文件的文件名。默认为/\.css$/g
            cssProcessor: require('cssnano'), //用于优化\最小化CSS的CSS处理器,默认为cssnano
            cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给cssProcessor的选项,默认为{}
            canPrint: true                    //一个布尔值,指示插件是否可以将消息打印到控制台,默认为true
        }),
        new ExtractTextPlugin({
            filename: (getPath) => {
                return getPath('[name].css').replace("js", "css")
            }
        })
]

处理css在浏览器的兼容

  • 安装postcss-loader autoprefixer postcss
//sass-loader依赖于node-sass,所以还要安装node-sass
//postcss-loader autoprefixer postcss 处理浏览器兼容
npm install --save-dev  postcss-loader autoprefixer postcss
  • webpack.config.js配置
{
     test:/\.css$/,
     use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
              { 
                  loader: 'css-loader', 
                  options: { importLoaders: 1 } 
              },
              'postcss-loader'
          ]
      }),
 }

预编译(less、sass)

  • 安装less
npm install --save-dev less-loader less

webpack.comfig.js配置

rules:[
	{
     test:/\.css$/,
     use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
              { 
                  loader: 'css-loader', 
                  options: { importLoaders: 1 } 
              },
              'postcss-loader'
          ]
      }),
	 },
	{
         test: /\.less$/,
         exclude : '/node_modules',
         use:  ExtractTextPlugin.extract({
          	   fallback: 'style-loader',
               use:[
	            {
	                 loader: 'style-loader'
	             },
	             {
	                 loader: 'css-loader',   
	                 options: {
	                     importLoaders: 1
	                 }
	             },
	             {
	                 loader: 'postcss-loader',
	                 options: {
	                     ident: 'postcss',
	                     plugins: (loader) => [
	                       require('postcss-import')({ root: loader.resourcePath }),
	                       require('postcss-cssnext')(),
	                       require('autoprefixer')(),
	                       require('cssnano')()
	                     ]
                   	}
	             },
	             {
	                 loader: 'less-loader',  // 
	                 options: {
	                     importLoaders: 1
	                 }
	             }
         	]
       	}),
     }
]
// 需要注意的是顺序问题: style-loader -> css-loader -> postcss-loader -> less-loader 执行顺序于此相反。
  • 安装sass
//在项目下,运行下列命令行
npm install --save-dev sass-loader
//因为sass-loader依赖于node-sass,所以还要安装node-sass
npm install --save-dev node-sass

webpack.comfig.js配置

rules:[
			//解析.scss文件,对于用 import 或 require 引入的sass文件进行加载,以及<style lang="sass">...</style>声明的内部样式进行加载
            {
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract("style", 'css!sass') //这里用了样式分离出来的插件,如果不想分离出来,可以直接这样写 loader:'style!css!sass'
            }
]

9.ES6 到 ES5 的转换

注意,这里由于bable升级后,安装跟以往不一样,bable跟bable-loader的版本必须匹配。
babel-loader 8.x | babel 7.x

npm install  --save-dev babel-loader @babel/core @babel/preset-env 

babel-loader 7.x | babel 6.x

npm install  --save-dev babel-loader@7 babel-core babel-preset-env

创建…babelrc文件

// 将来babel-loader运行的时候,会检查这个配置文件,并读取相关的语法和插件配置
{
//8.x的写法
    "presets": ["@babel/env",]
//7.x 的写法
 	"presets": ["env",]
}

10.webpack 热更新

  • 安装webpack-dev-server
 npm install webpack-dev-server --save-dev

启动服务

webpack-dev-server --inline --colors

server在webpack.config.js的配置


    //插件
    plugins: [
        //热加载需要
        new webpack.HotModuleReplacementPlugin()
    ],
    devtool:'eval-source-map', //热加载
    devServer: {               //热更新 一般不配置也可以
        historyApiFallback: true, // 当我们搭建spa应用时非常有用,它使用的是HTML5 History Api,任意的跳转或404响应可以指向 index.html 页面
        contentBase: './',// 本地服务器在哪个目录搭建页面,一般我们在当前目录即可;
        inline: true, // 页面自动刷新的配置,webpack有两种模式支持自动刷新,一种是iframe模式,一种是inline模式;使用iframe模式是不需要在devServer进行配置的,只需使用特定的URL格式访问即可
        hot: true,  // 启动webpack热模块替换特性 hot这个属性已经没有用了,使用热模块的话我们需要用到一个叫webpack.HotModuleReplacementPlugin
        port: 8080,
        open:false //自动打开浏览器
    }

以上就是用webpack4.x构建hmtl项目开发、打包所有需要的插件的安装使用的教程,内容是又本人根据其他文章总结归纳的,若有错误欢迎指出。最后贴一下package插件的版本,若与你安装版本的不一样,操作后报错有可能是版本不一样的原因。

package.json

  "devDependencies": {
    "@babel/core": "^7.4.3",
    "@babel/preset-env": "^7.4.3",
    "autoprefixer": "^9.5.0",
    "babel-loader": "^8.0.5",
    "css-loader": "^2.1.1",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "image-webpack-loader": "^4.6.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss": "^7.0.14",
    "postcss-loader": "^3.0.0",
    "style-loader": "^0.23.1",
    "transfer-webpack-plugin": "^0.1.4",
    "url-loader": "^1.1.2",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0",
    "webpack-dev-server": "^3.2.1"
  },
  "dependencies": {
    "babel-runtime": "^6.26.0",
    "file-loader": "^3.0.1",
    "url-loader": "^1.1.2"
  }

webpack.config.js

var webpack = require('webpack');

var path = require('path');

var HtmlWebpackPlugin = require('html-webpack-plugin'); //打包html的插件

var ExtractTextPlugin = require("extract-text-webpack-plugin");   //打包css的插件

var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); //压缩css

var TransferWebpackPlugin = require('transfer-webpack-plugin');  //懒加载图片需另外搬移

module.exports = {

    entry://path.resolve(__dirname, './app/src/index.js'),
    {
        'js/index': './src/index.js',  //移动端入口文件
        'pc/js/index': './src/pc/index.js',  //pc端入口文件
    },
    output: {
        filename: '[name].js',      //打包后index.js的名字,    
        path: path.resolve(__dirname, './dist')
    },
    //文件类型转换配置
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        { 
                            loader: 'css-loader', 
                            options: { importLoaders: 1 } 
                        },
                        'postcss-loader'
                    ]
                }),
            },
            {
                // 正则匹配 html 文件
                test: /\.html$/,
                use: [
                    {
                        // 引入 html 文件加载插件
                        loader: 'html-loader'
                    }
                ]
            },
            // exclude 排除,不需要编译的目录,提高编译速度
            // {
            //     test: /\.(js)$/,
            //     loader: 'babel-loader',
            //     exclude: /node_modules/
            // },
            {
                //处理图片
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10000,
                            name: 'images/[name].[ext]'
                        }
                    },
                    {	//压缩图片要在file-loader之后使用
                        loader:'image-webpack-loader',
                        options:{
                            bypassOnDebug: true
                        }
                    }
    
                ]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                loader: 'file-loader'
            }
        ]
    },
    //插件
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: 'src/index.html',
            inject: 'body',
            chunks:['js/index'],//加载指定模块中的文件,否则页面会加载所有文件
            hash: false,    //为静态资源生成hash值
            minify: {    //压缩HTML文件
                removeComments: false,    //移除HTML中的注释
                collapseWhitespace: false    //删除空白符与换行符
            }
        }),
        new HtmlWebpackPlugin({
            filename: 'pc/index.html',
            template: 'src/pc/index.html',
            inject: 'body',
            chunks:['pc/js/index'],//加载指定模块中的文件,否则页面会加载所有文件
            hash: false,    //为静态资源生成hash值
            minify: {    //压缩HTML文件
                removeComments: false,    //移除HTML中的注释
                collapseWhitespace: false    //删除空白符与换行符
            }
        }),
        new ExtractTextPlugin({
            filename: (getPath) => {
                return getPath('[name].css').replace("js", "css")
            }
        }),
        // 把app/src/images目录下的文件copy到dist/images目录下
        new TransferWebpackPlugin([{
            from: 'images',
            to: 'images'
        },
        {
            from: 'pc/images',
            to: 'pc/images'
        }
        ], path.resolve(__dirname, 'src')),
        new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css$/g,       //一个正则表达式,指示应优化/最小化的资产的名称。提供的正则表达式针对配置中ExtractTextPlugin实例导出的文件的文件名运行,而不是源CSS文件的文件名。默认为/\.css$/g
            cssProcessor: require('cssnano'), //用于优化\最小化CSS的CSS处理器,默认为cssnano
            cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给cssProcessor的选项,默认为{}
            canPrint: true                    //一个布尔值,指示插件是否可以将消息打印到控制台,默认为true
        }),
        //热加载需要
        new webpack.HotModuleReplacementPlugin()
    ],
    devtool:'eval-source-map', //热加载
    devServer: {               //热更新 一般不配置也可以
        historyApiFallback: true, // 当我们搭建spa应用时非常有用,它使用的是HTML5 History Api,任意的跳转或404响应可以指向 index.html 页面
        contentBase: './',// 本地服务器在哪个目录搭建页面,一般我们在当前目录即可;
        inline: true, // 页面自动刷新的配置,webpack有两种模式支持自动刷新,一种是iframe模式,一种是inline模式;使用iframe模式是不需要在devServer进行配置的,只需使用特定的URL格式访问即可
        hot: true,  // 启动webpack热模块替换特性 hot这个属性已经没有用了,使用热模块的话我们需要用到一个叫webpack.HotModuleReplacementPlugin
        port: 8080,
        open:false //自动打开浏览器
    }
}

若更换了项目再用cnpm安装依赖后,会出现丢包的情况,这样会导致无法打包,所有建议安装使用npm进行

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值