Webpack
ディレクトリ構造全体は
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
// mode: 'production',
// devtool: 'cheap-module-source-map',
entry: {
main: './src/index.js'
},
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}, {
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist']),
new webpack.HotModuleReplacementPlugin()
],
optimization: {
usedExports: true
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
-1 Tree Shaking
math.jsを記述するときに、2つのメソッドを追加し、マイナスをエクスポートしますが、index.jsのみメソッドを追加インポートすると、自動的にコードのマイナスを削除するには、パッケージ化されたファイルがインポートされていないように、ツリーを振ることができますが、開発と生産の2つのモードでは、開発では、わずかな違いがあります。optimization: {usedExports: true}開発モードでは、追加の設定する必要があり、package.jsonの設定 "sideEffects "で:falseは、すべてのツリーを振ることを示し
import '@/babel/polyfill' import '."sideEffects": ['@/babel/polyfill','*.css']/style.css'はそれ自体インポートされないので、Tree Shakingはそれらを完全に無視します。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
// mode: 'production',
// devtool: 'cheap-module-source-map',
...
module: {
...
},
plugins: [
...
],
optimization: {
usedExports: true
},
...
}
// math.js
export const add = (a, b) => {
console.log( a + b );
}
export const minus = (a, b) => {
console.log( a - b );
}
// index.js
// Tree Shaking ES Module
// ES Module下は静的インポート
// CommonJs 下はダイナミックにインポートする
import { add } from './math.js';
add(1, 2);
npm run bundle から得られるバンドルファイルには
export provided: add minus
export used: add
開発モードでは、プロンプトが表示されるだけですが、それでもすべてのコードをパッケージ化します。インポートされていないコードを自動的に削除すると、ソースファイルとパッケージ化されたファイルのsourceMapが一致しなくなる可能性があり、デバッグに不便だからです。
プロダクションモードでは、実際にツリーシェイキングを行うためにsideEffectsを設定するだけです!
-2 development and production
optimization: {usedExports: true}通常、開発環境と生成環境のwebpackの設定は同じではありません。例えば、Tree Shakingの場合、開発環境は設定のみで、devserverも同じですが、devtoolは2つとも同じではありません!
そうすると、パッケージするたびにwebpack.config,jsファイルを手動で変更する必要があります。
// package.json
{
"scripts": {
"dev": "webpack-dev-server --config ./webpack.dev.js",
"build": "webpack --config ./webpack.prod.js"
},
}
また、webpack.dev.jsとwebpack.prod.jsの公開設定をwebpack.common.jsに展開し、新しいビルドフォルダを作成して、buildの下に3つのファイルを配置することで最適化できます。
webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}, {
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
}, {
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist'],{
{
root: path.resolve(__dirname, '../') //アドレスをbuildと同じレベルに変更する
}
})
],
output: {
filename: '[name].js',
// path: path.resolve(__dirname, '../', 'dist') //同じレベルをビルドするためにパッケージファイルのアドレスを生成する
path: path.resolve(__dirname, '../dist') //同じレベルをビルドするためにパッケージファイルのアドレスを生成する
}
}
webpack.dev.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const devConfig = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
optimization: {
usedExports: true
}
}
module.exports = merge(commonConfig, devConfig);
webpack.prod.js
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: 'production',
devtool: 'cheap-module-source-map'
}
module.exports = merge(commonConfig, prodConfig);
// package.json
{
"scripts": {
"dev": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.prod.js"
},
}
開発環境のための npm run dev
npm run build for production
-3 Code Splitting
デフォルトでは、webpackはすべてのモジュールを1つのファイル、例えばmain.jsにパッケージします。
例えばjQueryやlodashなどです。これらのモジュールは別のファイルにパッケージできます。
- 1.手作業による分割
// lodash.js
import _ from 'lodash'
window._ = _
// index.js
console.log(_.join(['a','b','c'],'---'))
そして、前述のようにパッケージングのために複数のエントリを設定し、HtmlWebpackPluginを介してhtmlに2つのファイルを導入することができます。
module.exports = {
entry: {
lodash: './src/lodash.js',
main: './src/index.js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist'],{
{
root: path.resolve(__dirname, '../') //アドレスをbuildと同じレベルに変更する
}
})
],
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../dist') //同じレベルをビルドするためにパッケージファイルのアドレスを生成する
}
}
import _ from 'lodash'同期モジュール
最適化を設定するだけ
// index.js
import _ from 'lodash'
console.log(_.join(['a','b','c'],'---'))
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../')
})
],
optimization: {
splitChunks: {
chunks: 'all'
}
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../dist')
}
}
main.jsとvendor~main.jsをパッケージ化し、htmlに導入します。
- 3.非同期モジュール
// index.js
function getComponent() {
return import('lodash').then(({ default: _ }) => {
var element = document.createElement('div');
element.innerHTML = _.join(['a', 'b', 'c'], '---');
return element;
})
}
getComponent().then(element => {
document.body.appendChild(element);
});
何も設定しなくても、コードは自動的に分割され、新しいファイルmain.jsと0.jsに配置されます。
これはマジックコメントと呼ばれ、生成されるモジュールのファイル名を指定することができます。/* webpackChunkName: "jquery" */マジックコメントを使うには
// .babelrc
{
presets: [
[
"@babel/preset-env", {
targets: {
chrome: "67",
},
useBuiltIns: 'usage'
}
],
"@babel/preset-react"
],
plugins: ["@babel/plugin-syntax-dynamic-import"]
}
-4 Lazy Loading
レイジーローディングはwebpackのコンセプトではなく、ESのコンセプトです。
これは、すべてのコードを一度にロードするタイプです。
// index.js
import _ from 'lodash'
document.addEventListener('click', () => {
var element = document.createElement('div')
element.innerHTML = _.join(['hello', 'world'], '-')
document.body.appendChild(element)
})
以下の非同期コードは、インタフェースをクリックすると、必要なモジュールをロードするために行くでしょう、遅延ロード動作を達成するために書くことができる効果は、ページでは、main.jsの先頭のみがロードされ、その後、ページをクリックすると、loadsh関数にロードされ、文字列のスプライシング処理を実現するために、この関数のメソッドの一部を呼び出すと、最終的にページ上にレンダリングされます。
function getComponent() {
return import(/* webpackChunkName: "lodash" */ 'lodash').then(
({ default: _ }) => {
var element = document.createElement('div')
element.innerHTML = _.join(['hello', 'world'], '-')
return element
}
)
}
document.addEventListener('click', () => {
getComponent().then(element => {
document.body.appendChild(element)
})
})
ES7のasyncとawaitを使えば、上記のコードは次のように書き直せます。
async function getComponent() {
const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash')
const element = document.createElement('div')
element.innerHTML = _.join(['hello', 'world'], '-')
return element
}
document.addEventListener('click', () => {
getComponent().then(element => {
document.body.appendChild(element)
})
})
-5 パッキング分析
まず、package.jsonを変更します。
// package.json
"scripts": {
"dev": "webpack --profile --json > stats.json --config webpack.dev.js"
}
npm run devはstats.jsonを生成します。
-6 preloading prefetching
前面に書き込むと、クロームブラウザは、コードカバレッジを表示する機能があります、つまり、F12をctrl + shift + pの後、コードの使用率を表示するには、カバレッジを入力してください
元のコードから見てみましょう。
// index.js
document.addEventListener('click', () => {
var element = document.createElement('div')
element.innerHTML = 'nice day!'
document.body.appendChild(element)
})
クリック関数のコードはパッケージング後に使用されないので、修正してください。
// index.js
document.addEventListener('click', () =>{
import('./click.js').then(({default: func}) => {
func();
})
});
// click.js
function handleClick() {
const element = document.createElement('div');
element.innerHTML = 'Dell Lee';
document.body.appendChild(element);
}
export default handleClick;
この修正により、コードがより効率的になり、最初の画面ロードの時間が短縮されます。
そのため、webpackがコードをパッケージに分割するように設定されている場合、チャンクのデフォルトは、すべてまたは初期ではなく、非同期です。webpackは、同期コードはキャッシュを増やすことができるだけでなく、そのようなコンポーネントの非同期ロードのみが本当にWebページパッケージのパフォーマンスを向上させることができると考えているため、最初の時間はまだ多くのリソースをロードする必要があり、実際のパフォーマンスの向上は非常に限られています
このビューでは、または非同期ロードできるようにするには、モジュールのコードをロードすることを望むが、非常に遅いロードを恐れています。たとえば、サイトのホームページをロードするときに、非同期にログインモーダルボックスモジュールをロードすることができますが、私はログインをクリックするのが怖い、モーダルボックスモジュールは非常に遅いので、非同期コードプリロードとメインビジネス文書を一緒にロードするプリロードネットワークアイドルがあります。
/* webpackPrefetch: true */
/* webpackPreload: true */
import(/* webpackPrefetch: true */'./click.js')
これは、帯域幅が解放された後、黙ってログインモーダルボックスモジュールのコードのロードのために、両方のホームページのロード高速のニーズを満たすために、ウェブサイトのホームページのロードが完了しているだけでなく、ログインのロード高速のニーズを満たすためにすることができます!





