bfieck bfieck - 1 year ago 93
TypeScript Question

Makefile compiles all tsc regardless of changes


I wrote a makefile to compile all of my typescript files to javascript, but also run them through a linter (tslint). I wrote the following makefile:


#source dirs
SASS_DIRS=./apps ./lib
TS_DIRS=./apps ./lib ./library

#source files
SASS_SRC ::= $(shell find $(SASS_DIRS) -name '*.scss')
TS_SRC ::= $(shell find $(TS_DIRS) -name '*.ts')
APPS_SASS_SRC ::= $(shell find ./apps -name 'app.scss')

#compilation options/binary flags
SASS_FLAGS = --output-style compressed -q
TSC_FLAGS = --sourceMap -t ES5 --noEmitOnError

.PHONY: clean

all: tsc sass

sass scss: $(patsubst %.scss, %.css, $(SASS_SRC))

%.css: %.scss
$(SASS) $(SASS_FLAGS) $< > $@

tsc: $(patsubst %.ts, %.js, $(TS_SRC))

%.js: %.ts
$(TSLINT) $<

incodesass: $(MAIN_SASS_SRC)
touch $(APPS_SASS_SRC); $(SASS) $(SASS_FLAGS) $< > $(MAIN_SASS_DEST); make sass

$(shell for i in $(shell find -name '*.rej'); do rm $i; done; for i in $(shell find -name '*.orig'); do rm $i; done;)

The problem is that any time I run
(or equivalently
make all
), the scss and tslint rules only run on changed files as appropriate, but even if I've changed no typescript files, the tsc recipe runs it's command (
). What did I do wrong?


From what I understand of typescript, even if only one file was changed, all the files need to be recompiled so it can understand references that they make between them, which is fair I suppose. With that in mind, this makefile needs to run
on each individual typescript source file, but also must run
on all of the source typescript files if even just one of them is changed. (currently it does that, the problem is just that
runs even if nothing's changed)


You might wonder why I left the sass/scss stuff in at all, it's because every
file in
s my main scss file (
) and I'd like it to run something that first checks if that's been changed, and if so
es all the app scuzzy files so they re-import it but regardless runs the sass/scss recipe AFTER that has completed. I can't think of a way to do this without a race condition (since I'm using
) that doesn't involve running make twice or without submakes. In general, I'm pretty new to this, so I'd happily accept criticisms on any part of this makefile in the comments, as well as a solution to that specific problem.

Answer Source

You've told make you're creating the file tsc, but the recipe doesn't create it.

Use the output files themselves as dependencies

SASS_CSS := $(SASS_SRC:=.scss=.css)
TS_JS    := $(TS_SRC:.ts=.js)

.PHONY: all js

all: $(SASS_CSS) $(TS_JS)

%.css: %.scss
    $(SASS) $(SASS_FLAGS) $< > $@

$(TS_JS): %.js: %.ts js.stub
    $(TSLINT) $<

js.stub: $(TS_SRC)
    $(TSC) $(TSC_FLAGS) $^
    @touch $@