Webpack demistified
https://github.com/lechinoix
Fullstack developer
Use Lean to create better working ways
Love climbing, video games and improving web app performances
Let's roll back in time...
A website kesako?
HTML / CSS / JS
style.css
script.js
And that's it !
Actually that is not, come and see my formation the 27 may at Theodo
How is our website equivalent to this ?
Webpack
A bunch of files
app.js
Entrypoint
// index.js
import Vue from 'vue'
import component from './component'
new Vue({
el: '#app',
components: [component]
})
Output
// app.js
var module = {}
Entrypoint
// index.js
import Vue from 'vue'
import component from './component'
new Vue({
el: '#app',
components: [component]
})
Output
// app.js
var module = {}
// Vue source code is printed here
// Exports are stored in variables
// to be reused
var Vue = ........
module.Vue.export.default = Vue
Entrypoint
// index.js
import Vue from 'vue'
import component from './component'
new Vue({
el: '#app',
components: [component]
})
Output
// app.js
var module = {}
// Vue source code is printed here
// Exports are stored in variables
// to be reused
var Vue = ........
module.Vue.export.default = Vue
// ./component.js
import capitalize from 'capitalize.js'
export default {
template: '<h1>Hello {{ bigName }}</h1>',
props: ['name'],
computed: {
bigName: function() {
return capitalize(name)
}
}
}
Entrypoint
// index.js
import Vue from 'vue'
import component from './component'
new Vue({
el: '#app',
components: [component]
})
Output
// app.js
var module = {}
// Vue source code is printed here
// Exports are stored in variables
// to be reused
var Vue = ........
module.Vue.export.default = Vue
// capitalize source code
var capitalize = .........
module.capitalize.export.default = capitalize
// ./component.js
import capitalize from 'capitalize.js'
export default {
template: '<h1>Hello {{ bigName }}</h1>',
props: ['name'],
computed: {
bigName: function() {
return capitalize(name)
}
}
}
Entrypoint
// index.js
import Vue from 'vue'
import component from './component'
new Vue({
el: '#app',
components: [component]
})
Output
// app.js
var module = {}
module.Vue.export.default = Vue
module.capitalize.export.default = capitalize
// Our code from component.js
var import_1 = module.capitalize.export.default
module.component.export.default = {
template: '<h1>Hello {{ bigName }}</h1>',
props: ['name'],
computed: {
bigName: function() {
return import_1(name)
}
}
}
// ./component.js
import capitalize from 'capitalize.js'
export default {
template: '<h1>Hello {{ bigName }}</h1>',
props: ['name'],
computed: {
bigName: function() {
return capitalize(name)
}
}
}
Entrypoint
// index.js
import Vue from 'vue'
import component from './component'
new Vue({
el: '#app',
components: [component]
})
Output
// app.js
var module = {}
module.Vue.export.default = Vue
module.capitalize.export.default = capitalize
// Our code from component.js
var import_1 = module.capitalize.export.default
module.component.export.default = {...}
// Our code from index.js
var import_1 = module.Vue.export.default
var import_2 = module.component.export.default
new import_1({
el: '#app',
components: [import_2]
})
// ./component.js
import capitalize from 'capitalize.js'
export default {
template: '<h1>Hello {{ bigName }}</h1>',
props: ['name'],
computed: {
bigName: function() {
return capitalize(name)
}
}
}
There is more about this
- Only import module once
- Isolate modules with closure and dependency injection
There is more about this
// app.js
// Our code from index.js
var module1.component.export = function(import_1, import_2) {
var VueInstance = new import_1({
el: '#app',
components: [import_2]
})
return {
default: VueInstance
}
})(module.Vue.export.default, module.component.export.default)
Config
- Entry : List entrypoints with path and names
- Output : Specify the format of the output
- Module.rules : Specify what rules to apply to your modules
- Plugins : Add actions to the build on compiler hooks
- DevServer : Serve assets from a server instead of statically compiling them
Loader
- Export a single function
- Takes the file as text as parameter
- Applies transformations to it
Loader
Rules
Output
// ./compiled/app.js
var module = {}
// Loaded from icon.svg
module.icon.export.default = '/icon.svg'
// Loaded from component.js
var import_1 = module.icon.export.default
module.export.default.component = {
template: '<img :src="icon" />',
data() {
return {
icon: import_1
}
}
}
// ./index.js
import icon from './icon.svg'
export default {
template: '<img :src="icon" />',
data() {
return {
icon
}
}
}
// webpack.config.js
export default {
entry: {
app: './index.js'
},
output: {
path: './compiled',
filename: '[name].js'
},
module: {
rules: [{
match: /\.svg$/,
loader: 'file-loader'
}]
}
}
// ./compiled/icon.svg
<svg>
<fill ... />
</svg>
PublicPath
Output
// ./compiled/app.js
var module = {}
// Loaded from icon.svg
module.icon.export.default =
config.publicPath + '/icon.svg'
// Loaded from component.js
var import_1 = module.icon.export.default
module.export.default.component = {
template: '<img :src="icon" />',
data() {
return {
icon: import_1
}
}
}
// ./index.js
import icon from './icon.svg'
export default {
template: '<img :src="icon" />',
data() {
return {
icon
}
}
}
// webpack.config.js
export default {
entry: {
app: './index.js'
},
output: {
path: './compiled',
filename: '[name].js'
},
module: {
rules: [{
match: /\.svg$/,
loader: 'file-loader'
options: {
publicPath: '/compiled'
}
}]
}
}
// ./compiled/icon.svg
<svg>
<fill ... />
</svg>
Webpack encore (NPM)
- Default configuration
- Customizable with methods
/* global require, __dirname, module */
let Encore = require('@symfony/webpack-encore');
let path = require('path')
const PROJECT_ROOT = path.join(__dirname, '../..')
Encore
// will create public/build/app.js and public/build/app.css
.addEntry('app', [
path.join(PROJECT_ROOT, '/web/js/app.js'),
path.join(PROJECT_ROOT, '/app/Resources/sass/app.scss')
])
// enable source maps during development
.enableSourceMaps(!Encore.isProduction())
// empty the outputPath dir before each build
.cleanupOutputBeforeBuild()
// create hashed filenames (e.g. app.abc123.css)
.enableVersioning(Encore.isProduction())
...
Webpack encore (NPM)
- Default configuration
- Some helpers provided
- Customizable with methods
Webpack encore (Composer)
<!-- base.thml.twig -->
...
{% block javascripts %}
<script src="{{ asset('js/lib/jquery-2.1.4.min.js') }}"></script>
{{ encore_entry_script_tags('app') }}
{% endblock %}
...
# config.yml
...
webpack_encore:
output_path: "%kernel.root_dir%/../web/js/compiled"
builds:
leadformance: "%kernel.root_dir%/../web/js/compiled/leadformance"
<!-- base.thml.twig -->
...
{% block javascripts %}
<script src="/js/lib/jquery-2.1.4.min.js"></script>
<script src="/js/compiled/app.0ea6c7.js"></script>
{% endblock %}
...
<!-- base.thml.twig -->
...
{% block javascripts %}
<script src="{{ asset('js/lib/jquery-2.1.4.min.js') }}"></script>
{{ encore_entry_script_tags('app') }}
{% endblock %}
...
{
"entrypoints": {
"app": {
"css": [
"/js/compiled/app.8b762e.css"
],
"js": [
"/js/compiled/app.0ea6c7.js"
]
}
}
}
Webpack dev server
http://localhost:9001/webpack-dev-server
Questions ?
Webpack demistified
By Nicolas Ngô-Maï
Webpack demistified
- 360