UNPKG

44.4 kBMarkdownView Raw
1<!-- STOP! Don't edit me. Look at local.gulpfile.js/README.md and build from there. -->
2
3<div align="center">
4
5<!-- Typedocs will have a copy of ./media in its own folder -->
6<img src="media/timpla-logo.png" width="182" height="100" />
7
8Your auntie's favourite asset bundler for [server-side] web frameworks. Provides an optimal web-development experience for TypeScript and/or ESNext.
9
10Powered by gulp 4 & webpack 4.
11
12[![Greenkeeper badge](https://badges.greenkeeper.io/igimanaloto/timpla.svg)](https://greenkeeper.io/)
13[![Build Status](https://travis-ci.org/igimanaloto/timpla.svg?branch=master)](https://travis-ci.org/igimanaloto/timpla)
14[![Coverage Status](https://coveralls.io/repos/github/igimanaloto/timpla/badge.svg)](https://coveralls.io/github/igimanaloto/timpla)
15[![npm version](https://badge.fury.io/js/timpla.svg)](https://badge.fury.io/js/timpla)
16
17</div>
18
19- [Getting started](#getting-started)
20 - [Installation](#installation)
21 - [The Timpla-way of thinking](#the-timpla-way-of-thinking)
22 - [Commands](#commands)
23 - [Debugging](#debugging)
24 - [Influence](#influence)
25- [Configuring Timpla](#configuring-timpla)
26 - [List of available options](#list-of-available-options)
27 - [The timplaHelper object](#the-timplahelper-object)
28 - [Specifying a config file on runtime](#specifying-a-config-file-on-runtime)
29 - [Overriding babel & babel-loader options](#overriding-babel---babel-loader-options)
30 - [Configuring Webpack](#configuring-webpack)
31 - [Overriding tasks](#overriding-tasks)
32 - [TypeScript](#typescript)
33 - [Disabling TypeScript / TSLint](#disabling-typescript---tslint)
34 - [ESLint](#eslint)
35 - [Disabling ESLint](#disabling-eslint)
36- [The three levels of reloading](#the-three-levels-of-reloading)
37 - [BrowserSync injection and reloading](#browsersync-injection-and-reloading)
38 - [Hot module reloading + React HMR](#hot-module-reloading---react-hmr)
39 - [Dev-server reloading based on config file changes](#dev-server-reloading-based-on-config-file-changes)
40- [Common setups](#common-setups)
41 - [Using Timpla as a static html workflow](#using-timpla-as-a-static-html-workflow)
42 - [Using Timpla with an existing site (Proxy option)](#using-timpla-with-an-existing-site--proxy-option-)
43 - [Replacing the html task with Shopify Liquid templating](#replacing-the-html-task-with-shopify-liquid-templating)
44- [Common Problems](#common-problems)
45 - [I'm getting a different version of dependency X when I use Timpla!](#i-m-getting-a-different-version-of-dependency-x-when-i-use-timpla-)
46 - [Timpla doesn't pick up changes to my eslintrc](#timpla-doesn-t-pick-up-changes-to-my-eslintrc)
47 - [When I build, javascript files don't work!](#when-i-build--javascript-files-don-t-work-)
48 - [process.cwd() isn't working as it's supposed to!](#processcwd---isn-t-working-as-it-s-supposed-to-)
49 - [Tips for working with npm linked dependencies](#tips-for-working-with-npm-linked-dependencies)
50- [CAQIAs (Commonly asked questions I ask)](#caqias--commonly-asked-questions-i-ask-)
51- [Developing the plugin](#developing-the-plugin)
52- [Releasing the plugin](#releasing-the-plugin)
53
54## Getting started
55
56Timpla aims is to provide you with an excellent web development experience. Timpla focuses on the truly defined parts in every build process: preparing javascript, css and media files for your websites. Three layers of reloading power Timpla: CSS-injection/reloading via BrowserSync (proxy or server), Webpack JS/TS Hot Module Reloading and full dev-server reloads based on core config changes.
57
58Unlike a `boilerplate` or a `full-blown` development framework, the rational behind Timpla is that of guiding users with an undiscriminating base. You bring your own dependencies to enhance and/or extend the core Timpla build pipeline.
59
60Timpla maintains its own side of the fence, while you focus on the more important aspects of your workflow, or better yet - getting straight into work!
61
62You may wonder why bother with Timpla if Webpack does everything. Timpla by no means undermines what Webpack is already able to achieve! However, in our quest to find a sweet development environment, we've come to realise that forcing everything through Webpack yields painful load and reload times. Timpla's performance and tooling in a decently sized project is something we're proud of!
63
64<!-- Typedocs will have a copy of ./media in its own folder -->
65<img src="media/timpla-sample.jpg" />
66
67### Installation
68
69We recommend that you install Timpla as a whole first first, and removing bits that you do not need. See [Configuring Timpla](#configuring-timpla) for more info.
70
71```sh
72# Base install
73npm i --save-dev timpla webpack @babel/core
74
75# Run these too to get Timpla up and running after npx timpla init.
76# The dependencies below are for extending Timpla to have both
77# TypeScript and Javascript running in parallel.
78# Each of the dependencies here are removeable, so we recommend
79# installing the whole bunch first to see how everything works.
80# Slim it down afterwards based on your requirements!
81npm i --save-dev react react-dom react-hot-loader prettier @babel/preset-env @babel/polyfill @babel/preset-typescript @babel/preset-react eslint eslint-loader babel-eslint eslint-config-prettier eslint-plugin-react tslint-config-prettier typescript tslint tslint-react @types/react @types/react-dom webpack-bundle-analyzer hard-source-webpack-plugin fork-ts-checker-webpack-plugin speed-measure-webpack-plugin
82
83# Initialise timpla
84# Careful: outputs config files and a starter src directory:
85# babel.config.js
86# .eslintrc
87# tsconfig.json
88# tslint.json
89# .prettierrc
90# .timplaconfig.js
91npx timpla init
92
93# Start the dev-server
94npx timpla
95
96# Build all asset files
97npx timpla build
98```
99
100### The Timpla-way of thinking
101
102Timpla is a process-driven tool. Each `asset stream` holds a pre-defined and parallelised part in the Timpla build chain. The following assets are built in parallel:
103
104- `Sass` files are compiled into css files, so you may load it as normal in your templates.
105- `SVG` files are combined into single-svgs for use, either via direct insertion into your templates, or your javascript-driven loading.
106- `Image` and `static` asset files are simply copied, but the processes are extendible, wherein you can tap into the build-stream and introduce your own pre-processing tasks.
107- `Javascript and/or Typescript` files bundled using Webpack.
108- Useful tooling such as file size reports, file-revving, bundle analysis and Webpack performance measurements are made available to further enhance your development process.
109
110In every dev or production build, `prebuild` and `postbuild` hooks are available for you to enhance the Timpla process. Apart from the javascript task, you may replace how each asset-type is processed via Timpla's alternateable tasking system.
111
112Timpla also allows you to register extra tasks via Gulp. These may be added to the pre or post parts of the build process.
113
114Timpla nukes the `destination` folder for every dev or production start. This ensures that you treat the `src` directory as the one true source for raw source files.
115
116### Commands
117
118```sh
119# Timpla starts the development server by default (npx timpla)
120npx timpla [command]
121
122[command]
123init # inits timpla (copies initial src and config files to project root)
124initConfig # recreates the .timplaconfig.js file in the project root
125build # outputs build files
126clean # cleans the dest directory
127javascripts # builds js and ts files
128rev # revs files and outputs a manifest file (designed for html/basic use-cases only)
129sizeReport # shows a file sizes report
130svg # combines svg files into one
131stylesheets # transpiles sass/scss files to css
132openAnalyzer # opens the bundle analyzer (run this after a build)
133fonts # copies files from font src to dest
134images # copies files from images src to dest
135staticFiles # copies files from static src to dest
136html # copies files from html src to dest
137```
138
139These will be available as `npx timpla [yourcustomtask]`.
140
141You can also set up npm scripts to simplify the commands:
142
143```json
144# You package.json file
145{
146 "scripts": {
147 "build": "timpla build",
148 "start": "timpla",
149 "tasks": "npx timpla --tasks"
150 }
151}
152```
153
154### Debugging
155
156Enable verbose logs by running any timpla command with env DEBUG=timpla:
157
158```sh
159DEBUG=timpla timpla [command]
160```
161
162To view a breakdown of plugin / loader times, you may also enable it by setting MEASURE=1:
163
164```sh
165MEASURE=1 timpla [command]
166```
167
168This is done through `speed-measure-webpack-plugin`, so you'll need to have that installed in your project. ForkTS Checker breaks when this is run along-side it, so we have decided not to make it separate from the rest of the debug process. Follow the [issue here](https://github.com/stephencookdev/speed-measure-webpack-plugin/issues/56).
169
170### Influence
171
172Server-side frameworks like Django, Rails, Craft, Wordpress and Laravel come with templating engines that require access to static assets.
173
174Timpla brings back the ol' 'just-output-built-files' approach to asset bundling.
175
176This plugin provides a drop-in asset bundling system to complement your favourite server-side framework. It streamlines your build and development processes through the following features:
177
178- Bundling JS/TS via Webpack
179- On-screen ESLint and/or TSLint feedback
180- Compiling sass and scss files
181- Bundling svgs via SVGStore
182- Copying static fonts, images and other files, with support for extending their workflows.
183- Live-reloading via browsersync and webpack hmr (dev), with support for React Hot Module reloading
184
185To be exact, Timpla uses the following technologies:
186
187- Gulp
188- Webpack
189- BrowserSync
190- Node-sass
191- Babel
192- SVGStore
193- ESLint (dev-only)
194- TypeScript
195- TSLint (dev-only)
196
197Timpla also provides TSLint and ESLint support for development-mode. Having errors on an overlay are helpful! On production builds, Timpla disables these to speed up compilation times. Please use an alternative process for production builds, if you wish to lint files.
198
199Timpla started as a fork of [Blendid](https://github.com/vigetlabs/blendid), and continues to carry the torch for providing awesome server-side-driven dev experiences.
200
201## Configuring Timpla
202
203One of Timpla's aims is to be zero-configuration. By default, Timpla is set to run in HTML mode and displays an html page. Browsersync may be used to `mount` on top of your existing project.
204
205The most basic Timpla configuration follows:
206
207<!-- inject:timpla_config_basic:js -->
208```javascript
209// @ts-check
210
211/**
212 * The @type annotations are harmless, vscode might just make your life easier
213 * by adding intellisense support whilst you type!
214 */
215
216const { configure } = require('timpla')
217
218module.exports = configure({
219 javascripts: {
220 /** @type { import("timpla").ITimplaWebpackEntryHook } */
221 entry: ({ resolve: r }) => ({
222 'js-index': r('./js-index.jsx'),
223 'ts-index': r('./ts-index.tsx'),
224 'ts-error': r('./ts-error.ts'),
225 }),
226
227 /** @type { import("timpla").ITimplaCustomizeWebpackConfig } */
228 customizeWebpackConfig(w) {
229 // The following helpers are available to aid you in extending the webpack config.
230 const {
231 projectDestPath,
232 projectSrcPath,
233 timplaConfig,
234 timplaProcess,
235 webpack,
236 webpackConfig,
237 webpackMerge,
238 } = w
239 return w.webpackConfig
240 },
241 },
242
243 // To get intellisense for more complex configs, follow the jsdoc example below:
244 // html: {
245 // /** @type { import("timpla").ITimplaHofTask } */
246 // alternate: p => {
247 // p.timplaProcess
248 // },
249 // },
250
251 // additionalTasks: {
252 // /** @param p { import("timpla").ITimplaHelper } */
253 // initialize: p => {},
254 // development: {
255 // /** @type { import("timpla").ITimplaHofTask } */
256 // prebuild(tp) {},
257 // },
258 // },
259})
260
261```
262<!-- endinject -->
263
264Tasks such as html, static and images copy files from the src to the dest folder. Use the `alternate` option to define processing logic. To keep Timpla light, no preprocessing happens for image and other static files. It is left to you to add your preferred workflows. (see alternate configs for reach of the asset tasks below)
265
266Full configuration is available through `.timplaconfig.js`. You'll get a copy in your project's root folder after running `npx timpla init`.
267
268Timpla exports a helper function called `configure`. Use this to create a timplaconfig object in your `.timplaconfig.js`. As an added benefit, your IDE's intellisense should suggest what options are available!
269
270### List of available options
271
272[Full TS documentation](https://igimanaloto.github.io/timpla/interfaces/_lib_timplainterfaces_.ifulltimplaconfig.html) of the timpla config object is available for viewing. An excerpt of the full timpla config follows:
273
274<!-- inject:timpla_config:ts -->
275```typescript
276
277export interface IFullTimplaConfig {
278 /** The base folder to include for compilation. Defaults to `./src`. */
279 src: string
280 /** The base folder to output bundled files to. Defaults to `./dest`. */
281 dest: string
282 /*
283 * Instructs timpla on how to run the staticFiles task.
284 * Set to `false` to disable the task.
285 */
286 staticFiles:
287 | false
288 | {
289 /** The folder to include for compilation. Defaults to `static`. */
290 src: string
291 /** The folder to output bundled files to. Defaults to `./`. */
292 dest: string
293 /** Options to pass to the gulp src task. This setting is ignored when an alternate task is provided. */
294 srcOptions: SrcOptions
295 /** Options to pass to the gulp dest task. This setting is ignored when an alternate task is provided. */
296 destOptions: DestOptions
297 /** A custom task to override the default with. */
298 alternate?: ITimplaHofTask
299 }
300 /**
301 * Instructs timpla on how to run the clean task.
302 * Set to `false` to disable the task.
303 */
304 clean:
305 | false
306 | {
307 /**
308 * Extra files and folders to `clean` before Timpla runs the dev-server or full-build.
309 * `Please take great care when specifying your own patterns`
310 * Accepts an array of globs. Defaults to the project `dest` directory.
311 */
312 patterns?: string | ReadonlyArray<string>
313 /** Options to pass to the del function. */
314 delOptions: Options
315 }
316
317 /** Watch task options */
318 watch: {
319 /**
320 * Gulp watch options.
321 * Accepts gulp watch options for all tasks,
322 * or a keyed-list of watch-options to apply to tasks individually.
323 * - E.g. gulpWatch.svg = {} sets specific configs for the svg task.
324 */
325 gulpWatch: {
326 [name: string]: any
327 }
328 }
329
330 /**
331 * Instructs timpla on how to run the stylesheets task.
332 * Set to `false` to disable the task.
333 */
334 stylesheets:
335 | false
336 | {
337 /** The folder to include for compilation. Defaults to `stylesheets`. */
338 src: string
339 /** The folder to output bundled files to. Defaults to `stylesheets`. */
340 dest: string
341 /** Options to pass to the gulp src task. This setting is ignored when an alternate task is provided. */
342 srcOptions: SrcOptions
343 /** Options to pass to the gulp dest task. This setting is ignored when an alternate task is provided. */
344 destOptions: DestOptions
345 /** [Cssnano](https://www.github.com/cssnano/cssnano) options */
346 cssnanoOptions: CssNanoOptions
347 /** [Autoprefixer](https://github.com/postcss/autoprefixer#options) options */
348 autoprefixerOptions: autoprefixer.Options
349 /** [PostCSS](https://github.com/postcss/postcss#options) options */
350 postcssOptions: postcss.ProcessOptions
351 /** [Gulp/Node sass](https://www.npmjs.com/package/gulp-sass) options */
352 sassOptions: INodeSassOptions
353 /** A list of extensions for BrowserSync to watch. Defaults to `['sass', 'scss', 'css']`. */
354 extensions: string[]
355 /** Development-specific stylesheets options */
356 development: {
357 /** Defaults to `true`. */
358 sourceMap: boolean
359 }
360 /** Production-specific stylesheets options */
361 production: {
362 /** Defaults to `false`. */
363 sourceMap: boolean
364 }
365 /** A custom task to override the default with. */
366 alternate?: ITimplaHofTask
367 }
368 /**
369 * Instructs timpla on how to run the fonts task.
370 * Set to `false` to disable the task.
371 */
372 fonts:
373 | false
374 | {
375 /** The folder to include for compilation. Defaults to `fonts`. */
376 src: string
377 /** The folder to output bundled files to. Defaults to `fonts`. */
378 dest: string
379 /** Options to pass to the gulp src task. This setting is ignored when an alternate task is provided. */
380 srcOptions: SrcOptions
381 /** Options to pass to the gulp dest task. This setting is ignored when an alternate task is provided. */
382 destOptions: DestOptions
383 /** A list of extensions for BrowserSync to watch. Defaults to `['woff2', 'woff', 'eot', 'ttf', 'svg']`. */
384 extensions: string[]
385 /** A custom task to override the default with. */
386 alternate?: ITimplaHofTask
387 }
388 /**
389 * Instructs timpla on how to run the images task.
390 * Set to `false` to disable the task.
391 */
392 images:
393 | false
394 | {
395 /** The folder to include for compilation. Defaults to `images`. */
396 src: string
397 /** The folder to output bundled files to. Defaults to `images`. */
398 dest: string
399 /** Options to pass to the gulp src task. This setting is ignored when an alternate task is provided. */
400 srcOptions: SrcOptions
401 /** Options to pass to the gulp dest task. This setting is ignored when an alternate task is provided. */
402 destOptions: DestOptions
403 /** A list of extensions for BrowserSync to watch. Defaults to `['jpg', 'png', 'svg', 'gif']`. */
404 extensions: string[]
405 /** A custom task to override the default with. */
406 alternate?: ITimplaHofTask
407 }
408 /**
409 * Instructs timpla on how to run the svg task.
410 * Set to `false` to disable the task.
411 */
412 svg:
413 | false
414 | {
415 /** Options for the gulp-svg plugin. */
416 svgstore: IGulpSvgStore
417 /** The output filename for the concatanted svg file. Defaults to `icons.svg`. */
418 outputName: string
419 /** The folder to include for compilation. Defaults to `svg`. */
420 src: string
421 /** The folder to output bundled files to. Defaults to `images`. */
422 dest: string
423 /** Options to pass to the gulp src task. This setting is ignored when an alternate task is provided. */
424 srcOptions: SrcOptions
425 /** Options to pass to the gulp dest task. This setting is ignored when an alternate task is provided. */
426 destOptions: DestOptions
427 /** A custom task to override the default with. */
428 alternate?: ITimplaHofTask
429 }
430 /**
431 * Instructs timpla on how to run the html task.
432 * Set to `false` to disable the task.
433 */
434 html:
435 | false
436 | {
437 /** The folder to include for compilation. Defaults to `html`. */
438 src: string
439 /** The folder to output bundled files to. Defaults to ``. */
440 dest: string
441 /** Options to pass to the gulp src task. This setting is ignored when an alternate task is provided. */
442 srcOptions: SrcOptions
443 /** Options to pass to the gulp dest task. This setting is ignored when an alternate task is provided. */
444 destOptions: DestOptions
445 /** A custom task to override the default with. */
446 alternate?: ITimplaHofTask
447 }
448 /**
449 * Instructs timpla on how to run the javascripts task.
450 */
451 javascripts: {
452 /** The folder to include for compilation. Defaults to `javascripts`. */
453 src: string
454 /** The folder to output bundled files to. Defaults to `javascripts`. */
455 dest: string
456 /** A list of extensions for BrowserSync to watch and Webpack to load. Defaults to `['js', 'jsx', 'ts', 'tsx']`. */
457 extensions: string[]
458 /**
459 * The webpack entry config.
460 * Accepts a Timpla-flavoured entry function or a webpack entry object.
461 * Webpack is configured to use the projectRoot as the cwd.
462 * Files you point in the entry config need to have the relative path to the javascripts folder.
463 * Use the `resolve` helper to resolve files to the js src folder.
464 */
465 entry: ITimplaWebpackEntry
466 /**
467 * Instructs webpack the base path for all the assets within your application.
468 * Defaults to the `javascripts.dest` path. e.g. `/javascripts`
469 */
470 publicPath?: string
471 /**
472 * Options for the babelLoader. Accepts babel-loader specific as well as Babel options.
473 * For more advanced use-cases, e.g. manually specifying the babel config file to use.
474 * Defaults to
475 * - `cacheDirectory: true`
476 * - `cacheCompression: false`
477 * - `root: your project root`
478 */
479 babelLoaderOptions: IBabelLoaderOptions
480 /**
481 * Accepts [webpackBundleAnalyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) options.
482 * Set to `false` to disable webpackBundleAnalyzer.
483 * Defaults to
484 * - `statsFilename: timpla-webpack-stats.json`
485 * - `openAnalyzer: true if Timpla hasn't fully reloaded.`
486 */
487 webpackBundleAnalyzerOptions: false | BundleAnalyzerPlugin.Options
488 /**
489 * A customisation function that allows modifying the generated
490 * webpack config before it is passed to webpack.
491 */
492 customizeWebpackConfig: ITimplaCustomizeWebpackConfig
493
494 /** Instructs timpla on how Webpack should run in dev-mode. */
495 development: {
496 /**
497 * The webpack devtool to use.
498 * Defaults to `cheap-module-eval-source-map`.
499 */
500 devtool: webpack.Options.Devtool
501 /**
502 * Accepts [Webpack Hot Middleware](https://github.com/webpack-contrib/webpack-hot-middleware) options.
503 * Set to `false` to disable [hot module reloading](https://webpack.js.org/concepts/hot-module-replacement/).
504 * Defaults to
505 * - `reload: true`
506 * - `quiet: true`
507 */
508 webpackHotMiddlewareOptions: IWebpackHotMiddlewareOptions | false
509 /**
510 * In dev-mode, Timpla supports ESLint via the ESLint loader.
511 * By default, Timpla requires the eslint package to be installed.
512 * - `npm i --save-dev eslint`
513 * - Set to `false` to disable ESLint.
514 */
515 eslint: {
516 /*
517 * Accepts [eslint-loader](https://github.com/webpack-contrib/eslint-loader) & [eslint](http://eslint.org/docs/developer-guide/nodejs-api#cliengine) options.
518 */
519 esLintLoaderOptions: IESLintLoaderOptions
520 }
521 /**
522 * In dev-mode, Timpla uses Fork TS Checker, a webpack plugin that runs typescript export type checker on a separate process.
523 * By default, Timpla requires dependent packages to be installed.
524 * - `npm i --save-dev typescript tslint fork-ts-checker-webpack-plugin`
525 * - Set to `false` to disable the plugin, and TSLint support.
526 */
527 tslint:
528 | {
529 /** Accepts [Fork TS Checker](https://github.com/Realytics/fork-ts-checker-webpack-plugin) options. */
530 forkTsCheckerOptions: IForkTsCheckerOptions
531 }
532 | false
533 }
534
535 /**
536 * Instructs timpla on how to run Webpack in production.
537 */
538 production: {
539 /**
540 * The webpack devtool to use.
541 * Defaults to `source-map`.
542 */
543 devtool: webpack.Options.Devtool
544 /**
545 * Timpla uses Hard Source to improve production build times.
546 * Set to `false` to disable the plugin.
547 * Accepts [hard-source-webpack-plugin](https://github.com/mzgoddard/hard-source-webpack-plugin) options.
548 */
549 hardSourceOptions: false | IHardSourceWebpackPluginOptions
550 /**
551 * [Terser Webpack Plugin](https://github.com/webpack-contrib/terser-webpack-plugin) options.
552 * Timpla uses Terser to uglify the bundled JS files.
553 * UglifyJS2 is outdated, and Terser is its successor.
554 */
555 terserConfig: Partial<{}>
556 }
557 }
558
559 /**
560 * Configures the BrowserSync task.
561 * Accepts [browser-sync](https://browsersync.io/docs/options) options.
562 *
563 * May also be used to individually `disable` the default
564 * middleware added to proxy and server modes via middlewareConfig:
565 * - webpackDevMiddleware - disableDev
566 * - webpackHotMiddleware - disableHot
567 * - historyApiFallback - disableSpa
568 *
569 * Set proxy/server.middleware to `false` to disable middleware.
570 */
571 browserSync: ITimplaBrowserSyncOptions
572
573 /** Instructs Timpla on after-build tasks. */
574 production: {
575 /**
576 * Opens a specified target in an app after all the core-tasks run.
577 * Uses the opn package to achieve this.
578 * Defaults to `false`.
579 */
580 open: false | IOpenOptions
581 /**
582 * Enables file-reving (hashed filenames).
583 * Timpla revs your files and generates a json manifest file.
584 * You'll need to write your own mapper to pick up the filenames from the rev manifest file.
585 * Defaults to `false`.
586 */
587 rev: boolean
588 }
589
590 /** Instructs Timpla on post-dev-launch tasks. */
591 development: {
592 /**
593 * Opens a specified target in an app after all the core-tasks run.
594 * Uses the opn package to achieve this.
595 * Defaults to `false`.
596 */
597 open: false | IOpenOptions
598 /**
599 * Extra files and folders for Timpla to watch.
600 * When these change, Timpla reloads the dev-server.
601 * Set to `false` to disable this option.
602 * Defaults to `true`.
603 */
604 timplaWatch: boolean | string[]
605 }
606
607 /** Instructs Timpla on additional tasks */
608 additionalTasks: {
609 /** An init function that runs before all the other Timpla. */
610 initialize?: (timplaHelper: ITimplaHelper) => any
611 /** Instructs Timpla to add extra `development tasks`. */
612 development: {
613 /** Adds an extra development `prebuild task`. Accepts a `higher-order-function`, i.e. returns a Gulp/Undertaker TaskFunction. */
614 prebuild?: ITimplaHofTask
615 /** Adds an extra development `postbuild task`. Accepts a `higher-order-function`, i.e. returns a Gulp/Undertaker TaskFunction. */
616 postbuild?: ITimplaHofTask
617 }
618 /** Instructs Timpla to add extra `production tasks`. */
619 production: {
620 /** Adds an extra production `prebuild task`. Accepts a `higher-order-function`, i.e. returns a Gulp/Undertaker TaskFunction. */
621 prebuild?: ITimplaHofTask
622 /** Adds an extra production `postbuild task`. Accepts a `higher-order-function`, i.e. returns a Gulp/Undertaker TaskFunction. */
623 postbuild?: ITimplaHofTask
624 }
625 }
626}
627
628/** The partialised Timpla Config so users' may opt in to only customise what they wish to. */
629export type ITimplaConfig = IRecursivePartial<IFullTimplaConfig>
630
631```
632<!-- endinject -->
633
634### The timplaHelper object
635
636The following variables are available from the timplaHelper
637
638```javascript
639const timplaHelper = {
640 browserSync, // Access the browserSync instance.
641 gulp, // A gulp instance that can be used to register new tasks.
642 projectDestPath, // Resolves a list of strings to the project's dest path.
643 projectSrcPath, // Resolves a list of strings to the project's src path.
644 timplaConfig, // The full timplaConfig
645 timplaProcess, // Provides useful constants such as isDevelopment, isProduction and INIT_CWD (your project's resolved base path).
646}
647```
648
649### Specifying a config file on runtime
650
651To specify a timpla config on runtime, you may set the TIMPLA_CONFIG_FILE env like so:
652
653`TIMPLA_CONFIG_PATH='./relative/path/to/file' npx timpla [command]`
654
655### Overriding babel & babel-loader options
656
657You may use javascripts.babelLoaderOptions to fully control how the webpack babel-loader works.
658
659Babel config resolution is set to default, so babel.config.js and babelrc files are picked up by Timpla. We recommend using babel.config.js as opposed to a babelrc so that npm linked modules are also picked up by babel-loader, via Babel's root config resolution mechanism.
660
661Timpla copies the following babel config file to your project folder. (babel.config.js) and pre-configures your .timplaconfig.js to pick this up.
662
663<!-- inject:babel:js -->
664```javascript
665const debug = process.env.DEBUG === 'timpla'
666const isProduction = process.env.NODE_ENV === 'production'
667
668module.exports = {
669 presets: [
670 [
671 '@babel/preset-env',
672 {
673 // usage automatically injects @babel/polyfill, so older browsers may still work
674 // see https://babeljs.io/docs/en/babel-polyfill
675 // We're only loading this for production builds so development compilation times are faster!
676 ...(isProduction && { useBuiltIns: 'usage' }),
677 debug,
678 },
679 ],
680 '@babel/preset-typescript',
681 '@babel/preset-react',
682 ],
683 plugins: ['react-hot-loader/babel'],
684}
685
686```
687<!-- endinject -->
688
689### Configuring Webpack
690
691Webpack by default uses the following plugins (module.rules):
692
693```sh
694# HardSourceWebpackPlugin - disabled for now, as caching may break babel-loader 7.2 builds.
695TerserPlugin # uglifies/minifies code
696SpeedMeasurePlugin # Shows a useful breakdown of Webpack compilation speed. Runs when DEBUG=timpla is set.
697ForkTsCheckerWebpackPlugin # creates a forked (separated) TSLint server to run alongside Timpla
698BundleAnalyzerPlugin # provides a visual report of js bundle sizes
699```
700
701Each of these plugins are configurable/can be disabled. For example, javascripts.tslint.forkTsCheckerOptions accepts ForkTsCheckerWebpackPlugin configuration options.
702
703In certain scenarios, Timpla lazy-loads plugins. This gives you the flexibility to `remove` packages that you don't need :). For example, setting javascripts.tslint to false disables tslint and loading the module itself. As a result, you may remove tslint and ForkTsCheckerWebpackPlugin from your dependencies.
704
705Webpack also uses the following loaders:
706
707```
708babel-loader (ESNext and TypeScript support)
709eslint-loader (dev-only)
710```
711
712You have access to the full webpack configuration before it gets fed to Webpack itself. This way, you can add extra loaders you wish to use. Please use the javascripts.customizeWebpackConfig rule in .timplaconfig.js. It accepts a function that returns a configuration object:
713
714```javascript
715// .timplaconfig.js
716{
717 // ... the rest of your config file
718 javascripts: {
719 customizeWebpackConfig({
720 webpackConfig,
721 timplaConfig,
722 timplaProcess,
723 webpack,
724 projectDestPath,
725 projectSrcPath,
726 webpackMerge
727 }) => {
728 const modifiedConfig = { ...webpackConfig }
729 // You can modify the config to how you want it
730
731 // check if it's prod or development
732 if (timplaProcess.isProduction) {
733 // do this;
734 }
735 if (timplaProcess.isDevelopment) {
736 // do this
737 }
738
739 // or even modify rules & plugins...
740 modifiedConfig.plugins = modifiedConfig.plugins.filter(yourFilterFunction)
741 modifiedConfig.module.rules.push(yourOwnRule)
742
743 // or with the webpack merge plugin, you can even do a webpackMerge(webpackConfig, require('./yourOverrides'))
744
745 return modifiedConfig
746 }
747 }
748}
749```
750
751### Overriding tasks
752
753You may overwrite any listed tasks with an alternate option. Please provide a higher order function (a function returning a function) that accepts a timplaHelper object. You may use these to help write the tasks. The higher order function should signal gulp completion: either through a manual callback call or by returning a gulp stream. If in doubt, always return an Undertaker TaskFunction!
754
755A contrived example follows.
756
757```javascript
758{
759 // ... the rest of your timpla config
760 stylesheets: {
761 // ... the rest of your stylesheets config
762 alternate({
763 browserSync,
764 gulp,
765 projectDestPath,
766 projectSrcPath,
767 timplaConfig,
768 timplaProcess,
769 }){
770 const stylesheetsConfig = timplaConfig.stylesheets // access the stylesheets config
771 const paths = {
772 src: projectSrcPath(stylesheetsConfig.src, '**/*.{' + stylesheetsConfig.extensions + '}'),
773 dest: projectDestPath(stylesheetsConfig.dest),
774 }
775
776 // We must return a higher order function
777 return (cb) => {
778 // if gulp is not being used, cb can be used to call signal completion
779 // dosomethingElse();
780 // cb()
781
782 // We can also return a gulp stream instead
783 return gulp
784 .src(paths.src) // finds [your-project]/stylesheets/something.txt
785 .pipe(yourOwnSassProcesser())
786 .pipe(gulp.dest(paths.dest)) // transfers the file to [your-project]/stylesheets/somethingelse.txt
787 .pipe(browserSync.stream()) // streams changes to browserSync
788 }
789 }
790 }
791}
792```
793
794### TypeScript
795
796By default TypeScript and TSLint are enabled. TypeScript functionality is provided through babel-loader and @babel/preset-typescript. TSLint is enabled by default for development mode.
797
798Timpla uses babel-loader with @babel/preset-typescript and [Fork TS Checker Webpack Plugin](https://github.com/Realytics/fork-ts-checker-webpack-plugin) to process TypeScript files. To improve compilation times, Timpla utilises the Fork TS Checker Webpack Plugin to create a separate linting process for TypeScript. Any linting errors won't block the webpack compilation process but will display either in the console or as an overlay on the web page.
799
800For production builds, TSLint is disabled. We've found that it is better to run TSLint as a separate production process.
801
802### Disabling TypeScript / TSLint
803
804If you followed the installation instructions above, please uninstall the following packages: `fork-ts-checker-webpack-plugin`, `tslint`, and `typescript`. Remove @babel/preset-typescript from babel.config.js. Finally, set javascripts.development.tslint to false.
805
806### ESLint
807
808ESLint is enabled for dev-mode. Timpla requires you to have an eslintrc file in your project directory, as well the eslint-loader package installed. Eslintrc resolution is left to the eslint-loader plugin, which means that it should pick up child-dir eslintrc files.
809
810### Disabling ESLint
811
812Set javascripts.development.eslint to false if you don't require it. As eslint-loader is loaded conditionally, you may uninstall it if you don't require eslint.
813
814## The three levels of reloading
815
816### BrowserSync injection and reloading
817
818Timpla uses BrowserSync to inject stylesheets and notify the browser of full-reloads when files change. Timpla pre-configures the watched files for you, but you may also extend it through the `files: [globs]` config.
819
820```javascript
821module.exports = {
822 browserSync: {
823 files: ['when_this_changes_reload_the_page/**/*'],
824 },
825}
826```
827
828When writing your own tasks, Timpla Helper passes the browserSync instance so you may stream(inject) your changes on the fly!
829
830### Hot module reloading + React HMR
831
832Any files you mark as hot won't cause the browser to reload. This is useful when you need to keep the browser in its current state.
833
834Hot module reloading is enabled by default. Setting `javascripts.development.webpackHotMiddlewareOptions` to `false` disables it.
835
836To support react hot module reloading, please install and add `react-hot-loader/babel` to your `babel.config.js`'s plugins. This should be fine even for production builds, as react-hot-loader adds minimal footprint to your code.
837
838#### Dev-server reloading based on config file changes
839
840Timpla fully reloads the dev-server whenever your config files such as babel config, tsconfig, tslint and eslint files change. This saves you the hassle of having to restart just to test configuration settings!
841
842You may also extend the watched files/folders by adding them to .timplaconfig.js > development.timplaWatch. Timpla iterates through these files and sets up reload watchers. You may provide resolved or relative paths.
843
844Setting `development.timplaWatch` to `false` disables the reload server.
845
846## Common setups
847
848### Using Timpla as a static html workflow
849
850Out of the box, Timpla is configured to serve an html page.
851
852### Using Timpla with an existing site (Proxy option)
853
854More often than never, server-side frameworks run your site on localhost (or a locally configured server). Timpla can mount on your site through BrowserSync's proxy option.
855
856To use timpla with an existing site, you may follow the sample browsersync config below. You run your server-side framework and Timpla in a separate process. Use the browserSync option in .timplaconfig.js to set BrowserSync options - it accepts a configuration object. An example of getting it to work with Django/Rails/Laravel follows:
857
858```javascript
859// .timplaconfig.js
860const { configure } = require('timpla')
861const path = require('path')
862
863// You would most probably want to react to template changes, you may set extra folders here (relative)
864const extraWatchFiles = ['templates/**/*']
865
866// The local instance of your site that Timpla will proxy to
867const proxyTarget = 'http://127.0.0.1:7025'
868
869// Access the site via localhost:localhostPort
870const localhostPort = 5605
871
872// If you are using nginx/htaccess to point a host to a local port
873// This is useful if CORS headers are set on your local site resources (CDN)
874const host = 'http://local-new.grabone.co.nz'
875
876module.exports = configure({
877 browserSync: {
878 proxyTarget,
879 files: extraWatchFiles,
880 port: localhostPort,
881 cors: true,
882 proxy: {
883 target: proxyTarget,
884 proxyReq: [
885 // Additional request headers may be added here
886 function(proxyReq) {
887 proxyReq.setHeader('host', host.replace(/^https?:\/\//i, ''))
888 // grabone authentication requires proper host header to be set
889 proxyReq.setHeader('Access-Control-Allow-Origin', '*')
890 },
891 ],
892 },
893 files: files.map(fileGlob => path.join(process.env.PWD, fileGlob)),
894 host,
895 // Prevent browsersync from automatically opening the site (can get annoying pretty quickly)
896 open: false,
897 online: false,
898 },
899 // ... the rest of your config
900})
901```
902
903### Replacing the html task with Shopify Liquid templating
904
905The following example shows how to get Shopify liquid templating support. We'll override the html task to run the html files through liquidr via gulp-liquidr.
906
907The same approach can be made to pull in gulp-pug, gulp-haml, gulp-slim and gulp-jinja!
908
909```javascript
910// make sure to run npm i --save gulp-liquidr first
911const { configure } = require('timpla')
912const liquidr = require('gulp-liquidr')
913const changed = require('gulp-changed')
914
915module.exports = configure({
916 // ... the rest of your file
917 html: {
918 src: 'html',
919 dest: './',
920 // An alternative task may be defined to replace the default
921 alternate({ gulp, env, timplaConfig, browserSync, projectSrcPath, projectDestPath }) {
922 const htmlConfig = timplaConfig.html
923 const paths = {
924 src: [projectSrcPath(htmlConfig.src, '**/*.html')],
925 dest: projectDestPath(htmlConfig.dest),
926 }
927
928 return () =>
929 gulp
930 .src(paths.src)
931 .pipe(changed(paths.dest))
932 .pipe(
933 liquidr({
934 root: [projectSrcPath(htmlConfig.src)],
935 data: {
936 accessMeInYourTemplate: 'ishouldwork',
937 },
938 // other config available from https://www.npmjs.com/package/gulp-liquidr
939 })
940 )
941 .pipe(gulp.dest(paths.dest))
942 .pipe(browserSync.stream())
943 },
944 },
945})
946```
947
948## Common Problems
949
950### I'm getting a different version of dependency X when I use Timpla!
951
952Run `npm i --save/--save-dev [your-package`] to ensure that Webpack picks up your preferred package version.
953
954### Timpla doesn't pick up changes to my eslintrc
955
956This is a known [issue](https://github.com/webpack-contrib/eslint-loader/issues/214) with eslint-loader. Ensure that cache is turned off whilst a patch is being worked on. Alternatively, you may specify your own eslint caching strategy via `cacheIdentifer`.
957
958### When I build, javascript files don't work!
959
960We have encountered this happening whenever you switch the `production.rev` setting. Please clear `./node_modules/cache` to force-clear all caches and try again!
961
962### process.cwd() isn't working as it's supposed to!
963
964Gulp / Timpla sets the process.env.INIT_CWD to the current projectRoot whereas process.cwd() points to the node_modules/timpla folder. Please ensure that you use INIT_CWD instead to resolve to projectPaths.
965
966### Tips for working with npm linked dependencies
967
968Ensure that you are using a babel.config.js. This will allow babel-loader to process the linked module files (TypeScript and ESNext).
969
9701. npm link yourmodule
9711. set up a module.resolve rule for webpack e.g. yourmodule\$: path.resolve(\_\_dirname, 'node_modules/yourmodule/src/index.ts')
972
973## CAQIAs (Commonly asked questions I ask)
974
975<details>
976 <summary>Is this workflow right for me?</summary>
977 <p>
978 If you are working on a server-side web framework like Django, Rails, Laravel, Shopify, Wordpress, Drupal or Craft - then yes! Timpla works along-side your engine's web templating system by dealing only with building your site assets. Timpla provides live-reloading and a sweet build process - so you can worry less about setup and more about writing code!
979 </p>
980 <p>
981 If you are working on a single page application or a client-side library/framework (e.g. Vue, React and Angular), it's best to go for a client-side boilerplate. The returns will diminish with no-backbone apps.
982 </p>
983</details>
984<details>
985 <summary>Gulp? Task runners are no longer required!</summary>
986 <p>Gulp still solves the issue of running tasks. Instead of polluting your npm run scripts or ad-hoc writing your build scripts, Gulp provides an easy-to-pick-up DSL for writing tasks.</p>
987 <p>Although gulp plugins are long past their debut, most of them are still relevant to our tasking needs.</p>
988 <p>Gulp is useful as it opens up streams to BrowserSync and Webpack.</p>
989</details>
990<details>
991 <summary>Gem/plugin/package X provides webpack middleware...</summary>
992 <p>
993 Yes, there are packages, gems or composer plugins that allow injecting webpack via middleware into your asset pipeline.
994 </p>
995 <p>
996 These tools are great, but often do we care less the older project dev environments get. By delegating the `core` to Timpla, we hope that more focus is put on extending, rather than maintaining!
997 </p>
998 <p>
999 Also, we often get into the framework-exclusivity. Think of Timpla as a consistent tool to bring over to projects.
1000 </p>
1001</details>
1002<details>
1003 <summary>How different is this from Blendid?</summary>
1004 <p>
1005 After a fork to upgrade dependencies, it was decided to branch out to provide an updated and extensive configuration framework.
1006 </p>
1007</details>
1008<details>
1009 <summary>Does it optimise images or fonts?</summary>
1010 <p>Timpla only copies images and fonts to their destination folders. It is recommended that you optimise the images separately, so as not to overload the build process. If you really want to, use the alternate() config.</p>
1011</details>
1012<details>
1013 <summary>Why not inject stylesheets?</summary>
1014 <p>Critical-css, lesser requests through service workers / caching and css-in-html have benefits too :)</p>
1015</details>
1016<details>
1017 <summary>Is this production ready?</summary>
1018 <p>We use Timpla for [Grabone](https://grabone.co.nz). We invite you to share ideas, and raise issues if you find any! The added benefit of reusing existing gulp tasks is that they are tested independently, dropping the need to duplicate tests!</p>
1019</details>
1020
1021## Developing the plugin
1022
1023Files are written in TypeScript, so program to your heart's content. Dev plugins are loaded only in your environment, so they don't get shipped as part of the main package!
1024
1025```sh
1026cd [timpla folder]
1027npm install
1028npm run lib:start # starts the tsc watcher, compiling gulpfile.ts on the go.
1029
1030# In a separate terminal
1031cd [your project]
1032npm link timpla
1033```
1034
1035When npm-linked, make sure you execute your commands using `timpla`.
1036
1037## Releasing the plugin
1038
10391. Make changes
10401. pr > Commit those changes to a separate PR
10411. pr > Make sure Travis turns green
10421. master > Merge PR
10431. master > Bump version in package.json
10441. master > npm run lib:changelog (needs to be installed first)
10451. master > npm run lib:docs (builds the ts-docs and readme files)
10461. master > Commit package.json and docs, README.md and CHANGELOG.md files
10471. master > Tag
10481. master > Push
10491. npm publish