cd webpack_demo
npm init
var path = require('path');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
}
};
npm install --save-dev babel-loader babel-core babel-preset-env webpack
var path = require('path');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loder'
},
exclude: /(node_modules|bower_components)/
}]
}
};
{
"presets": ["env"]
}
cnpm instal postcss-loader autoprefixer --save-dev
module.exports = {
plugins: [
require('autoprefixer')
]
};
cnpm install css-loader style-laoder --save-dev
3.配置文件如下
var path = require('path');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}]
}]
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
"@": resolve('src'),
"@static": resolve('static')
}
}
};
插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。
Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。
Webpack有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。
要使用某个插件,我们需要通过npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)
var path = require('path');
var webpack = require('webpack');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}]
}]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
],
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
"@": resolve('src'),
"@static": resolve('static')
}
}
};
我们知道,webpack编译后,css会存放在编译后的js文件里,就有强迫症的人来看这种结构就很奇怪,==extract-text-webpack-plugin==就是这样一个能够把css文件提取出来的插件
1. 下载extract-text-webpack-plugin插件
cnpm install extract-text-webpack-plugin --save-dev
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}]
})
}]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin({
filename: path.posix.join('assets', 'css/[name].[contenthash].css')
})
],
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
"@": resolve('src'),
"@static": resolve('static')
}
}
};
cnpm install optimize-css-assets-webpack-plugin --save-dev
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}]
})
}]
},
plugins: [
// js压缩
new webpack.optimize.UglifyJsPlugin(),
// css压缩
new OptimizeCssAssetsPlugin(),
// css分离
new ExtractTextPlugin({
filename: path.posix.join('assets', 'css/[name].[contenthash].css')
})
],
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
"@": resolve('src'),
"@static": resolve('static')
}
}
};
这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。
1. 安装
cnpm install html-webpack-plugin --save-dev
这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直以来的项目结构做一些更改:
将根目录中的index.html作为html模板,编译后,webpack会在dist目录下生成index.html(编译后的html文件),编译后的文件css和js文件都自动引入,无需手动引入
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}]
})
}]
},
plugins: [
// js压缩
new webpack.optimize.UglifyJsPlugin(),
// css压缩
new OptimizeCssAssetsPlugin(),
// css分离
new ExtractTextPlugin({
filename: path.posix.join('assets', 'css/[name].[contenthash].css')
}),
// html 编译
new HtmlWebpackPlugin({
filename: 'index.html', //new 目标编译出的文件的文件名
template: 'index.html', //new 编译后的html的路径,相对目录是dist文件夹
inject: true // 是否把js文件插入到body的最后
})
],
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
"@": resolve('src'),
"@static": resolve('static')
}
}
};
webpack中我们这里只考虑简单情况,使用简洁的==webpack-dev-server==插件来实现
- 想不想让你的浏览器监听你的代码的修改,并自动刷新显示修改后的结果,其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现你想要的这些功能,不过它是一个单独的组件,在webpack中进行配置之前需要单独安装它作为项目依赖
cnpm install webpack-dev-server --dev
devserver的配置选项 | 功能描述 |
---|---|
contentBase | 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public”目录) |
port | 设置默认监听端口,如果省略,默认为”8080“ |
inline | 设置为true,当源文件改变时会自动刷新页面 |
historyApiFallback | 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html |
- 把这些命令加到webpack的配置文件中,现在的配置文件webpack.config.js如下所示
devServer: {
contentBase: "./", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true //实时刷新
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",
"server": "webpack-dev-server --open"
},
在webpack中实现HMR也很简单,只需要做两项配置
在Webpack Dev Server中添加“hot”参数;
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
function resolve(_path) {
return path.posix.join(__dirname, _path);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: 'assets/js/[name].[hash:7].js'
},
devtool: 'eval-source-map', // source-map
devServer: {
contentBase: "./", //本地服务器所加载的页面所在的目录
port: 8888,
inline: true, //实时刷新
historyApiFallback: true, //不跳转
hot: true // 开启热重载
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: /(node_modules|bower_components)/
}, {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}]
})
}]
},
plugins: [
// js压缩
new webpack.optimize.UglifyJsPlugin(),
// css压缩
new OptimizeCssAssetsPlugin(),
// css分离
new ExtractTextPlugin({
filename: path.posix.join('assets', 'css/[name].[contenthash].css')
}),
// html 编译
new HtmlWebpackPlugin({
filename: 'index.html', //new 目标编译出的文件的文件名
template: 'index.html', //new 编译后的html的路径,相对目录是dist文件夹
inject: true // 是否把js文件插入到body的最后
}),
//热加载插件
new webpack.HotModuleReplacementPlugin(),
],
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
"@": resolve('src'),
"@static": resolve('static')
}
}
};
开发总是离不开调试,方便的调试能极大的提高开发效率,不过有时候通过打包后的文件,你是不容易找到出错了的地方,对应的你写的代码的位置的,Source Maps就是来帮我们解决这个问题的。
通过简单的配置,webpack就可以在打包时为我们生成的source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。
在webpack的配置文件中配置source maps,需要配置devtool,它有以下四种不同的配置选项,各具优缺点,描述如下:
devtool选项 | 配置结果 |
---|---|
source-map | 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包速度; |
cheap-module-source-map | 在一个单独的文件中生成一个不带列映射的map,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便; |
eval-source-map | 使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定不要启用这个选项; |
cheap-module-eval-source-map | 这是在打包文件时最快的生成source map的方法,生成的Source Map 会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点; |
- 正如上表所述,上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的打包速度的后果就是对打包后的文件的的执行有一定影响。
module.exports = {
...
devtool: 'eval-source-map',
...
}
==cheap-module-eval-source-map方法构建速度更快,但是不利于调试,推荐在大型项目考虑时间成本时使用。==
// 定义全局变量
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
_: 'lodash'
}),
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var webpack = require('webpack');
var config = require('../config');
function resolve(url) {
return path.join(__dirname, '..', url);
}
module.exports = {
entry: {
main: resolve('src/main.js')
},
output: {
path: resolve('dist'),
filename: path.posix.join('assets', 'js/[name].js')
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader'
},
}, {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [{
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}]
})
}, {
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [{
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}, {
loader: 'less-loader'
}]
})
}, {
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [{
loader: 'css-loader'
}, {
loader: 'postcss-loader'
}, {
loader: 'less-loader'
}]
})
}, {
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: path.posix.join('assets', 'img/[name].[hash:7].[ext]')
}
}, {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: path.posix.join('assets', 'fonts/[name].[hash:7].[ext]')
}
}]
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
'@static': resolve('static'),
'@cfg': resolve('src/config')
}
}
}
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var webpack = require('webpack');
var merge = require('webpack-merge');
var config = require('../config');
var webpackBaseConfig = require('./webpack.base.conf');
module.exports = merge(webpackBaseConfig, {
devtool: 'eval-source-map', // source-map
plugins: [
new webpack.DefinePlugin({
'process.env': config.build.env
}),
// 定义全局变量
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
_: 'lodash',
bootbox: 'bootbox'
}),
// 编译html
new HtmlWebpackPlugin({
filename: 'index.html', //new 目标编译出的文件的文件名
template: 'index.html', //new 一个这个插件的实例,并传入相关的参数
inject: true // 是否把js文件插入到body的最后
}),
// extra style.css 引入
new ExtractTextPlugin({
filename: path.posix.join('assets', 'css/[name].[contenthash].css')
}),
//热加载插件
new webpack.HotModuleReplacementPlugin()
]
});
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var webpack = require('webpack');
var merge = require('webpack-merge');
var config = require('../config');
var webpackBaseConfig = require('./webpack.base.conf.js');
function resolve(url) {
return path.join(__dirname, '..', url);
}
module.exports = merge(webpackBaseConfig, {
output: {
path: resolve('dist'),
filename: path.posix.join('assets', 'js/[name].[hash:7].js')
},
devtool: '#source-map', // source-map
plugins: [
new webpack.DefinePlugin({
'process.env': config.build.env
}),
// 定义全局变量
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
_: 'lodash',
bootbox: 'bootbox'
}),
new CopyWebpackPlugin([{
from: path.resolve(__dirname, '../static'),
to: path.resolve(__dirname, '../dist/static'),
ignore: ['.*']
}]),
// 编译html
new HtmlWebpackPlugin({
filename: 'index.html', //new 目标编译出的文件的文件名
template: 'index.html', //new 一个这个插件的实例,并传入相关的参数
inject: true // 是否把js文件插入到body的最后
}),
// css压缩
new OptimizeCssAssetsPlugin(),
// js压缩
new webpack.optimize.UglifyJsPlugin(),
// extra style.css 引入
new ExtractTextPlugin({
filename: path.posix.join('assets', 'css/[name].[contenthash].css')
}),
new webpack.BannerPlugin('版权所有,翻版必究'),
]
})
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.prod.config.js",
"dev": "webpack-dev-server --open --inline --config build/webpack.dev.conf.js"
},
process.env.NODE_DEV = 'production';
var rm = require('rimraf');
var ora = require('ora');
var chalk = require('chalk');
var path = require('path');
var webpack = require('webpack');
var webpackProdConfig = require('./webpack.prod.conf.js');
var spinner = ora('building...')
spinner.start()
rm(path.join(__dirname, '../dist'), error => {
if (error) throw error;
webpack(webpackProdConfig, (err, stats) => {
if (err) throw err;
spinner.stop();
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n');
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.cyan(' ##### Build code:' + process.env.ROUTERSOFT_BUILDCODE + '\n'))
});
});